Property Status control not working properly (CSLA 4.0.1 + Silverlight 4 + MVVM)

Property Status control not working properly (CSLA 4.0.1 + Silverlight 4 + MVVM)

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


Mr X posted on Monday, January 17, 2011

Hi all,

I implemented the example described in Rocky's MVVM video "Deeper dive into collections".  I was succesful in my implementation of the "New Employee" and then went forward to implement his navigation example going from the list of employees to the employee item.  The navigation works fine (I get my list and can edit the selected item) but for some reason, when I click on my button to create a single item, the propertystatus controls will not validate my object anymore and therefore will not change the status of my fields and buttons.  Any help would be greatly appreciated.

My object is called Business.EditUser.  It has dual factory and data access methods. In this case, only the root methods are called.  I am not getting any errors from CSLA and I can see my object is created (and in this case also populated with hardcoded values for debugging) and returned to the client.  Therefore I do not think the object is the reason.  Of course, I could be wrong but with that info coming back, I do not think so.

This may not matter but I must say I was not able to drag and drop my datasource through VS2010.  The CollectionViewSource included in the EditUser.XAML file have been put there manually (like all other controls on this usercontrol).

I included here only the code accessed during this process.  Also, I handle the transactions outside the objects in stored procedures.

Here is my EditUser.XAML code:

<UserControl x:Class="Demo.EditUser"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"

    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"

    mc:Ignorable="d"

    d:DesignHeight="300" d:DesignWidth="400"

    xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk"

    xmlns:my="clr-namespace:ViewModels"

    xmlns:this="clr-namespace:Demo"

    Loaded="UserControl_Loaded"

    xmlns:my1="clr-namespace:Csla.Xaml;assembly=Csla.Xaml"

    xmlns:my2="clr-namespace:Bxf.Converters;assembly=Bxf"

    xmlns:my3="clr-namespace:Bxf.Converters;assembly=Bxf">

 

    <UserControl.Resources>

        <my2:NotConverter x:Key="NotConverter" />

        <my3:VisibilityConverter x:Key="VisibilityConverter" />

       

<CollectionViewSource x:Key="EditUserViewModelViewSource" d:DesignSource="{d:DesignInstance my:EditUserViewModel, CreateList=True}" />

 

<CollectionViewSource x:Key="UserRoleListModelViewSource" Source="{Binding Path=Model.RoleList, Source={StaticResource EditUserViewModelViewSource}}" />

    </UserControl.Resources>

 

    <Grid x:Name="LayoutRoot">

        <Grid DataContext="{StaticResource EditUserViewModelViewSource}" Name="grid1">

            <Grid.ColumnDefinitions>

                <ColumnDefinition Width="Auto" />

                <ColumnDefinition Width="Auto" />

                <ColumnDefinition Width="Auto" />

                <ColumnDefinition Width="159*" />

            </Grid.ColumnDefinitions>

            <Grid.RowDefinitions>

                <RowDefinition Height="Auto" />

                <RowDefinition Height="Auto" />

                <RowDefinition Height="Auto" />

                <RowDefinition Height="Auto" />

                <RowDefinition Height="Auto" />

                <RowDefinition Height="Auto" />

                <RowDefinition Height="Auto" />

                <RowDefinition Height="87*" />

            </Grid.RowDefinitions>

  <!—1st row -->

         

<sdk:Label Content="Id:" Grid.Column="0" Grid.Row="0" HorizontalAlignment="Left" Margin="3" VerticalAlignment="Center" />

            

<TextBox Grid.Column="1" Grid.Row="0" Height="23" HorizontalAlignment="Left" Margin="3" Name="idTextBox" Text="{Binding Path=Model.Id, Mode=OneWay}" VerticalAlignment="Center" Width="120" IsReadOnly="True" />

 

<my1:PropertyStatus Grid.Column="2" Grid.Row="0" Margin="5" Name="psID" Width="20" Height="20" Property="{Binding Path=Model.Id}" />

<!—2nd row -->

<sdk:Label Content="Login Name:" Grid.Row="1" Grid.Column="0" HorizontalAlignment="Left" Margin="3" VerticalAlignment="Center" />

           

<TextBox Grid.Column="1" Grid.Row="1" Height="23" HorizontalAlignment="Left" Margin="3" Name="LoginNameTextBox" Text="{Binding Path=Model.LoginName, Mode=TwoWay, ValidatesOnExceptions=true, ValidatesOnNotifyDataErrors=False}" VerticalAlignment="Center" Width="120" IsReadOnly="{Binding ElementName=psLoginName, Path=CanWrite, Converter={StaticResource NotConverter}}" />

 

<my1:PropertyStatus Grid.Column="2" Grid.Row="1" Margin="5" Name="psLoginName" Width="20" Height="20" Property="{Binding Path=Model.LoginName}" />

<!—3rd row -->

 

<sdk:Label Content="User Name:" Grid.Column="0" Grid.Row="2" HorizontalAlignment="Left" Margin="3" VerticalAlignment="Center" />

           

<TextBox Grid.Column="1" Grid.Row="2" Height="23" HorizontalAlignment="Left" Margin="3" Name="UserNameTextBox" Text="{Binding Path=Model.UserName, Mode=TwoWay, ValidatesOnExceptions=true, ValidatesOnNotifyDataErrors=False}" VerticalAlignment="Center" Width="120" IsReadOnly="{Binding ElementName=psUserName, Path=CanWrite, Converter={StaticResource NotConverter}}" />

           

<my1:PropertyStatus Grid.Column="2" Grid.Row="2" Margin="5" Name="psUserName" Width="20" Height="20" Property="{Binding Path=Model.UserName}" />

 

<!—4th row -->

 

<sdk:Label Content="Profile ID:" Grid.Row="3" HorizontalAlignment="Left" Margin="3,3,0,3" VerticalAlignment="Center" />

           

<this:ComboBox x:Name="cboRoleList"

ItemsSource="{Binding Source={StaticResource UserRoleListModelViewSource}}"

                     SelectedValue="{Binding Path=Model.ProfileID, Mode=TwoWay}"

ValueMemberPath="Key"

DisplayMemberPath="Value" Grid.Column="1" Grid.Row="3" Height="20" Margin="0,4" />

 

<my1:PropertyStatus Grid.Column="2" Grid.Row="3" Margin="5" Name="psProfileId" Width="20" Height="20" Property="{Binding Path=Model.ProfileID}" />

 

 

<!—5th row -->

 

<sdk:Label Content="Last Updated:" Grid.Row="4" HorizontalAlignment="Left" Margin="3,3,0,3" VerticalAlignment="Center" />

           

<TextBox Grid.Column="1" Grid.Row="4" Height="23" HorizontalAlignment="Left" Margin="3" Name="LastUpdatedTextBox" Text="{Binding Path=Model.LastUpdated, Mode=TwoWay, ValidatesOnExceptions=true, ValidatesOnNotifyDataErrors=False}" VerticalAlignment="Center" Width="120" IsReadOnly="{Binding ElementName=psLastUpdated, Path=CanWrite, Converter={StaticResource NotConverter}}" />

           

<my1:PropertyStatus Grid.Column="2" Grid.Row="4" Margin="5" Name="psLastUpdated" Width="20" Height="20" Property="{Binding Path=Model.LastUpdated}" />

<!—6th row -->

 

<sdk:Label Content="Updated By:" Grid.Row="5" HorizontalAlignment="Left" Margin="3,3,0,3" VerticalAlignment="Center" />

           

<TextBox Grid.Column="1" Grid.Row="5" Height="23" HorizontalAlignment="Left" Margin="3" Name="UpdatedByTextBox" Text="{Binding Path=Model.UpdatedBy, Mode=TwoWay, ValidatesOnExceptions=true, ValidatesOnNotifyDataErrors=False}" VerticalAlignment="Center" Width="120" IsReadOnly="{Binding ElementName=psUpdatedBy, Path=CanWrite, Converter={StaticResource NotConverter}}" />

           

<my1:PropertyStatus Grid.Column="2" Grid.Row="5" Margin="5" Name="psUpdatedBy" Width="20" Height="20" Property="{Binding Path=Model.UpdatedBy}" />

 

<!—Button row -->

 

<StackPanel Grid.ColumnSpan="3" Grid.Row="6" Grid.RowSpan="1" Name="stackPanel1" Orientation="Horizontal" Margin="0">

 

<!—Save button -->

<Button Content="Save"  Height="23" Name="SaveButton" Width="75"  IsEnabled="{Binding Path=CanSave}" />

 

<my1:TriggerAction Height="20" HorizontalAlignment="Left"

Name="SaveTrigger" VerticalAlignment="Top" Width="20"

TargetControl="{Binding ElementName=SaveButton}"

MethodName="Save" DataContext="{Binding Path=CurrentItem}" />

           

             

<!—Cancel button -->

<Button Content="Cancel"  Height="23" Name="CancelButton" Width="75"  IsEnabled="{Binding Path=CanCancel}" Grid.Column="1" />

 

<my1:TriggerAction Height="20" HorizontalAlignment="Left" Name="CancelTrigger" VerticalAlignment="Top" Width="20" TargetControl="{Binding ElementName=CancelButton}" MethodName="Cancel" DataContext="{Binding Path=CurrentItem}" />

 

              </StackPanel>

 

        </Grid>

    </Grid>

</UserControl>

 

The corresponding ViewModel is as followed (IMPORTANT: Only the first constructor is ever called, EditUserViewModel):

using System;

using Bxf;

using Business;

using Csla.Xaml;

using Demo; //Included here to make use of App.Language (custom variable)

 

namespace ViewModels

{

    public class EditUserViewModel : ViewModel<Business.EditUser>

    {

        public EditUserViewModel()

        {    

Shell.Instance.ShowStatus(new Status { Text = "Creating Editable User", IsBusy = true });

 

              BeginRefresh("NewEditUser", App.Language);

        }

 

        public EditUserViewModel(Business.EditUser EditUser)

        {

Shell.Instance.ShowStatus(new Status { Text = string.Format("Retrieving Editable User {0}", EditUser.UserName), IsBusy = true });

           

BeginRefresh("GetEditUser", EditUser.LoginName, App.Language);

 

        }

 

        protected override void OnError(Exception error)

        {

            Shell.Instance.ShowError(error.Message, "Error");

            base.OnError(error);

        }

 

        protected override void OnRefreshed()

        {

            Shell.Instance.ShowStatus(new Status());

            base.OnRefreshed();

        }

 

        public override void Save(object sender, Csla.Xaml.ExecuteEventArgs e)

        {

Shell.Instance.ShowStatus(new Status { Text = "Saving", IsBusy = true });

 

            base.Save(sender, e);

        }

 

        protected override void OnSaved()

        {

            Shell.Instance.ShowStatus(new Status { Text = "Saved" });

            base.OnSaved();

        }

    }

}

 

 

After calling the EditUserViewModel constructor, the application calls the client side code of my BO:

using System;

using Csla;

using Csla.Serialization;

 

namespace Business

{

    public partial class EditUser

    {

        #region "Factory Methods"

public static void NewEditUser(int Language, EventHandler<DataPortalResult<EditUser>> callback)

            {

                var dp = new DataPortal<EditUser>(DataPortal.ProxyModes.Auto );

                dp.CreateCompleted += (o, e) =>

                {

                    if (e.Error == null)

                       

                      

                    callback(o, e);

                };

 

                dp.BeginCreate(Language);

            }

 

 

this in turn calls the Server side DataPortal_Create(param1) described bellow:

 

 

private void DataPortal_Create(int Language)

{

 

// TODO: load values

 

//Load NVL

LoadProperty(RoleListProperty, Business.NVLSecurityProfile.GetNVLSecurityProfile(Language));

 

base.DataPortal_Create();

}

 

 

 

 

As I mentionned earlier, I can "read" my resulting BO, It is on the UserControl that the propertystatus control do not seem to "know" about my object's status.

 

Totally confused... again.   I am going to start over, again but I do want to know what I am doing wrong. It was working before. Please help me figure it out.  Thanks.

 

 

EditUserViewModel is called from the MainMenuViewModel:  --> NewEditUser

 

MainMenuViewModel.cs -->

 

using System;

using Bxf;

using Business;

using Demo;   //Required here to use my own Silverlight custom variables: //Language, //username

 

namespace ViewModels

{

  public class MainMenuViewModel

  {

      public void NewEditUser()

    {

        Business.SLPrincipal.Login(App.LoggedUser, (o, arg) =>

        {

        });

 

        Shell.Instance.ShowView(

          typeof(Demo.EditUser).AssemblyQualifiedName,

          "EditUserViewModelViewSource", new ViewModels.EditUserViewModel(),

          "MainContent");

    }

   }

}

 

Mr X replied on Wednesday, February 16, 2011

Problem solved.

Had to modify the BusinessRules section and include the call to base.AddBusinessRules() as followed:

#region Business Rules

    protected override void AddBusinessRules()

    {

       

        // TODO: add validation rules

        base.AddBusinessRules();

        //BusinessRules.AddRule(new Rule(), MyProperty);

    }

#endregion

Copyright (c) Marimer LLC