The question of what Windows Workflow Foundation version 4 means for developers currently developing using WF recently came up. As I mentioned before WF 4 is a complete rewrite and doesn’t use any of the existing WF 3 classes. The design of WF 4 is even quite different from the design of WF 3.
So are WF 3 developers completely left in the dark and have to start from scratch? And what about their existing applications, will they still run on .NET 4 or are they stuck in .NET 3.5 until the end of times?
Fist of all let me address why I believe Microsoft could make such a radical change. Keep i mind this is just my personal opinion and I might be completely wrong
.
WF 3 was never widely adopted so I believe the team felt they could do this and not create too much of a problem. Personally I don't think the low adoption of WF 3 had anything to do with the technology. Sure it has its problems but most people never got to the point that they ran into real technical issues. Instead most people looked, didn't understand and quit. So IMHO the main problem was far more a question if evangelism that technology.
So what is the big issue with a migration from WF 3 to WF 4?
One big issue with WF 4 is that Microsoft decided not to release a state machine implementation. In WF 3 there was a choice between state machine and sequential workflows. In WF 4 there is a choice between sequential and flow chart. And in WF 3 a state machine turned out to be far more flexible and useful and quite a few cases are not really covered by the WF 4 model. There are a few workarounds to do something like a state machine in WF 4 but they are not pretty. That said, a number of state machine workflows could very well be done using a flow chart.
As far as backward compatibility the story is a bit more complicated. WF 4 ships with an interop activity you can use to host custom WF 3 activities in a WF 4 workflow. How good or bad this is? I really don't know yet but given how different the two designs are I fear it is very limited.
But WF 3 developers need not worry about their existing projects!
There is however a second side to the compatibility story. .NET 4 will ship both with the WF 3 and the WF 4 runtimes. The WF 3 runtime will not be prominent but it will still be there so all existing WF 3 applications will continue to run as is. And because it is part of the current .NET framework I suspect this is a legal requirement (but then I am no lawyer so could be wrong here). So there is no reason for existing workflow developers to panic just yet
.
So existing workflow developers should start learning WF 4 for future projects but can continue to keep using their existing WF 3 solutions for the foreseeable future.
Enjoy!
www.TheProblemSolver.nl
Wiki.WindowsWorkflowFoundation.eu
Dear Maurice de Beijer,
Congratulations! We are pleased to present you with the 2009 Microsoft® MVP Award! This award is given to exceptional technical community leaders who actively share their high quality, real world expertise with others. We appreciate your outstanding contributions in Connected System Developer technical communities during the past year.
O yes, I am happy again 
www.TheProblemSolver.nl
Wiki.WindowsWorkflowFoundation.eu
A recent article I wrote for the MSDN website just went live.
Read is here.
Passing parameters into a workflow is similar in WF4 as it was in WF3.
In both case a Dictionary<string, object> is passed in when creating the workflow instance object. Alternatively when using the WF4 WorkflowInvoker you can pass it into the Invoke() method.
This is quite simple but I have never been a fan of the very loose coupling here. basically on the outside you have to create a dictionary with as key something inside of the workflow. No compile time checking. No improvement where, unless you consider the somewhat easier unit testing with the WorkflowInvoker.
The actual behavior between WF3 and WF4 is quite different however.
In Wf3 if you pass in a key that doesn’t match up you get a System.Reflection.TargetInvocationException with a System.InvalidOperationException inner exception with the text: “This operation can not be performed at runtime.”. Great help in debugging 
In WF4 on the other hand you get no error at all. The value is just ignored so it is even harder to detect typos. Well I guess not every change can be an improvement. And just in case you where thinking “But a unit test will take care of that right?” keep in mind that workflows tend to be complex and long running things not very well suited to unit testing.
Starting a workflow with a parameter:
Shared Sub Main()
Dim inArgs As New Dictionary(Of String, Object)
inArgs("Name") = "Maurice"
Dim myInstance As WorkflowInstance = New WorkflowInstance(New Sequence1(), inArgs)
myInstance.OnCompleted = AddressOf OnWorkflowCompleted
myInstance.OnAborted = AddressOf OnWorkflowAborted
myInstance.OnUnhandledException = AddressOf OnWorkflowUnhandledException
myInstance.Run()
syncEvent.WaitOne()
End Sub
So where is this Name value actually stored?
Well in WF3 that would have been stored in a property, possibly a dependency property, or a field. The types must match, exactly.
In WF4 the notion of properties and fields is gone. No more dependency properties to tie everything together. So instead we have Variables and Arguments. Basically a variable is just like a variable in a function, only here it holds some value for an activity. Big difference is that a Variable is in scope, i.e. visible, to all nested activities as well. So basically it is a way of sharing state between different activities.
To allows us to pass data into a workflow, or get something out, we need to use an Argument.
In this case I have defined two arguments, the Name to pass into the workflow and the Greeting that will be the result of the workflow.
Getting the result out is done in the OnCompleted delegate. This delegate is passed a WorkflowCompletedEventArgs which in turn contains another dictionary with all out argument.
Shared Sub OnWorkflowCompleted(ByVal e As WorkflowCompletedEventArgs)
Dim greeting As String = e.Outputs("Greeting")
Console.WriteLine(greeting)
syncEvent.Set()
End Sub
Again not very different from WF3 where we used the WorkflowCompleted event and the OutputParameters dictionary from the WorkflowRuntime.
Conclusion
While there are quite a few differences in the details the basic approach remains the same. And as the old approach with dictionaries was rather error prone I consider this a missed chance 
Enjoy!
www.TheProblemSolver.nl
Wiki.WindowsWorkflowFoundation.eu
With WF3 there was a central workflow runtime environment called the WorkflowRuntime and used to manage the lifetime of workflow instances. In WF4 this central class no longer exists and we manage individual workflows.
To compare the two, this is what a minimal console application looks like in WF3. It basically runs a workflow and prints a message when done:
static void Main(string[] args)
{
using (WorkflowRuntime workflowRuntime = new WorkflowRuntime())
{
workflowRuntime.WorkflowCompleted += delegate(object sender, WorkflowCompletedEventArgs e)
{
Console.WriteLine("The workflow has completed.");
};
WorkflowInstance instance = workflowRuntime.CreateWorkflow(typeof(WorkflowConsoleApplication1.Workflow1));
instance.Start();
Console.WriteLine("Waiting for the workflow to complete.");
Console.ReadLine();
}
}
The same functionality in WF4 looks very different:
static void Main(string[] args)
{
WorkflowInstance myInstance = new WorkflowInstance(new Sequence1());
myInstance.OnCompleted += delegate(WorkflowCompletedEventArgs e)
{
Console.WriteLine("The workflow has completed.");
};
myInstance.Run();
Console.WriteLine("Waiting for the workflow to complete.");
Console.ReadLine();
}
The most important thing to note is that there is no longer a WorkflowRuntime object, instead we create a new WorkflowInstance object passing in a workflow instance (compared to a workflow type before).
There are some benefits as well as drawbacks to not having a WorkflowRuntime.
The main benefit is that it makes creating and running workflows much easier. No longer do we need to keep track of a singleton and use that to do everything. Another benefit is we can register event handler per workflow instance, makes it easier to do different things for different types of workflows. In fact the OnCompleted isn’t an event but a delegate so you can add only a single handler.
The drawback is that general configuration. Like recording workflow errors, tracking execution or workflow persistence must be done for each instance while before we could just do it on the workflow runtime.
Some things haven’t changed. In both WF3 and WF4 running the workflow is done asynchronously so we need to wait, in both cases done using a Console.ReadLine().
Synchronous execution
With WF3 it was hard to have a workflow execute synchronously. Basically we had to add a different scheduler to the workflow runtime and explicitly tell the scheduler to execute the workflow. Of course this would affect every workflow created through the same WorkflowRuntime.
With WF4 there is a much easier model using the WorkflowInvoker class. All we need to do is call WorkflowInvoker.Invoke() passing in the workflow object and the workflow will execute synchronously on the same thread. Not only very useful for running the odd workflow but also for unit testing as any WorkflowElement, the base class for all activities, can be executed this way.
static void Main(string[] args)
{
WorkflowInvoker.Invoke(new Sequence1());
Console.WriteLine("The workflow has completed.");
Console.ReadLine();
}
Nice right!
Enjoy.
www.TheProblemSolver.nl
Wiki.WindowsWorkflowFoundation.eu
As you may have heard Windows Workflow Foundation 4 is not an upgrade from Windows Workflow Foundation 3 (or 3.5). The version numbers might suggest that the previous version was quite mature but in fact it refers to the version of the .NET framework. In fact Windows Workflow Foundation 3 was the first version and 3.5 added only very few features and some bug fixes. And as WF 4 is a complete rewrite we should approach it as a new product and forget just about everything we already know about WF 3.
That might be a bit surprising, after all we still have activities and a workflow runtime right?
Well wrong actually!
There no longer is a class named WorkflowRuntime. Creating workflows is done by creating a WorkflowInstance object. This object is raises events for that workflow and only for that specific workflow.
But surely there is still an Activity base class?
Yes there is. But this is a completely new class that has nothing to do with the class Activity that was used with WF 3. In fact the new Activity class is in a new assembly and namespace, the full name is System.Activities.Activity in the assembly System.Activities.dll. The “old” activity class was System.Workflow.ComponentModel.Activity in the System.Workflow.ComponentModel.dll assembly. The old class still exists in .NET 4 so old workflows will still run but the new classes have no relation with the old classes.
So basically forget all you knew about the behavior of WF 3 
So lets take a brief look at creating a new workflow 4 style workflow.
When we start Visual Studio 2010 and select File/New/Project we get the new project tab. Select the Workflow node and you will see the four new project types
More about the different types in another blog post. For now just select the “Sequential Workflow Console Application”.
What we end up with is a simple project with just 2 files, the program.cs and the Sequence1.xaml. The latter contains the workflow. Note there is no choice between code or xaml workflows, the designer only works with xaml based workflows. Also note that the extension is no longer XOML but has changed to XAML.
The Sequence1.xaml workflow is still empty and looks like this:
When we open the Toolbox we see the new collection of basic activities. These are also completely new. For now just drag a WriteLine activity onto the Sequence in the designer. The goal of the WriteLine activity is just what the name suggest: write a line of text to some form of output stream. When we open the property sheet with the WriteLine activity selected we see there are just three properties: the DisplayName, the Text and the TextWriter.
The DisplayName is actually the name used on the design surface and used during the design of the workflow.
The Text property contains the text we want to print. In the property sheet we see a textbox with the text “<Enter an expression>”. This really is an expression editor where you can type in code. So if you want to enter a simple fixed text you must use quotation marks around it. This must always be a valid Visual Basic statement. yes that isn’t a typo Visual Basic, not C#, even if you are developing a C# project.
So in this case just add “Hello Workflow 4” including the quotation marks.
The TextWriter property is the text stream to write the text to. This is also an expression, just like the Text, and is optional. When not specified the text will be written to Console.Out which will do fine for now.
These expression windows in VB are completely new and a big change from WF3. Where we previously had to bind to property binding or something similar to add custom code we can now type it directly into the designer.
With this in place we are ready to run the workflow. Press Ctrl+F5 and with a bit of luck you should see the output appear in the console window. You might need a bit of luck because it appears the current bits are still a bit unstable and on my laptop running Windows 7 the designer tends to lock up quite a bit 
In the next post more about how the workflow is created and started at runtime.
Using the declarative DomainDataSource that is part of the upcoming Silverlight 3 RIA services makes it quite easy to work with data. All you need to do is add a DomainDataSource control to the the XAML, point it to the generated DomainContext class (in this case NorthwindContext) and tell it which method to use to load the data from the web service(in this case LoadCustomers). Next add a DataGrid to display the data and you are good to go.
<UserControl xmlns:dataControls="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data.DataForm" x:Class="LOBUsingRIAServices.CustomerListPage"
xmlns:data="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data"
xmlns:riaControls="clr-namespace:System.Windows.Controls;assembly=System.Windows.Ria.Controls"
xmlns:web="clr-namespace:LOBUsingRIAServices.Web"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid x:Name="LayoutRoot" Background="White">
<riaControls:DomainDataSource x:Name="CustomerDataSource"
LoadMethodName="LoadCustomers">
<riaControls:DomainDataSource.DomainContext>
<web:NorthwindContext />
</riaControls:DomainDataSource.DomainContext>
</riaControls:DomainDataSource>
<data:DataGrid ItemsSource="{Binding Data, ElementName=CustomerDataSource}" />
</Grid>
</UserControl>
Pretty simple and that is the way I like it 
Adding paging.
Sometimes the lost of data to load can get somewhat large and you might not want to load all data. In that case all you need to do is add a PageSize and the DomainDataSource will only load enough data to display on a single page. You can do this by just setting the PageSize on the DomainDataSource but as we also need a control to allow the user to page trough the data it is easier to also add the DataPager control. Now you have the option of setting the PageSize on the DomainDataSource or the DataPager. I found that setting it on either would work just was well except for the initial load where the DataPager shows page 0 when the PageSize is set on the DomainDataSource while it is set to 1, the correct value, when set on the DataPager. I assume this is just a small bug in the current preview.
Another thing you can specify is the LoadSize. This determines how many rows are loaded with each request and if not set equals the PageSize. Setting this to double the PageSize will improve the responsiveness of the the client application so might be a good idea if the data isn’t too large.
<UserControl xmlns:dataControls="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data.DataForm" x:Class="LOBUsingRIAServices.CustomerListPage"
xmlns:data="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data"
xmlns:riaControls="clr-namespace:System.Windows.Controls;assembly=System.Windows.Ria.Controls"
xmlns:web="clr-namespace:LOBUsingRIAServices.Web"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid x:Name="LayoutRoot" Background="White">
<riaControls:DomainDataSource x:Name="CustomerDataSource"
LoadMethodName="LoadCustomers"
LoadSize="40">
<riaControls:DomainDataSource.DomainContext>
<web:NorthwindContext />
</riaControls:DomainDataSource.DomainContext>
</riaControls:DomainDataSource>
<data:DataGrid ItemsSource="{Binding Data, ElementName=CustomerDataSource}" />
<dataControls:DataPager Source="{Binding Data, ElementName=CustomerDataSource}"
PageSize="20" />
</Grid>
</UserControl>
The DataPager control is quite easy to use as well. Just drop it below the DataGrid and point it to the DomainDataSource to use and it just works. One problem I ran into was adding the DataPager above the DataGrid though. When I did that the DataPager didn’t show up on the UI so the user could not page through the data even though it still limited the data to the first page.
Using progressive loading
Another nice option is delayed loading. When using progressive loading all you need to do is specify the LoadSize on the DomainDataSource. The DomainDataSource will now load the specified number of rows, wait a bit and load the next set of rows. It will keep on doing this until all data is loaded. The nice thing here is that all the data is loaded but the UI still stays responsive for the user. De the default interval between load requests is 0.75 seconds but this can be fine tuned using the LoadDelay time span on the DomainDataSource.
<UserControl xmlns:dataControls="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data.DataForm" x:Class="LOBUsingRIAServices.CustomerListPage"
xmlns:data="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data"
xmlns:riaControls="clr-namespace:System.Windows.Controls;assembly=System.Windows.Ria.Controls"
xmlns:web="clr-namespace:LOBUsingRIAServices.Web"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid x:Name="LayoutRoot" Background="White">
<riaControls:DomainDataSource x:Name="CustomerDataSource"
LoadMethodName="LoadCustomers"
LoadSize="10"
LoadDelay="0:0:0.25">
<riaControls:DomainDataSource.DomainContext>
<web:NorthwindContext />
</riaControls:DomainDataSource.DomainContext>
</riaControls:DomainDataSource>
<data:DataGrid ItemsSource="{Binding Data, ElementName=CustomerDataSource}" />
</Grid>
</UserControl>
And all of this was done without writing any code add everything was completely declarative. Of course it is just a matter of setting properties so doing so from code is easy enough.
Enjoy!
Normal
0
21
false
false
false
MicrosoftInternetExplorer4
<!--
/* Style Definitions */
p.MsoNormal, li.MsoNormal, div.MsoNormal
{mso-style-parent:"";
margin:0cm;
margin-bottom:.0001pt;
mso-pagination:widow-orphan;
font-size:12.0pt;
font-family:"Times New Roman";
mso-fareast-font-family:"Times New Roman";}
a:link, span.MsoHyperlink
{color:blue;
text-decoration:underline;
text-underline:single;}
a:visited, span.MsoHyperlinkFollowed
{color:purple;
text-decoration:underline;
text-underline:single;}
@page Section1
{size:612.0pt 792.0pt;
margin:70.85pt 70.85pt 70.85pt 70.85pt;
mso-header-margin:35.4pt;
mso-footer-margin:35.4pt;
mso-paper-source:0;}
div.Section1
{page:Section1;}
-->
/* Style Definitions */
table.MsoNormalTable
{mso-style-name:"Table Normal";
mso-tstyle-rowband-size:0;
mso-tstyle-colband-size:0;
mso-style-noshow:yes;
mso-style-parent:"";
mso-padding-alt:0cm 5.4pt 0cm 5.4pt;
mso-para-margin:0cm;
mso-para-margin-bottom:.0001pt;
mso-pagination:widow-orphan;
font-size:10.0pt;
font-family:"Times New Roman";
mso-ansi-language:#0400;
mso-fareast-language:#0400;
mso-bidi-language:#0400;}
Normally you should never have to set the <machineKey> in the in the web.config. This is only needed when am ASP.NET site runs on a web farm and in that case the machines in question should be configured using the machineKey instead of individual web applications. However we have run into the following exception a few times: “System.Web.UI.ViewStateException: Invalid viewstate” after leaving the browser idle for some time.
Turns out that the <machineKey> that where supposed to be on the web farm where missing. Now this is a shared hoster so not much we can do about the machine configuration but adding this key to the web.config before deploying is simple enough.
And generating the values to add is simple using this nifty, not my words, little generator.
www.TheProblemSolver.nl
Wiki.WindowsWorkflowFoundation.eu
The View – Model – ViewModel design pattern, also known as MVVM, is getting more popular these days. I have found it extremely easy to use when developing very different applications and have used the design pattern recently in both ASP.NET, WPF and Silverlight applications. However easy as it might be is seems to confuse people as I have seen some terrible examples where people make a complete mess of things.
Josh Smith did an excellent screen cast for Pixel8 on using MVVM with WPF, you can find it here.
Even thought the UI technology used doesn't change the basic MVVM pattern there are some subtle differences, like not easily being able to use ICommand in Silverlight, so I decided to create a small Silverlight sample.
The basic structure goes like this:
- The user interacts with a View, implemented as a Silverlight user control.
- The View is data bound to a ViewModel. This is the most important step to remember. The ViewModel is just another class.
- The ViewModel is a wrapper for a Model. Think of the Model as the data and the business rules.
The Model
The Model I am using is very simple and has two read-write properties, FirstName and LastName, and a single read-only property, FullName. The FullName property represents some business rule on how a name should be formatted. I know it is a bit of a lame business rule but it is just a sample
. The Model also implements INotifyPropertyChanged so the UI can be updated whenever a value is updated. The complete model looks like this:
1: using System.ComponentModel;
2:
3: namespace SilverlightMVVMDemo.Model
4: {
5: public class Customer : INotifyPropertyChanged
6: {
7: private string _firstName;
8: private string _lastName;
9:
10: public string FirstName
11: {
12: get { return _firstName; }
13: set
14: {
15: _firstName = value;
16: OnPropertyChanged("FirstName");
17: OnPropertyChanged("FullName");
18: }
19: }
20: public string LastName
21: {
22: get { return _lastName; }
23: set
24: {
25: _lastName = value;
26: OnPropertyChanged("LastName");
27: OnPropertyChanged("FullName");
28: }
29: }
30:
31:
32: public string FullName
33: {
34: get { return FirstName + " " + LastName; }
35: }
36:
37: public event PropertyChangedEventHandler PropertyChanged;
38:
39: protected void OnPropertyChanged(string propertyName)
40: {
41: if (PropertyChanged != null)
42: {
43: var args = new PropertyChangedEventArgs(propertyName);
44: PropertyChanged(this, args);
45: }
46: }
47: }
48: }
The View
The View is just a Silverlight user control that makes things visible for the user. All controls use data binding to get to their values. There is one interesting twist here. Just like I had a business rule about how to format a FullName I have a rule about the font weight to use to display the FullName. This is just UI so not a business rule and as a result it is not stored in the Model. We do not want to code this in the UI as that makes things hard to test. So that leaves one place, the ViewModel
. And the View uses data binding to set the FontWeight property.
The complete View looks like this:
1: <UserControl
2: xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
3: xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
4: xmlns:SilverlightMVVMDemo_ViewModel="clr-namespace:SilverlightMVVMDemo.ViewModel" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" x:Class="SilverlightMVVMDemo.View.CustomerView"
5: Width="400" Height="300" mc:Ignorable="d">
6: <Grid x:Name="LayoutRoot"
7: Background="White">
8: <Grid.RowDefinitions>
9: <RowDefinition Height="0.133*"/>
10: <RowDefinition Height="0.133*"/>
11: <RowDefinition Height="0.133*"/>
12: <RowDefinition Height="0.18*"/>
13: <RowDefinition Height="0.42*"/>
14: </Grid.RowDefinitions>
15: <Grid.ColumnDefinitions>
16: <ColumnDefinition Width="0.3*"/>
17: <ColumnDefinition Width="0.7*"/>
18: </Grid.ColumnDefinitions>
19: <TextBlock Text="Firstname:"
20: Margin="8"/>
21: <TextBox Text="{Binding Path=FirstName, Mode=TwoWay}"
22: Grid.Column="1"
23: Margin="8,8,8,8"/>
24: <TextBlock Text="Lastname:"
25: Grid.Row="1"
26: Margin="8"/>
27: <TextBox Text="{Binding Path=LastName, Mode=TwoWay}"
28: Grid.Row="1"
29: Grid.Column="1"
30: Margin="8,8,8,8"/>
31: <TextBlock Text="Fullname:"
32: Grid.Row="2"
33: Margin="8"/>
34: <TextBox Text="{Binding Path=FullName}"
35: Grid.Row="2"
36: Grid.Column="1"
37: Margin="8,8,8,8"
38: FontWeight="{Binding Path=FullNameFontWeight}"
39: IsReadOnly="True"/>
40: <Button Content="Save"
41: Click="Button_Click"
42: Grid.Row="3"
43: Grid.Column="1" />
44: </Grid>
45: </UserControl>
The code behind is very simple and looks like this:
1: using System.Windows.Controls;
2: using SilverlightMVVMDemo.ViewModel;
3:
4: namespace SilverlightMVVMDemo.View
5: {
6: public partial class CustomerView : UserControl
7: {
8: public CustomerView()
9: {
10: InitializeComponent();
11: DataContext = new CustomerViewModel();
12: }
13:
14: private void Button_Click(object sender, System.Windows.RoutedEventArgs e)
15: {
16: var viewModel = (CustomerViewModel)DataContext;
17: viewModel.Save();
18: }
19: }
20: }
In an ideal world there would be no code at all, or only that setting the DataContext but as Silverlight makes it a little harder to use commands there is a single line, okay two counting the cast, to pass the save command on to the ViewModel.
The ViewModel
The ViewModel class is the one that glues the View and the Model together, hence its name
. basically the ViewModel wraps each Model object, so if you want to use a collection of customer models you create a collection of CustomerViewModel objects and databind against them. The ViewModel catches all PropertyChanged events from the Model and passes them on to the user interface. Whenever the FullName property changes the FullNameFontWeight might also change so in that case an extra PropertyChanged event is raised. Note that calculation of the FontWeight to use is part of the ViewModel as the UI depends on this but it is not a business rule per se.
Another example of a property like this would be the CSS class to use in an ASP.NET application. basically if a UI property changes, create a property get to do so and databind it.
The complete ViewModel class looks like this:
1: using System.ComponentModel;
2: using System.Windows;
3: using SilverlightMVVMDemo.Model;
4:
5: namespace SilverlightMVVMDemo.ViewModel
6: {
7: public class CustomerViewModel : INotifyPropertyChanged
8: {
9: private Customer _model;
10:
11: public CustomerViewModel()
12: {
13: Model = new Customer() { FirstName = "Maurice", LastName = "de Beijer" };
14: }
15:
16: public CustomerViewModel(Customer model)
17: {
18: Model = model;
19: }
20:
21:
22: public Customer Model
23: {
24: get { return _model; }
25: private set
26: {
27: if (_model != null)
28: _model.PropertyChanged -= ModelPropertyChanged;
29:
30: _model = value;
31:
32: if (_model != null)
33: _model.PropertyChanged += ModelPropertyChanged;
34: }
35: }
36:
37: void ModelPropertyChanged(object sender, PropertyChangedEventArgs e)
38: {
39: OnPropertyChanged(e.PropertyName);
40:
41: if (e.PropertyName == "FullName")
42: OnPropertyChanged("FullNameFontWeight");
43: }
44:
45:
46: public string FirstName
47: {
48: get { return Model.FirstName; }
49: set { Model.FirstName = value; }
50: }
51: public string LastName
52: {
53: get { return Model.LastName; }
54: set { Model.LastName = value; }
55: }
56:
57: public string FullName
58: {
59: get { return Model.FullName; }
60: }
61:
62: public FontWeight FullNameFontWeight
63: {
64: get
65: {
66: if (FullName.Length > 20)
67: return FontWeights.ExtraBold;
68: else if (FullName.Length > 15)
69: return FontWeights.Bold;
70: else if (FullName.Length > 10)
71: return FontWeights.Normal;
72: else
73: return FontWeights.Light;
74: }
75: }
76:
77: public event PropertyChangedEventHandler PropertyChanged;
78:
79: protected void OnPropertyChanged(string propertyName)
80: {
81: if (PropertyChanged != null)
82: {
83: var args = new PropertyChangedEventArgs(propertyName);
84: PropertyChanged(this, args);
85: }
86: }
87:
88: internal void Save()
89: {
90: // Implement the logic to save the customer.
91: }
92: }
93: }
In this case I duplicated all properties from the Model in the ViewModel. This is not a must, some people prefer to expose and bind to the Model directly. It saves a few lines of code but I prefer not to do so. Of course there is no need to duplicate properties the UI is never going to bind to directly.
Model-View-ViewModel guidelines
Not very difficult at all as long as you keep to a few guidelines:
- Never set any UI properties from your CS code with the exception of the DataContext.
- If you need an event handler in your code behind, like the button click, make it a single line and pass the request onto the ViewModel.
- All UI control properties that need to change at runtime do so by data binding to a ViewModel property.
- Organize your ViewModel types per View and not per Model. It is perfectly fine to create a ViewModel that wraps two different Models. A View has only a single DataContext so you cannot bind it to multiple ViewModel objects.
www.TheProblemSolver.nl
Wiki.WindowsWorkflowFoundation.eu
And now on Twitter at http://twitter.com/mauricedb.
I was working on an article about the .NET RIA Services and decided to fire up Fiddler to take a close look at the data actually passed around. I was sort of expecting to see a WCF REST based approach with XML messages. Turns out I was wrong, though I expect this option will be added in the future.
It turns out the .NET RIA Services use JSON as their serialization format. This is actually kind of nice as the DataContractJsonSerializer is part of the System.ServiceModel.Web assembly and therefore usable by all .NET clients.
The good part is that a .NET RIA Service is also usable from a JavaScript browser based client. So the same .NET RIA Services library gives us lots of client options. Now this was always the plan but it is nice to see that the default already enable it.
And the best thing?
Well that is that I was already using the .NET RIA Services and never even needed to know how the messages where actually send across the wire, something I shouldn't have to worry about when developing a RIA style application. Which is exactly the goal of the .NET RIA Services.
Cool stuff and highly recommended if you want to create browser based LOB apps 
www.TheProblemSolver.nl
Wiki.WindowsWorkflowFoundation.eu
And now on Twitter at http://twitter.com/mauricedb.
As was to be expected the Surface machine at the last SDE was a big success and with lots of people wanting to have a go at it.
Nice to see the interest. And I am grateful Martin Tirion from the Dutch Microsoft office let us borrow the machine for a day.
At the end of June we will have the next big event 
Cu there.
BTW you can find more pictures from the event here.
www.TheProblemSolver.nl
Wiki.WindowsWorkflowFoundation.eu
And now on Twitter at http://twitter.com/mauricedb.
Then you should check Mike Swanson’s blog post here. He has two batch files, the first downloads all MIX session recordings with in the format you like, the second renames them so it is easier to make sense of all the media file names.
If you just want a list of all sessions with download links this page might be the thing for you.
So much better than downloading them by hand. Not as good as going to the MIX itself but if you, like me, couldn’t go it is still a nice way to see all the content.
Enjoy!
Nog een paar dagen en de volgende Software Development Event is weer een feit. Er zijn weer veel goede sessies deze keer. Maar er is meer, deze keer hebben we ook een Microsoft Surface machine staan. Dus als je nog nooit de gelegenheid gehad hebt om eens met een Microsoft Surface machine te spelen en te kijken wat je er nu eigenlijk mee kan is dit je kans.
Het hele programma is hier te vinden.
Tot volgende week maandag.
The P&P team have just release a VB version of the Prism quick starts.
You can download the goods here.
Enjoy!
In a previous blog post I mentioned that T4 templates didn’t quite work with Silverlight development. The reason being that Visual Studio decides to load the Silverlight version of System.dll which doesn’t contain all the required classes. Fortunately I was not the first person to run into this limitation, Jason Jarrett did as well and he described the solution in a blog post here.
The solution turns out to be surprisingly simple, just not very obvious. All you need to do is include the following line at the top of the T4 template.
1: <#@ assembly name="C:\Windows\Microsoft.NET\Framework\v2.0.50727\System.dll" #>
This way the T4 template engine loads the regular System.dll instead of the CoreCLR version and all is well.
So now the complete template looks like:
1: <#@ Template language="C#" #>
2: <#@ assembly name="C:\Windows\Microsoft.NET\Framework\v2.0.50727\System.dll" #>
3: <#@ import namespace="System.Collections.Generic" #>
4: <#
5: Dictionary<string, string> props = new Dictionary<string, string>();
6: props.Add("FirstName", "string");
7: props.Add("LastName", "string");
8: props.Add("Age", "int");
9: #>
10: namespace T4Test
11: {
12: public class Demo
13: {
14: <#
15:
16: foreach (KeyValuePair<string, string> prop in props)
17: {
18: #>
19: /// <summary>
20: /// Get or set the <#= prop.Key #> property.
21: /// </summary>
22: public <#= prop.Value #> <#= prop.Key #> { get; set; }
23:
24: <#
25: }
26: #>
27: }
28: }
and the generated output looks like:
1: namespace T4Test
2: {
3: public class Demo
4: {
5: /// <summary>
6: /// Get or set the FirstName property.
7: /// </summary>
8: public string FirstName { get; set; }
9:
10: /// <summary>
11: /// Get or set the LastName property.
12: /// </summary>
13: public string LastName { get; set; }
14:
15: /// <summary>
16: /// Get or set the Age property.
17: /// </summary>
18: public int Age { get; set; }
19:
20: }
21: }
Pretty nice, something I will be using a lot more often when developing all those repetitive DTO classes.
A T4 template editor
By default Visual Studio allows you to create T4 templates by renaming a text files extension from TXT to TT but that is about it. No IntelliSense, no keyword highlighting or any of the other things we are used to.
Fortunately Clarius has developed a T4 editor that plug into Visual Studio and makes live a bit easier when developing T4 templates. There are several editions and they even have a free community edition, which I am using now. The free edition might not have all the features of the professional edition that ships for just $ 99.99 but its a big improvement over the default Visual Studio experience and for a price that is hard to beat. Below is a screen shot of the Clarius T4 editor with the same template.
Very useful and a great addition to my Visual Studio toolkit!
Enjoy!
Just one week to go to the next Software Development Event. The schedule with all the sessions is looking good. But this time there is even more!
We will have a Microsoft Surface machine somewhere in the common area for people to try our. And if you have never played, oops tested, with a Surface machine before this is a truly exiting machine!
Just goes to show, the SDN will go to extraordinary efforts to please all attendees
You can see the full schedule here. And don’t forget, we are not in Ede this time but in a great new location in Driebergen.
Hope to see everyone there next week Monday.
www.TheProblemSolver.nl
Wiki.WindowsWorkflowFoundation.eu
And now on Twitter at http://twitter.com/mauricedb.
Everyone who has Visual Studio 2008 also has T4 templates that can be used to generate code, or anything else textual for that matter. Using T4 should be pretty easy but unfortunately Visual Studio kind of hides the fact, there is no “Add T4 template” option and when you manually add one there is no help whatsoever in the box to create a working template. There are some tools out there that will help some but getting started with a simple template is easy. The following is a simple template to create a simple class
1: <#@ Template language="C#" #>
2: <#@ import namespace="System.Collections.Generic" #>
3: <#
4: Dictionary<string, string> props = new Dictionary<string, string>();
5: props.Add("FirstName", "string");
6: props.Add("LastName", "string");
7: props.Add("Age", "int");
8: #>
9: namespace T4Test
10: {
11: public class Demo
12: {
13: <#
14: foreach (KeyValuePair<string, string> prop in props)
15: {
16: #>
17:
18: /// <summary>
19: /// Get or set the <#= prop.Key #> property.
20: /// </summary>
21: public <#= prop.Value #> <#= prop.Key #> { get; set; }
22: <#
23: }
24: #>
25: }
26: }
The template looks nice, specially with the keyword highlighting but unfortunately that is my code snippet for Live Writer at work because Visual Studio only shows this as a single color text. The result is a nice C# class that looks like this:
1: namespace T4Test
2: {
3: public class Demo
4: {
5:
6: /// <summary>
7: /// Get or set the FirstName property.
8: /// </summary>
9: public string FirstName { get; set; }
10:
11: /// <summary>
12: /// Get or set the LastName property.
13: /// </summary>
14: public string LastName { get; set; }
15:
16: /// <summary>
17: /// Get or set the Age property.
18: /// </summary>
19: public int Age { get; set; }
20: }
21: }
Pretty easy to do and a useful technique don’t you think so?
The bad news
So that was rather easy and great for generating business entities with a bunch of properties, all with identical property implementations. And that is exactly what I tend to do in my Silverlight line of business applications. So I decided to try using T4 with a Silverlight project. But unfortunately that didn’t quite work. using exactly the same template I only had the single word “ErrorGeneratingOutput” appear in the output.
The errors where a bit more useful thought.
Error 1 Compiling transformation: The type or namespace name 'CompilerError' does not exist in the namespace 'System.CodeDom.Compiler' (are you missing an assembly reference?)
Error 2 Compiling transformation: The type 'System.CodeDom.Compiler.CompilerErrorCollection' is defined in an assembly that is not referenced. You must add a reference to assembly 'System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'.
It turns out Visual Studio uses the project references itself to run the template. And While the System.CodeDom.Compiler namespace exists in Silverlight the required classes like CompilerError and CompilerErrorCollection do not.
This really is a shame as there is really no good reason that T4 templates do not work for Silverlight. All generation is done in Visual Studio, which has access to the full .NET framework, and not at runtime in the browser.
Still enjoy T4 in the full framework.
www.TheProblemSolver.nl
[2]
And now on Twitter at http://www.twitter.com/mauricedb.
Attached are the PowerPoint presentation and samples from my WF with WCF presentation in Timisoara, Romania. Thanks to Ineta for providing the funding for this.
Attached are the PowerPoint presentation and samples from my state machine workflow presentation in Timisoara, Romania. Thanks to Ineta for providing the funding for this.
Attached is are the samples and slides I used for my intro into WCF talk yesterday at the VB Central meeting in the Netherlands.
Enjoy!
www.TheProblemSolver.nl
Wiki.WindowsWorkflowFoundation.eu
Now also on twitter at http://twitter.com/mauricedb
More Posts
Next page »