Silverlight 5 Implicit DataTemplates

One of the most powerful features introduced to Silverlight is Implicit Data Templates.  This has long been a feature of WPF and has been used to solve various challenges.  Implicit Data Templates allows a template to be automatically applied to bound items based on their types.  This feature becomes extremely useful in situations where you have a list of different objects and you want a different UI or layout based on the type of an individual item.

In this post, I will explore using Implicit DataTemplates to dynamically generate a list of report parameters.

Objective

Several weeks ago, I was asked by a colleague of my thoughts on his implementation of handling report parameters in the application we’re working on.  As we discussed ideas, we came up with a flexible solution making use of Implicit DataTemplates in XAML.  When creating a custom UI to handle report parameter input, there are a few common data elements that will be used in multiple reports of the application.  In our case most reports will require a date range, customer selection, and/or employee selection. 

Solution

Using Implicit DataTemplates, we will consistently and dynamically create the report parameter UI based on the parameters required by the report being requested by the user.  The following class will be used to allow this functionality.

ReportParameter Class

The ReportParameter represents the base functionality of a report parameter.  All report parameters will inherit from this class to serve as a common parameter and base error handling implementation.

public class ReportParameter : NotificationObject, INotifyDataErrorInfo
{
    private ErrorsContainer<string> _container;

    public ReportParameter()
    {
        _container = new ErrorsContainer<string>(OnErrorsChanged);
    }

    public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged;

    public System.Collections.IEnumerable GetErrors(string propertyName)
    {
        return _container.GetErrors(propertyName);
    }

    public bool HasErrors
    {
        get { return _container.HasErrors; }
    }

    protected virtual void SetErrors<TProp>(Expression<Func<TProp>> propExpression, IEnumerable<string> errors)
    {
        _container.SetErrors(propExpression, errors);
    }

    protected virtual void ClearErrors<TProp>(Expression<Func<TProp>> propExpression)
    {
        _container.ClearErrors(propExpression);
    }

    protected virtual void OnErrorsChanged(string propertyName)
    {
        EventHandler<DataErrorsChangedEventArgs> temp = ErrorsChanged;
        if (temp != null)
        {
            temp(this, new DataErrorsChangedEventArgs(propertyName));
        }
    }
}

DateRangeParameter Class

The DateRangeParameter class will be used to capture date range report parameter information.  This class will also handle all date parameter validation.

private DateTime? _StartDate;
public DateTime? StartDate
{
    get { return _StartDate; }
    set
    {
        _StartDate = value;
        ClearErrors<DateTime?>(() => StartDate);
        ValidateRequiredDate();
        ValidateDateRange();
        this.RaisePropertyChanged(() => StartDate);
    }
}

private DateTime? _EndDate;
public DateTime? EndDate
{
    get { return _EndDate; }
    set
    {
        _EndDate = value;
        ClearErrors<DateTime?>(() => EndDate);
        ValidateRequiredDate();
        ValidateDateRange();
        this.RaisePropertyChanged(() => EndDate);
    }
}

ShellViewModel Class

The ShellViewModel class will contain a collection of ReportParameter objects.  This property will be used by the view to render the appropriate view based on the bound ReportParameter object.

List<ReportParameter> _ReportParameters;
public List<ReportParameter> ReportParameters
{
    get { return _ReportParameters; }
    set
    {
        _ReportParameters = value;
        NotifyPropertyChanged("ReportParameters");
    }
}

ShellView Class

DateRangeParameter DataTemplate

The DateRangeParameter DataTemplate define the UI for a DateRangeParameter report parameter.  All report parameters will have to implement a datatemplate to define the UI of the report parameter.

<DataTemplate DataType="model:DateRangeParameter">                       
    <StackPanel Margin="10">
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition />
                <ColumnDefinition />
            </Grid.ColumnDefinitions>
            <Grid.RowDefinitions>
                <RowDefinition />
                <RowDefinition />
            </Grid.RowDefinitions>
            <TextBlock Grid.Row="0" Grid.Column="0" Text="Start Date:"/>
            <sdk:DatePicker Grid.Row="0" Grid.Column="1" Foreground="Black" SelectedDate="{Binding StartDate, Mode=TwoWay,  ValidatesOnExceptions=true, ValidatesOnNotifyDataErrors=True}" />
            <TextBlock Grid.Row="1" Grid.Column="0" Text="End Date:" />
            <sdk:DatePicker Grid.Row="1" Grid.Column="1" Foreground="Black" SelectedDate="{Binding EndDate, Mode=TwoWay, ValidatesOnExceptions=true, ValidatesOnNotifyDataErrors=True}" />
        </Grid>
    </StackPanel>
</DataTemplate>

Using Implicit DataTemplates, we will dynamically create the parameter UI dependent on the type of report parameters required for the report. The following class will be used to allow this functionality.

<StackPanel Width="300">
    <ItemsControl ItemsSource="{Binding ReportParameters}" />
    <Button Content="Run" Margin="10" Width="45" Command="{Binding RunReportCommand}" />
</StackPanel>

 

Click here to download the demo.

Advertisements

~ by travisdbrown on February 12, 2012.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

 
%d bloggers like this: