We have lots of immutable value objects in our domain model, one example of this is a position, defined by a latitude, longitude & height.
/// <remarks>When I grow up I want to be an F# record.</remarks>
public class Position
{
public double Latitude
{
get;
private set;
}
// snip
public Position(double latitude, double longitude, double height)
{
Latitude = latitude;
// snip
}
}
The obvious way to allow editing of a position is to build a ViewModel which has getters and setters, as well as a ToPosition() method to extract the validated immutable position instance. While this solution would be ok, it would result in a lot of duplicated code, especially XAML.
The value objects in question consist of between three and five properties which are usually some variant of X, Y, Z & some auxiliary stuff. Given this, I had considered creating three ViewModels to handle the various possibilities, where each ViewModel would need to expose properties for the value of each property as well as a description to display for each label (eg. "Latitude").
Going further, it seems like I could simplify it to one general ViewModel that can deal with N properties and hook everything up using reflection. Something like a property grid, but for immutable objects. One issue with a property grid is that I want to be able to change the look so I can have labels and textboxes such as:
Latitude: [ 32 ] <- TextBox
Longitude: [ 115 ]
Height: [ 12 ]
Or put it in a DataGrid such as:
Latitude | Longitude | Height
32 115 12
So my question is:
Can you think of an elegant way to solve this problem? Are there any libraries that do this or articles about something similar?
I'm mainly looking for:
Custom Type Descriptors could be used to solve this problem. Before you bind to a Position, your type descriptor could kick in, and provide get and set methods to temporarily build the values. When the changes are committed, it could build the immutable object.
It might look something like this:
DataContext = new Mutable(position,
dictionary => new Position(dictionary["lattitude"], ...)
);
Your bindings can still look like this:
<TextBox Text="{Binding Path=Lattitude}" />
Because the Mutable object will 'pretend' to have properties like Lattitude thanks to its TypeDescriptor.
Alternatively you might use a converter in your bindings and come up with some kind of convention.
Your Mutable class would take the current immutable object, and a Func<IDictionary, object>
that allows you to create the new immutable object once editing completes. Your Mutable class would make use of the type descriptor, which would create PropertyDescriptors that create the new immutable object upon being set.
For an example of how to use type descriptors, see here:
http://www.paulstovell.com/editable-object-adapter
Edit: if you want to limit how often your immutable objects are created, you might also look at BindingGroups and IEditableObject, which your Mutable can also implement.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With