WCF RIA Services without code using a TriggerAction

When you drop a WCF RIA service data source in the visual studio 2010 Beta 2, you will see that it generates for you a load button and assign it an event handler that call Load on the ria data source.

I don’t know for you but I find easier to use a TriggerAction than having to write the same code again and again.

In this post, I will discuss some TriggerAction that I have implemented and helps me write RIA application faster.

LoadAction

Loading data using a data source in RIA services is very simple. You only have to call Load. Why not ease that by making it available in Microsoft Expression Blend 3 using a TriggerAction.

Here is the implementation of the LoadAction that targets a DomainDataSource.

public class LoadAction : TargetedTriggerAction<DomainDataSource>
{
    protected override void Invoke(object parameter)
    {
        var target = Target;
        if (target != null && !target.IsLoadingData)
            target.Load();
    }
}

Wow! That was easy. 3 lines of code and we have our first action. Have a try in Blend and you will see that it really helps.

SubmitChangesAction

Submit data is also very simple. Here is how to do it using a TriggerAction:

public class SubmitChangesAction : TargetedTriggerAction<DomainDataSource>
{
    protected override void Invoke(object parameter)
    {
        var target = Target;
        if (target != null)
            target.SubmitChanges();
    }
}

NavigateAction

Ok, this one is a bit harder to implement but will helps you. To navigate in Silverlight, we need an instance of the NavigationService and call the Navigate method. Again, this can be simplified.

Create a TriggerAction to be attached to the Page since this is where we can have an instance of the NavigationService. We will add a property called PageUri which is the page to navigate to when the action is called:

public class NavigateAction : TriggerAction<Page>
{
   #region PageUri DependencyProperty
   public string PageUri
   {
      get { return (string)GetValue(PageUriProperty); }
      set { SetValue(PageUriProperty, value); }
   }

   public static readonly DependencyProperty PageUriProperty = DependencyProperty.Register
   (
      "PageUri",
      typeof(string),
      typeof(NavigateAction),
      new PropertyMetadata(null)
   );
}

protected override void Invoke(object parameter)
{
   var pageUri = PageUri;

   if (string.IsNullOrEmtpy(pageUri))
      return;

   var page = AssociatedObject;
   var uri = new Uri(pageUri, UriKind.RelativeOrAbsolute);
   var service = page.NavigationService;

   if (service != null)
      service.Navigate(uri);
}

NavigateAction with QueryString parameters

Good, we have a working NavigateAction. I think we can do much better. How about support for passing parameters in the query string. Here is the new implementation:

[ContentProperty("Parameters")]
public sealed class NavigateAction : TriggerAction<Page>
{
   public NavigateAction()
   {
      Parameters = new ObservableCollection<NavigateActionParameter>();
   }

   #region Methods
   private Uri CreateUri()
   {
      var s = PageUri;

      if (string.IsNullOrEmpty(s))
         return null;

      var c = s.Contains("?") ? '&' : '?';

      for (var i = 0; i < Parameters.Count; i++)
      {
         var parameter = Parameters[i];
         if (parameter == null)
            continue;

         var value = parameter.Value;
         if (value == null)
            continue;

         s += c + parameter.ParameterName + '=' + Uri.EscapeDataString(value);
         c = '&';
      }

      return new Uri(s, UriKind.RelativeOrAbsolute);
   }

   protected override void Invoke(object parameter)
   {
      var page = AssociatedObject;
      var uri = CreateUri();
      var service = page.NavigationService;

      if (uri != null && service != null)
         service.Navigate(uri);
   }
   #endregion

   #region Properties
   #region PageUri DependencyProperty
   public string PageUri
   {
      get { return (string)GetValue(PageUriProperty); }
      set { SetValue(PageUriProperty, value); }
   }

   public static readonly DependencyProperty PageUriProperty = DependencyProperty.Register
   (
      "PageUri",
      typeof(string),
      typeof(NavigateAction),
      new PropertyMetadata(null)
   );
   #endregion
   public ObservableCollection<NavigateActionParameter> Parameters { get; private set; }
   #endregion
}

public sealed class NavigateActionParameter : DependencyObject
{
   #region Properties
   public string ParameterName { get; set; }

   #region Value DependencyProperty
   public string Value
   {
      get { return (string)GetValue(ValueProperty); }
      set { SetValue(ValueProperty, value); }
   }

   public static readonly DependencyProperty ValueProperty = DependencyProperty.Register
   (
      "Value",
      typeof(string),
      typeof(NavigateActionParameter),
      new PropertyMetadata(null)
   );
   #endregion
   #endregion
}

You can now use the NavigateAction and add parameters in the Query String in Blend without using code. Here is a sample

<l:NavigateAction PageUri="/BacklogItemView?Action=Update">
   <l:NavigateActionParameter ParameterName="Id" Value="{Binding Path=SelectedItem.Id, ElementName=dataGrid1}"/>
</l:NavigateAction>

This will pass a parameter named Id in the Query String.

Happy programming!

0 comments: