Monday, April 6, 2009

Silverlight 3.0, Astoria, LINQ to SQL (3): DataForm CRUD

In last few posts:here and here, I wrote about how to build/prepare the solution, projects, and some ground work in LINQ to SQL and connecting it to ADO.NET Data Service as well as reading data through a Silverlight application using Silverlight 3.0 DataForm.

In this post, I will continue in implementing the Update/Edit, Create/New, and Delete to complete our CRUD.

To do EDIT, it is actually very simple. First you will need to add event handlers. We will need two handlers, but both of them will be reusable for ADD. To add event handlers, all we need to do is start typing our DataForm name and select the event that we want to implement via intellisense and hit tab key twice. It will complete the line for you and create a stub for the event hendler method.

By the way, I changed our binding, so instead of going against Customer, it is against Shipper (both from Northwind db and should exist in the LINQ mapping from the auto-gen code).

static Uri baseUri = new Uri("http://localhost:10403/NorthwindDataService.svc", UriKind.Absolute);
NorthwindDBDataContext northwindDSContext = new NorthwindDBDataContext(baseUri);

public MainPage()
{
InitializeComponent();
this.Loaded += new RoutedEventHandler(MainPage_Loaded);

// new code
dfShipper.ItemEditEnding += new EventHandler<DataFormItemEditEndingEventArgs>(dfShipper_ItemEditEnding);
dfShipper.ItemEditEnded += new EventHandler<DataFormItemEditEndedEventArgs>(dfShipper_ItemEditEnded);
}

void dfShipper_ItemEditEnding(object sender, DataFormItemEditEndingEventArgs e)
{
northwindDSContext.UpdateObject(dfShipper.CurrentItem);
}

void dfShipper_ItemEditEnded(object sender, DataFormItemEditEndedEventArgs e)
{
northwindDSContext.BeginSaveChanges((asyncResult) =>
{ northwindDSContext.EndSaveChanges(asyncResult); }, null);
}

The "BeginSaveChanges" and "EndSaveChanges" are there because our data connection is asynchronous.

For ADD, we need to change "dfShipper_ItemEditEnding" into this:
void dfShipper_ItemEditEnding(object sender, DataFormItemEditEndingEventArgs e)
{
if (dfShipper.IsAddingNew)
northwindDSContext.AddObject("Shippers", dfShipper.CurrentItem);
else
northwindDSContext.UpdateObject(dfShipper.CurrentItem);
}

For DELETE, we add this handler:
void dfShipper_DeletingItem(object sender, System.ComponentModel.CancelEventArgs e)
{
northwindDSContext.DeleteObject(dfShipper.CurrentItem);
northwindDSContext.BeginSaveChanges((asyncResult) =>
{ northwindDSContext.EndSaveChanges(asyncResult); }, null);
}

So our complete code should look like this:
public partial class MainPage : UserControl
{
static Uri baseUri = new Uri("http://localhost:10403/NorthwindDataService.svc", UriKind.Absolute);
NorthwindDBDataContext northwindDSContext = new NorthwindDBDataContext(baseUri);

public MainPage()
{
InitializeComponent();
this.Loaded += new RoutedEventHandler(MainPage_Loaded);
dfShipper.ItemEditEnding += new EventHandler<DataFormItemEditEndingEventArgs>(dfShipper_ItemEditEnding);
dfShipper.ItemEditEnded += new EventHandler<DataFormItemEditEndedEventArgs>(dfShipper_ItemEditEnded);
dfShipper.DeletingItem += new EventHandler<System.ComponentModel.CancelEventArgs>(dfShipper_DeletingItem);
}

void dfShipper_DeletingItem(object sender, System.ComponentModel.CancelEventArgs e)
{
northwindDSContext.DeleteObject(dfShipper.CurrentItem);
northwindDSContext.BeginSaveChanges((asyncResult) =>
{ northwindDSContext.EndSaveChanges(asyncResult); }, null);
}

void dfShipper_ItemEditEnding(object sender, DataFormItemEditEndingEventArgs e)
{
if (dfShipper.IsAddingNew)
northwindDSContext.AddObject("Shippers", dfShipper.CurrentItem);
else
northwindDSContext.UpdateObject(dfShipper.CurrentItem);
}

void dfShipper_ItemEditEnded(object sender, DataFormItemEditEndedEventArgs e)
{
northwindDSContext.BeginSaveChanges((asyncResult) =>
{ northwindDSContext.EndSaveChanges(asyncResult); }, null);
}

void MainPage_Loaded(object sender, RoutedEventArgs e)
{
var query = (DataServiceQuery<Shipper>)
from c in northwindDSContext.Shippers
orderby c.CompanyName
select c;

query.BeginExecute((asyncResult) =>
{
try
{
IEnumerable<Shipper> result = query.EndExecute(asyncResult);
Dispatcher.BeginInvoke(() =>
{
ObservableCollection<Shipper> data = new ObservableCollection<Shipper>();
foreach (Shipper p in result)
{
data.Add(p);
}
dfShipper.DataContext = data;
dfShipper.ItemsSource = data;
});
}
catch (Exception ex)
{
throw ex;
}
}, null);
}
}

1 comment:

Douglas said...

Hello,

I am having problem when trying to open my xaml where the DataForm is.

It shows the follow error: Failed to Invoke: callOpen.


query.BeginExecute((asyncResult) =>
{
try
{
IEnumerable(SurveyParticipant)
result = query.EndExecute(asyncResult);
Dispatcher.BeginInvoke(() =>
{
ObservableCollection(SurveyParticipant) data = new ObservableCollection(SurveyParticipant)();
foreach (SurveyParticipant p in result)
{
data.Add(p);
}
ManageSurveyForm.DataContext = data;
ManageSurveyForm.ItemsSource = data;
});
}
catch (Exception ex)
{
throw ex;
}
}, null);
}