CanWriteProperty not updating PropertyStatus TargetControl

CanWriteProperty not updating PropertyStatus TargetControl

Old forum URL: forums.lhotka.net/forums/t/8989.aspx


Russ posted on Tuesday, May 25, 2010

I am migrating a CSLA 3.x WPF project to 4.0 and have a problem with Authorization.

I am working with a very simple edit form designed to allow users to view the data and Admin users to modify the data. The table has a code and description field. Once the Admin user has created the record the code field should become read only.

Currently, the Non Admin user is indeed prevented from modifying data and the Admin user is able to add new records. The problem is that the Admin user is able to modify the Code field of an existing record which causes an unhandled security error. Why isn't the UI aware of the CanWriteProperty logic?

Here are my business rules:

#region Business Rules

 

protected override void AddBusinessRules()

{

  base.AddBusinessRules();

  BusinessRules.AddRule(new Csla.Rules.CommonRules.Required(CodeProperty));

  BusinessRules.AddRule(new Csla.Rules.CommonRules.MaxLength(CodeProperty, 10));

  BusinessRules.AddRule(new Csla.Rules.CommonRules.Required(DescriptionProperty));

  BusinessRules.AddRule(new Csla.Rules.CommonRules.MaxLength(DescriptionProperty, 100));

 

  BusinessRules.AddRule(new IsInRole(AuthorizationActions.CreateObject, new List<string> { "Admin" }));

  BusinessRules.AddRule(new IsInRole(AuthorizationActions.EditObject, new List<string> { "Admin" }));

  BusinessRules.AddRule(new IsInRole(AuthorizationActions.DeleteObject, new List<string> { "Admin" }));

}

 

public override bool CanWriteProperty(Csla.Core.IPropertyInfo property)

{

  if (property.Name == "Code")

    return IsNew;

  else

    return base.CanWriteProperty(property);

}

 

#endregion

 

I have removed the Authorizer and added the PropertyStatus controls. Here are the textbox bindings

<TextBlock Grid.Column="0" Grid.Row="0" Name="CodeTextBlock" Text="Code:" Style="{StaticResource TextBlockStyle}" />

<TextBox Grid.Column="1" Grid.Row="0" Name="CodeTextBox"

    Text="{Binding Code, Converter={StaticResource IdentityConverter}, ValidatesOnDataErrors=True, UpdateSourceTrigger=PropertyChanged}"

    Style="{StaticResource TextBoxStyle}"/>

<csla:PropertyStatus Grid.Column="2" Grid.Row="0" Property="{Binding Path=Code}" TargetControl="CodeTextBox"/>

 

<TextBlock Grid.Column="0" Grid.Row="1" Name="DescriptionTextBlock" Text="Description:"

    Style="{StaticResource TextBlockStyle}" />

<TextBox Grid.Column="1" Grid.Row="1" Name="DescriptionTextBox"

    Text="{Binding Description, Converter={StaticResource IdentityConverter}, ValidatesOnDataErrors=True, UpdateSourceTrigger=PropertyChanged}"

    Style="{StaticResource TextBoxStyle}" />

<csla:PropertyStatus Grid.Column="2" Grid.Row="1" Property="{Binding Path=Description}" TargetControl="DescriptionTextBox"/>

 

I have also changed the ObjectStatus from a container to a resource.

If a place a breakpoint in the CanWriteProperty method it is being hit.

I am looking for the CSLA 4.0 best practice and would appreciate any insight anyone is willing to share.

Thanks in advance

Russ

RockfordLhotka replied on Tuesday, May 25, 2010

The best solution is for the UI control (your textbox or whatever) to bind its IsEnabled/IsReadOnly/Visible property(ies) to the properties of the PropertyStatus control.

In older versions of CSLA I was trying to have PropertyStatus "manage" the UI control directly. That was a mistake, as it limits flexibility of UI design. So the CSLA 4 approach is for the UI control to bind to the PropertyStatus control's properties to control the UI appearance.

In other words, TargetControl is not really a preferred approach, and I should probably just remove it entirely. I can say that I haven't tested it in CSLA 4... Yes, now that I think about it, I think it should be removed to avoid any possible confusion/misuse.

PropertyStatus exposes a whole set of interesting properties (including CanRead and CanWrite) to make it easy for you to alter your UI as desired based on the status of the property.

Russ replied on Tuesday, May 25, 2010

Thanks Rocky,

Should I be using an Element binding from the textbox to the PropertyStatus control? I tried the following but it did not work.

<TextBlock Grid.Column="0" Grid.Row="0" Name="CodeTextBlock" Text="Code:" Style="{StaticResource TextBlockStyle}" />

<TextBox Grid.Column="1" Grid.Row="0" Name="CodeTextBox"

    Text="{Binding Code, Converter={StaticResource IdentityConverter}, ValidatesOnDataErrors=True, UpdateSourceTrigger=PropertyChanged}"

    Style="{StaticResource TextBoxStyle}"

    IsReadOnly="{Binding ElementName=CodePropertyStatus, Path=CanWrite}"/>

<csla:PropertyStatus Grid.Column="2" Grid.Row="0" x:Name="CodePropertyStatus" Property="{Binding Path=Code}"/>

 

Russ

Russ replied on Tuesday, May 25, 2010

It appears to work with IsEnabled but not with IsReadOnly!  The following code works:

<TextBlock Grid.Column="0" Grid.Row="0" Name="CodeTextBlock" Text="Code:" Style="{StaticResource TextBlockStyle}" />

<TextBox Grid.Column="1" Grid.Row="0" Name="CodeTextBox"

    Text="{Binding Code, Converter={StaticResource IdentityConverter}, ValidatesOnDataErrors=True, UpdateSourceTrigger=PropertyChanged}"

    Style="{StaticResource TextBoxStyle}"

    IsEnabled="{Binding ElementName=CodePropertyStatus, Path=CanWrite}"/>

<csla:PropertyStatus Grid.Column="2" Grid.Row="0" x:Name="CodePropertyStatus" Property="{Binding Path=Code}"/>

 

Very strange.

RockfordLhotka replied on Tuesday, May 25, 2010

You might need a NotConverter to invert the bool value.

Russ replied on Friday, May 28, 2010

Thanks Rocky.  I don't know how I missed that one!

Feeling great shame.

Russ

RockfordLhotka replied on Friday, May 28, 2010

I do it all the time - so hopefully there's not too much shame involved Wink

Copyright (c) Marimer LLC