3

I've created a table in Microsoft Sql CE that I'm using to hold some data. I've generated an ORM via SqlMetal and I've pulled the datasource into my WPF project.

I want to create a simple WPF form that can be used to edit a record in the table via the ORM-generated classes. I want this form to support typical OK/Cancel semantics. I've created the form in what I believe to be the typical fashion, using TwoWay databinding on the respective fields to bind against an instance of the object from the ORM. For example, given an object in the ORM that has a property "TaskName", I've included the following in my WPF form:

<Label Grid.Column="0" Grid.Row="0" >
    Name:
</Label>
<TextBox Name="txtName" Grid.Column="1" Grid.Row="0" 
         Text="{Binding TaskName, Mode=TwoWay}" AcceptsReturn="False"
         MaxLines="1" />

This, combined with a DataContext assignment in code:

var newRow = new OrmGeneratedClass();
// Populate default values on newRow, e.g.    
detailWindow.DataContext = newRow;
detailWindow.ShowDialog();

can work reasonably well for creation of a new row. All changes made via the form are immediately reflected in the underlying OrmGeneratedClass. The problem is that there's no immediate support for canceling changes if, e.g., the OrmGeneratedClass is filled with previously saved values.

What is a good design for this scenario, or am I designing it wrong before I get to this point? I'm a newbie with WPF and the Sql Server datasource/ORM integration aspects. (This is a personal project that I'm using to learn both technologies.)

I have a couple of thoughts and will place them in the answers

Serhat Ozgel
  • 23,496
  • 29
  • 102
  • 138
Greg D
  • 43,259
  • 14
  • 84
  • 117

2 Answers2

7

Paul Stovell has a brilliant article about creating an adapter for the IEditableObject interface that allows you to databind and allow apply/revert behaviour.

http://www.paulstovell.com/blog/runtime-ui-binding-behavior-ieditableobject-adapter

The adapter wraps around your ORM object and automatically caches changes so you can either apply the changes or revert back to the original.

Cameron MacFarland
  • 70,676
  • 20
  • 104
  • 133
  • Brilliant! This looks like it addresses exactly what I'm looking for. Thanks! – Greg D Dec 07 '08 at 04:43
  • Yeah I found the article a while ago, and have used it in several projects. Saved me heaps of time. – Cameron MacFarland Dec 07 '08 at 04:54
  • This works if you're working with a set of entities for which changes made to one doesn't have to cause a change in the other (immediately before EndEdit is called) . Let's say you have Orders and OrderItems in the same form. If you need to update the Customer on the order and each order item needs rate discounted based on some value of the customer (Discount code) then the order items won't update their total until Order.EditEdit (Typically in the Save button on the form) is called. So the User will not see the immediate feedback of the order_total changing when they change the customer. – Dasith Wijes Nov 25 '15 at 13:41
1

One possible solution would be to look for a cancel result from the dialog and, using the ORM object's primary key, retrieve the data from the database every time the user cancels to verify that the object contains the value it had in the database. This assumes that the value's most recently confirmed value has already been stored in the database. (Probably a fair assumption in a program as simple as this will be.)

It might look something like this (non-compiled) code:

var existingRow = GetExistingRow(someConditionOrWhatever);
detailWindow.DataContext = existingRow;
if(!detailWindow.ShowDialog())
{
    existingRow = GetExistingRow(someConditionOrWhatever);
}

I don't know if I like round-tripping to the database like that, though.

Greg D
  • 43,259
  • 14
  • 84
  • 117
  • http://groups.google.com.au/group/wpf-disciples/web/wpf-and-xaml-coding-guidelines includes some useful guidelines, including a better technique for the DataContext assignment that I'm performing in the question. – Greg D Jan 26 '09 at 14:24