Silverlight 2.0 Immersivity: Datagrid Two-Way Data Binding

The Silverlight 2.0 period of Immersivity continues with today’s keywords being Silverlight 2.0 Datagrid; Silverlight 2.0 Two-Way Data Binding; 2-Way Data Binding; No-Way Data Binding. (Just joking with the last one.  HA! HA!)

For good or bad, I stuck with my master plan of not spending resources on Silverlight until 2.0 went RTM, so I have no experience with anything that came before.  I’ve learned quickly however that Silverlight 2.0 DataGrid data binding was changed in RC0 from the betas, and since a lot of information out there pertains to the betas I was stumped for a while getting my head around how to capture updated data and send it back to the Web Service.  That was today’s mission.

Prior to 2.0 RC0, the Silverlight DataGrid supported events like CommittingCellEdit and CommittingRowEdit. The demise of those events is noted here in Scott Morrison’s “RC0 Breaking Changes” post and discussed on several Silverlight.net threads like this one.  The best workaround seems to be using the TextBox LostFocus event in a TemplateColumn CellEditingTemplate. That’s a bit tricky because the LostFocus event fires when you are on a different row, requiring you to keep a copy of the edited item.  For instance, using ((MyDataObject)dataGrid.SelectedItem) in a LostFocus() event would retrieve the wrong row.

Silverlight 2.0 really has made Two-Way Data Binding ridiculously simple, that is, once you get the initial concepts down and know what to type, like anything else.

The ridiculously simple process starts when adding a Service Reference in a Silverlight 2.0 class project. Visual Studio 2008 (SP1) wires up all of the property settings in the data class object for NotifyPropertyChanged and configures the class as an ObservableCollection<T>, making two-way data binding a cinch.  This is performed for both ASMX Web and WCF Services.

Before I describe how I captured Silverlight 2.0 DataGrid data updates and passed that data back to an .ASMX Web Service I must tell you that NONE of this is necessary if you simply want to pass the entire collection back to the database.  That truly is ridiculously simple and I may end up going that route, but before doing so I had to know how to capture individual changes and pass only changed records to my Web Service.

Interjection: I know we’ll need to add record insertion and deletion into the mix. I will address that on another day and another post.

We’re going to need two Observable Collections, one for the working collection and the second for the changed items. We also need to remember the ID of the record updated to support our LostFocus event.

private ObservableCollection<LaborPostWS> laborPosts =
          new ObservableCollection<LaborPostWS>();
private ObservableCollection<LaborPostWS> changes =
          new ObservableCollection<LaborPostWS>();
public int LaborID { get; set; }

 

Capturing the LaborID is performed in a DataGrid BeginningEdit event.


private void dg_BeginningEdit(object sender, DataGridBeginningEditEventArgs e)
{
    LaborPostWS _laborPost = (LaborPostWS)dg.SelectedItem as LaborPostWS;
    LaborID = _laborPost.LaborID;
}

Then on LostFocus a bit of LINQ populates the “changes” collection. I don’t like having two LINQ statements, but it’s peripheral and works for now.

 

private void TextBox_LostFocus(object sender, RoutedEventArgs e)
{
    LaborPostWS _laborPost = (from c in laborPosts
                              where c.LaborID == LaborID
                              select c).Single();

    LaborPostWS existing = (from c in changes
                            where c.LaborID == LaborID
                            select c).Single();

    if (existing != null)
        changes.Remove(existing);
    changes.Add(_laborPost);
}

Finally, the changed records are sent to my .ASMX Web Service with a Button OnClick event. The OnClick and Web Method are shown below. 

 

private void Submit_Click(object sender, RoutedEventArgs e)
{
    service.UpdateLaborPostsCompleted += new
           EventHandler<System.ComponentModel.AsyncCompletedEventArgs>
           (service_UpdateLaborPostsCompleted);
    service.UpdateLaborPostsAsync(changes);
}

 

[WebMethod]
public void UpdateLaborPosts(List<Jobs.LaborPostWS> laborPosts)
{
    LaborPostDataContext db = new LaborPostDataContext();
    foreach (Jobs.LaborPostWS _post in laborPosts)
    {
        postID = _post.PostID;
        scheduleDate = _post.ScheduleDate;
        db.dbvt_UpdateLaborDetails(_post.LaborID,
            _post.PhaseID,
            _post.ShiftID,
            Convert.ToDouble(_post.Hours),
            _post.ForemanID,
            _post.ScheduleDate,
            _post.PostID);
    }
}

Yeap, the DataGrid is shaping up nicely.  I’m still struggling through the “most ignorant developer in the world” stage, but we’re now editing data!

Tomorrow we move on to embedded listboxes, establishing data relationships and setting default properties!

Article written by

A long time developer, I was an early adopter of Linux in the mid-90's for a few years until I entered corporate environments and worked with Microsoft technologies like ASP, then .NET. In 2008 I released Sueetie, an Online Community Platform built in .NET. In late 2012 I returned to my Linux roots and locked in on Java development. Much of my work is available on GitHub.