This
article gives very brief introduction to MVVM (not in depth), there are
loads of post about what it is and how it works in essence its
splitting the code and UI into separate test driven layers within your
application while trying to keep the business logic seperate from the
UI.
To understand it better please see the simple example which shows one way you could bind your data.
One
of this problems I hit very early on, was how do I use MVVM and allow
data to be passed through from parent to child UserControls (these have
to be generic - one for the address, one for a single phone number, etc)
that are coded to validate themselves without having to understand the
data context they are being used in. The big plan is to use them across
multiple projects without having to rewrite/create each from scratch
every time.
I started by dumping everything
into one massive view model, this was the wrong way – it was nearly
impossible to manage the code and with each control only needing the
field(s) to do its single job it proved tough.
I
looked at all the MVVM frameworks around, all are great, but none do
all of the tasks I seemed to need. I also wanted to understand how MVVM
worked in the background and using a framework would hide this from me.
No framework this time, I just coded my own simple modelBase to manage the standard bits and bobs.
What
I ended up doing with the databinding is an MVVM application that uses
dependency properties in the control code behind to manage data binding
to some UI elements while still using MVVM to do the logic and control
data storage.
I am building a Silverlight
control to manage/create new customers so they can be vetted/contracts
created etc for a telecoms company.
I have
broken the form up into a number UserControls to try and make
development easier and hopefully make each UserControl useable in other
parts of the application.
The control forms a
part of a larger control/view that manages an entire customer account,
so being able to access the same customer data across (possibly)
multiple Views is important.
The correct way to do this
I
am using web services to build the objects/classes/observable
collections, these are all stored in a set of static classes that are
all run before the application loads the UI, I had issues with loading
everything asynchronously as if the customer loaded before the list of
categories for example it would crash (there is probably a work around
for that).
The main page holds all user
UserControls , each UserControl is populated with static data before I
load the customer view and ViewModel which will set the selectedvalue on
any databound controls or text property for text etc.
Injection into user control code behind;
I
am adding a binding my Customer ViewModel object to the LayoutRoot
grid’s DataContextProperty, however you could add this to any property
on any control. Or you could add a single field from the DataContext as
well to any UI property.
My child UserControl code behind =
namespace Project.Controls.Customer
{
public partial class ContractDetails : UserControl
{
public ContractDetails()
{
InitializeComponent();
LayoutRoot.SetBinding(Grid.DataContextProperty,
new System.Windows.Data.Binding
{
Source = this,
Path = new PropertyPath("PropName"),
Mode = System.Windows.Data.BindingMode.TwoWay
});
}
public static DependencyProperty DataProperty =
DependencyProperty.Register("PropName",
typeof(GenericDataService.queueCustomer), typeof(ContractDetails),
null);
public GenericDataService.queueCustomer PropName
{
get { return (GenericDataService.queueCustomer)GetValue(DataProperty); }
set
{
SetValue(DataProperty, value);
}
}
}
}
I
have set the Mode to TwoWay, you could set this to OneWay, OneTime or
change this at runtime depending who who is logged to force the binding
to be readonly.
I then pass the data into the child UserControl above in the xaml of the parent control;
<my:ContractDetails PropName="{Binding TheData }" x:Name="contractDetails1" />
One
last step is to set the text property of the textbox that is on the
child UserControl , in this case it is the phone number, I use a text
filter command to only allow numbers and there will be some UK phone
number validation as well.
<TextBox Text="{Binding ElementName=LayoutRoot, Path=DataContext.PhoneNumber, Mode=TwoWay}" />
<TextBox Text="{Binding ElementName=LayoutRoot, Path=DataContext.Fax, Mode=TwoWay}" />
<ComboBox
Height="23" Name="CBContractDuration" Width="120" Grid.Column="2"
ItemsSource="{Binding Path=ContractDuration, Source={StaticResource
StaticData}, Mode=TwoWay}" DisplayMemberPath="Name"
SelectedValuePath="id" SelectedValue="{Binding ElementName=LayoutRoot,
Path=DataContext.ContractDuration, Mode=TwoWay}" />
From
the ComboBox sample above you can see the control is filled with data
form my Static data class, however the selected item is set by the
Customer ViewModel data passed in through the dependency property up in
the first example,
(I have tried to show the linking between the three steps by colouring the keywords, sorry if this is confusing for anyone)
It
is important to remember that even in Xaml the binding keys are case
sensitive so in the above example PropName="{Binding TheData }" is
okay, but PropName="{Binding Thedata }" will not work.
The
above works well, but there are instances where you end up doing the
validation on the control within the ChildUserControl in the code behind
rather than the ViewModel, this is not perfect MVVM, but it works, so
is good enough for me – at least until I work out how to do it all in
the view model.
No comments :
Post a Comment