Improved binding support in EntitySet and EntityCollection

For our WCF RIA Services V1.0 SP1 Beta release we were finally able to improve binding support for EntitySets and EntityCollections. In our V1 release, EntitySet and EntityCollection did not support adding and removing entities through the IEditableCollectionView interface when used as the ItemsSource in a DataGrid or DataForm. While the details of the problem will only be familiar to some, if you’ve had difficulty adding or removing in a master/details scenario, this is the likely cause.

A Master/Details Example

In this section, I’ll put together a short sample showing how this feature enables a simple master/details scenario. I want to focus mainly on the client side of things so we’ll keep the DomainService simple.

   [EnableClientAccess]
  public class SampleDomainService : DomainService
  {
    public IEnumerable<SampleEntity> GetEntities() {…}

    public void CreateEntity(SampleEntity entity) {…}

    public void UpdateEntity(SampleEntity entity) {…}

    public void DeleteEntity(SampleEntity entity) {…}
  }

  public class SampleEntity
  {
    [Key]
    public int Id { get; set; }

    public string Name { get; set; }
  }

When the RIA Services codegen runs, it will generate the SampleDomainContext and SampleEntity types on the client. I’ve omitted most of the generated code, but here are the two members we’ll use later in the sample.

   public class SampleDomainContext : DomainContext
  {
    public EntitySet<SampleEntity> SampleEntities
    {
      get {…}
    }
    
    public EntityQuery<SampleEntity> GetEntitiesQuery() {…}
  }

My approach on the client side of the application is simple. I use a DataGrid to show a list of the SampleEntities and the DataForm to add, remove, and edit. I’ve defined my SampleDomainContext in the xaml to make the binding simple and explicit.

   <UserControl …>

    <UserControl.Resources>
      <web:SampleDomainContext x:Key="myDomainContext"/>
    </UserControl.Resources>

    <StackPanel x:Name="LayoutRoot" Background="White">
      <StackPanel Orientation="Horizontal" Margin="2">


        <sdk:DataGrid Name="myDataGrid"
          ItemsSource="{Binding SampleEntities,
                        Source={StaticResource myDomainContext}}" 
          IsReadOnly="True" />

        <toolkit:DataForm Name="myDataForm" Width="200"
          ItemsSource="{Binding SampleEntities,
                        Source={StaticResource myDomainContext}}"
          CurrentItem="{Binding SelectedItem,
                        ElementName=myDataGrid, Mode=TwoWay}"
          CommandButtonsVisibility="Add,Delete,Commit,Cancel" />

      </StackPanel>
        

      <Button Name="Submit" Content="Submit Changes" Click="Submit_Click"
        HorizontalAlignment="Left" Margin="2"/>

    </StackPanel>
  </UserControl>

The code behind is just as simple. I pull the SampleDomainContext from the resources (that I declared in xaml) and use it to load and save the SampleEntities. The only complexity here is tracking the DataForm’s Editing state to make sure the edit is committed and the validation errors are addressed before submitting changes.

   public partial class MainPage : UserControl
  {
    private readonly SampleDomainContext _context;
    private bool _isDataFormEditing;

    public MainPage()
    {
      InitializeComponent();

      this._context =
        (SampleDomainContext)this.Resources["myDomainContext"];
      this._context.Load(this._context.GetEntitiesQuery());

      // This is an unfortunate workaround to track the
      // DataForm Editing state
      this.myDataForm.AddingNewItem +=
        (sender, e) => this._isDataFormEditing = true;
      this.myDataForm.BeginningEdit +=
        (sender, e) => this._isDataFormEditing = true;
      this.myDataForm.EditEnded += 
        (sender, e) => this._isDataFormEditing = false;
    }

    private void Submit_Click(object sender, RoutedEventArgs e)
    {
      if (!this._isDataFormEditing || this.myDataForm.CommitEdit())
      {
        this._context.SubmitChanges();
      }
    }
  }

In the end, I have a nice little Master/Details application.

image

To Sum it Up

This sample is pretty simple. The point I really want to emphasize here is that you can now bind EntitySets and EntityCollections to Silverlight controls like the DataGrid and DataForm and have them work like you would expect them to. On top of that, these types will show improved compatibility in features like drag-and-drop and as well as in third party controls.