A better use of INotifyPropertyChanged in Silverlight using MVVM style

 

Working with Silverlight requires notification change, in other word we need to explicitly notify client that a changed occurs. For that you need to implement INotifyPropertyChanged (see the link for more details).

When you implement this interface, you are constraint to provide the property name as a string. This is error prone because when you rename your property (depends how you rename your properties) you can miss all the occurrences of the name.

The trick is to use INotifyPropertyChanged in combination with expression trees and lambda expression.

public static string GetMethodName(Expression<Func<object, object>> property)

{

   var expr = (((System.Linq.Expressions.LambdaExpression)(property)).Body);

   string method = string.Empty;

 

   if (expr is UnaryExpression)

   {

       method = 

           (((System.Linq.Expressions.MemberExpression)

           (((System.Linq.Expressions.UnaryExpression)

           (((System.Linq.Expressions.LambdaExpression)(property)).Body)).Operand)).Member).Name;

   }

   else if (expr is MemberExpression)

   {

       method = (((System.Linq.Expressions.MemberExpression)

                (((System.Linq.Expressions.LambdaExpression)(property)).Body)).Member).Name;

   }

 

   return method;

}

 

This method is very useful to extract the property name and than passed it to the INotifyPropertyChanged event argument.

public class BaseModel : INotifyPropertyChanged

{

    public event PropertyChangedEventHandler PropertyChanged;

    private void NotifyProperty(string propertyName)

    {

        if (PropertyChanged != null)

        {

            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));

        }

    }

 

    protected void NotifyProperty(Expression<Func<object, object>> property)

    {

        string method = Common.ExpressionHelper.GetMethodName(property);

 

        if (!string.IsNullOrEmpty(method))

        {

            this.NotifyProperty(method);

        }

    }

}

You can call it like this:

this.NotifyProperty(i => this.MyProperty);

This ensure you that whenever rename a property

Advertisements

Using DomainDataSource for getting data in Silverlight

I’m working on the project for a friend which needs to filter some data in order to help him to keep tracking the processing he needs to do over some audio or video files. In other words it’s a business application in Silverlight.

Because it’s a relatively a small project I didn’t use Prism, just simple code behind and xaml.

The main business functionality is the filtering of data in the main screen (see the picture below), so I need a simple and clean way to change filters (methods that needs to be called in order to get data from) also to pass parameters. The answer to my solution was DomainDataSource.

image 

DomainDataSource object is part of the WCF RIA Services framework and is a control that simplify the interaction between the user interface and data from domain context.

How I set the initial filtering ?
First I added a DomainDataSource object into my page and I set the domain context property with a instance of the context generated by WCF RIA. In order to retrieve data I specified the query name. In my case a method called GetStudiesViewQuery, which doesn’t have any parameters. If you want pagination you can provide also PageSize and a LoadSize.

<!-- namespace declarations --> xmlns:riaControls="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.DomainServices" xmlns:domain="clr-namespace:predic.Web.Host.Services" <!-- usage --> <riaControls:DomainDataSource x:Name="StudiesView" QueryName="GetStudiesViewQuery" AutoLoad="True" LoadSize="120" PageSize="40"> <riaControls:DomainDataSource.DomainContext> <domain:PredicContext /> </riaControls:DomainDataSource.DomainContext> </riaControls:DomainDataSource>

Binding data a grid

To be able to see data in a grid, I added a DataGrid and bind the ItemsSource property.

<sdk:DataGrid ItemsSource="{Binding Path=Data, ElementName=StudiesView}" /> <!-- Paginator --> <sdk:DataPager PageSize="40" Source="{Binding Path=ItemsSource, ElementName=GridPredici}" />

 

That’s work great, I got data with pagination. But as you saw in the screenshot, on the left there are few filter criteria’s that I need to apply. A solution would have been to bind query parameters from XAML but I choose to do that from code.

I want to change the filter method and add query parameter without losing the pagination. In code I did that:

if (this.SelectedPreacherID > 0) { StudiesView.QueryName = "GetStudiesViewWithFilter"; StudiesView.QueryParameters.Clear(); StudiesView.QueryParameters.Add(new Parameter() { ParameterName = "preacherID", Value = this.SelectedPreacherID }); StudiesView.QueryParameters.Add(new Parameter() { ParameterName = "title", Value = this.SelectedStudiu }); StudiesView.QueryParameters.Add(new Parameter() { ParameterName = "subtitle", Value = this.SelectedPredica }); } else { StudiesView.QueryParameters.Clear(); StudiesView.QueryName = "GetStudiesViewQuery"; } StudiesView.Clear(); StudiesView.Load();

In order to propagate the changes on the grid I just called the Clear method then Load.