Dynamic Data Forms for Silverlight, revisited

by Andrej Tozon 7. April 2009 17:12

A couple of weeks ago, I wrote a post about handling dynamic forms in Silverlight. With this continuation post, I’m going to make a few changes to the original project:

1. Implement a new, custom, field type and provide a template for it (I’ll write about it later), and
2. Make a few changes to the FormFieldTemplateSelector to make it more generic. So instead of writing templates like this:

A new TemplateSelectorDataTemplate…

<local:FormFieldTemplateSelector.StringTemplate>
    <DataTemplate>
        <TextBox Text="{Binding Value, Mode=TwoWay}" Width="100"/>
    </DataTemplate>
</local:FormFieldTemplateSelector.StringTemplate>
<local:FormFieldTemplateSelector.DateTimeTemplate>
    <DataTemplate>
        <basics:DatePicker SelectedDate="{Binding Value, Mode=TwoWay}" Width="100" />
    </DataTemplate>
</local:FormFieldTemplateSelector.DateTimeTemplate>

You could simply write:

<local:TemplateSelectorDataTemplate DataType="System.String">
    <TextBox Text="{Binding Value, Mode=TwoWay}" Width="100"/>
</local:TemplateSelectorDataTemplate>
<local:TemplateSelectorDataTemplate DataType="System.DateTime">
    <basics:DatePicker SelectedDate="{Binding Value, Mode=TwoWay}" Width="100" />
</local:TemplateSelectorDataTemplate>

You can see the DataType property on the TemplateSelectorDataTemplate used instead of using concrete templates like FormFieldTemplateSelecot.StringTemplate. This way, the FormFieldTemplateSelector’s DataType property can be matched with TemplateSelectorDataTemplate’s DataType property [long names confusion, I know] and you don’t have to factor a new template for each new field type you come with, making it feel a bit more like the DataTemplate implementation in WPF. Strings are used here instead of types. One reason for this is that Silverlight doesn’t support x:Type markup, and the second is the fact you can use any string to identify your field type: for example, you can use “#Signature#” string as a custom field type to insert a signature control into your form.

A written signature form field…

To demonstrate a support for custom field types, I created a special control, which will allow the user to sign herself on a special panel and the signature will be submitted to the server together with the other field values.

The control, which will allow us to write on it with the mouse, is of course InkPresenter. I’ve encapsulated it in another control, called SignaturePanel, which adds required mouse event handler which enables the user to write on the InkPresenter with a mouse. Here’s this control, contained within a new TemplateSelectorDataTemplate:

<local:TemplateSelectorDataTemplate DataType="#Signature#"> <local:SignaturePanel Width="100" Height="50"
Strokes="{Binding Value, Mode=TwoWay, Converter={StaticResource strokesConverter}}" /> </local:TemplateSelectorDataTemplate>

The template looks nothing special, except that strokesConverter, specified with the binding. What that does is serialize the Strokes collection from the InkPresenter when being written to the underlying ViewModel, where we need it when sending all submitted data over to the server side. This means that signature actually gets sent over the wire in a form of strokes collection, which you can store in a database. Alternatively, you could convert that strokes into the bitmap on the server and store the signature as an image [And I’ve yet to check how Silverlight 3 WritableBitmap can help doing this on the client]. Anyway, I’ve found StrokeCollection (de)serialization code in Julia Lerman’s Create Web Apps You Can Draw On with Silverlight 2 MSDN article and is included in the code sample attached to this post.

Here’s how the current form looks like:

image

Source code is now available. Please note that this is a Silverlight 3 project. It doesn’t contain any SL3 code, it’s just the project files were converted to SL3 when opened in Visual Studio.

All comments welcome. Enjoy.

Tags:

MVVM | Silverlight | User Experience | Development | Layout

Comments

5/28/2009 12:22:49 PM #

John "Z-Bo" Zabroski

Hi Andrej,

I have done something similar to you.  It was a huge PITA!  In my scenario, I allow for infinite nesting of templates.  My data model is FormSection = FormSection | FormDataGrid | FormDataField.

One question - why the Guid Id?  I don't get it Frown

John "Z-Bo" Zabroski United Kingdom | Reply

5/28/2009 12:42:38 PM #

John "Z-Bo" Zabroski

By the way, you may be interested in my recent blog post about this as it relates to WPF.  For my use case, I actually need to discriminate based on more than just a Type property.

Similar to you, we have a data model that cannot be elegantly mapped into the .NET Data Model of compile-time objects... and I also want to retrieve both the forms configuration model and data model at run-time.

z-bo.tumblr.com/.../wpf-design-flaws-part-1

My analagous solution in Silverlight is still not ideal.

John "Z-Bo" Zabroski United Kingdom | Reply

5/28/2009 12:46:37 PM #

John "Z-Bo" Zabroski

Also, consider renaming TemplateSelectorDataTemplate to DataTemplateSelector since it is (a) less department of the redundancy department (b) similar to WPF's class of the same name

sorry for three posts in a row!

John "Z-Bo" Zabroski United Kingdom | Reply

6/14/2009 12:43:52 PM #

Jack Addington

Great posting - this was exactly what I was looking for /w my current project.  I managed to get everything implemented in a datagrid but I'm having an issue with hooking the changed data into the grid.  I've tried with both the MS grid and with Telerik's grid but basically what is happening is that the data template is implemented but the control is essentially floating on top of the grid cell and doesn't actually interact.

So what I see is:

EnterCell
Enter DataTemplate control (say datepicker)
Edit date
Updates to BusinessObject
Leave datepicker control
focus to grid cell
editmode on grid
null value from grid cell value is then passed to BO and my datapicker value is lost.

Essentially it looks like the dynamic nature of swapping the data template loses the underlying binding with the gridcell value so it is lost.  I don't really understand how to put it back after the fact.

Not sure if this made sense or not but any ideas you have (or if you have an implementation in a grid) that would be great.

Thanks

jack

Jack Addington Canada | Reply

11/16/2009 8:45:15 AM #

Toshendra Dalvi

Where is the source code download link? I can't see it on the page.
Many Thanks
Toshendra

Toshendra Dalvi United Kingdom | Reply

Add comment




  Country flag

biuquote
  • Comment
  • Preview
Loading





Andrej Tozon
Andrej Tozon's on Twitter View Andrej Tozon's profile on LinkedIn Subscribe to me on FriendFeed Andrej Tozon's Facebook profile

MVP - Client Application Developer

Microsoft Certified Solution Developer

MSN Alerts

Get help from Andrej Tozon!

 

Currently reading


Microsoft Silverlight 4 Data and Services Cookbook

Stay tuned for the review... In the mean time, you can read an excerpt from the book.

RecentComments

Comment RSS