I’m a big fan of Caliburn.Micro and I hope that my presentation helped you become one too. Here’s the materials I used for the presentation:
Slides on SlideShare, Code on Github
Enjoy!
Random thoughts from a software guy
I’m a big fan of Caliburn.Micro and I hope that my presentation helped you become one too. Here’s the materials I used for the presentation:
Slides on SlideShare, Code on Github
Enjoy!
On my current project, we need to open a record for editing when the DataGridRow is double clicked. Unfortunately, the WPF DataGrid doesn’t support this functionality out of the box. There are, however, a couple ways to make this happen.
One way is to handle MouseDoubleClick event on the DataGrid. We are using Caliburn.Micro, so it is easy to get the MouseDoubleClick event to route to our view model. The view model can then assume that the selected item is to be edited. The problem with this is that double clicking anywhere on the DataGrid will trigger this event, including the scrollbars. That means that quickly scrolling down the items could trigger a double click and cause whatever item was last selected to be edited, which is unacceptable.
What we needed was to somehow handle the MouseDoubleClick event on each DataGridRow, make sure the one being double clicked on is actually selected, then call tell the view model to edit it.
I ultimately came up with two solutions. One uses a little code-behind and applies only to one case at a time. The other uses an attached DependencyProperty and is general enough to apply to all cases.
The code-behind solution may break the MVVM pattern, depending on your point of view. I feel that using code-behind makes sense in cases where you have logic that is specific to your how your view represents the UI.
First, you need to create the MouseDoubleClick event handler in the code-behind.
1 2 3 4 5 6 7 8 9 |
protected void OnMouseDoubleClick(object sender, EventArgs args) { var row = sender as DataGridRow; if (row != null && row.IsSelected) { var viewModel = (MainViewModel)DataContext; viewModel.Edit(); } } |
Next, you need the wire up each DataGridRow to use that handler for MouseDoubleClick events. You can do that with styling.
1 2 3 4 5 6 7 8 9 10 11 |
<DataGrid ItemsSource="{Binding People}" SelectedItem="{Binding SelectedPerson}" IsReadOnly="True"> <DataGrid.ItemContainerStyle> <Style TargetType="DataGridRow"> <EventSetter Event="MouseDoubleClick" Handler="OnMouseDoubleClick" /> </Style> </DataGrid.ItemContainerStyle> </DataGrid> |
That’s it. This solution is pretty straight-forward. However, there are two problems with the code-behind solution.
The first problem is that this solution doesn’t scale. What I mean by that is that you have to re-implement it every time you want to use it.
The second problem is that it uses code-behind. As I said earlier, I believe the use of code-behind has its place. However, I prefer to stay away from it if I can.
The attached DependencyProperty solution uses a helper class so that it can be reused across your application. It also assumes that your DataGrid’s DataContext is your view model. If that is not the case, you will need to modify it.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
public sealed class RowDoubleClickHandler : FrameworkElement { public RowDoubleClickHandler(DataGrid dataGrid) { MouseButtonEventHandler handler = (sender, args) => { var row = sender as DataGridRow; if (row != null && row.IsSelected) { var methodName = GetMethodName(dataGrid); var dataContextType = dataGrid.DataContext.GetType(); var method = dataContextType.GetMethod(methodName); if (method == null) { throw new MissingMethodException(methodName); } method.Invoke(dataGrid.DataContext, null); } }; dataGrid.LoadingRow += (s, e) => { e.Row.MouseDoubleClick += handler; }; dataGrid.UnloadingRow += (s, e) => { e.Row.MouseDoubleClick -= handler; }; } public static string GetMethodName(DataGrid dataGrid) { return (string)dataGrid.GetValue(MethodNameProperty); } public static void SetMethodName(DataGrid dataGrid, string value) { dataGrid.SetValue(MethodNameProperty, value); } public static readonly DependencyProperty MethodNameProperty = DependencyProperty.RegisterAttached( "MethodName", typeof(string), typeof(RowDoubleClickHandler), new PropertyMetadata((o, e) => { var dataGrid = o as DataGrid; if (dataGrid != null) { new RowDoubleClickHandler(dataGrid); } })); } |
This helper class ties into the DataGrid’s LoadingRow event and uses reflection to find a specified method on the DataContext and execute it. All you have left to do is use it.
1 2 3 4 5 |
<DataGrid ItemsSource="{Binding People}" SelectedItem="{Binding SelectedPerson}" IsReadOnly="True" helpers:RowDoubleClickHandler.MethodName="Edit" /> |
All you need to do is provide the name of the method on your view model to execute when the double click has occurred and the rest is taken care of.
While it’s unfortunate that WPF doesn’t provide this functionality right out of the box, it is not difficult to implement it yourself. Silverlight suffers from this same shortcoming. This solution won’t work as-is for Silverlight. It would need to be refactored into using Behaviors instead of an attached DependencyProperty.
I have posted a complete solution on github: https://github.com/brentedwards/DataGridRow_DoubleClick
Happy coding!
A few weeks ago, after presenting at CodeMastery, I sat down with Carl Franklin from dnrTV! to discuss WPF with MVVM. The discussion is centered around the demo portion of my presentation entitled WPF with MVVM: From the Trenches. This presentation is the precursor to the work I have done with MVVM Fabric. Without further ado, check it out here: http://dnrtv.com/default.aspx?ShowID=184 – complete with an un-flattering pic
A few days ago, I wrote about using MVVM Fabric’s ActionCommand. Commanding can be useful with controls that provide a Command property, such as Buttons and MenuItems. However, commanding doesn’t help when you want to wire up arbitrary events to your view model. That is where TriggerAction come in.
TriggerAction is a look-less framework element that wires itself up to whatever event you specify on whatever control you specify. When that event is raised, TriggerAction calls whatever method you specify on your view model.
TriggerAction was written by Rocky Lhotka for his business object framework, CSLA .NET. Since CSLA is open source, Rocky gave me permission to include TriggerAction with MVVM Fabric because of the great value it would provide consumers of the library. I have been using a precursor of TriggerAction, called InvokeMethod, on my projects with great success. While InvokeMethod has some limitations (no designer support and the ability to only wire one event for a control), TriggerAction provides a more robust implementation and eliminates these issues.
There’s really two different ways that I typically use TriggerAction. The first way is when I really only care if an event happened.
For this example, we will wire up TriggerAction to call the Close method on our view model when a button is clicked. We first need to name the button that we will be hooking events from.
1 2 3 |
<Button Name="CloseButton" Content="Close" /> |
Next we place the TriggerAction on our view.
1 2 3 4 5 6 |
<mvvm:TriggerAction TargetControl="{Binding ElementName=CloseButton}" MethodName="Close" TriggerEvent="Click" Width="0" Height="0" /> |
Notice that I used an Element Binding for the TargetControl property. That is how we tell TriggerAction to listen for the click event on our button. I also set the MethodName property with the name of the method we want called. It is important to note that TriggerAction looks for the method specified on its DataContext. So, you have to make sure that the DataContext is your view model if you want it to call methods on your view model.
Now we need to write the Close method on our view model.
1 2 3 4 |
public void Close() { // Do Stuff. } |
We’re all set. When the Click event is raised on our button, TriggerAction will look for a method called Close on its DataContext (which is our view model). The method it looks for must have 0 or 2 arguments. We have the 0 argument version here because we only care that the event happened.
The second way I typically use TriggerAction is for those situations where I need to pass a parameter to my method when the event I care about is raised.
For this example (and the one you will see in the sample application), we will wire up the MouseDoubleClick event on a ListView to pass the SelectedItem back to our method on the view model.
First, the ListView.
1 2 3 |
<ListView Name="MoviesList" ItemsSource="{Binding Movies}" /> |
Next, the TriggerAction.
1 2 3 4 5 6 7 8 |
<mvvm:TriggerAction TargetControl="{Binding ElementName=MoviesList}" MethodName="MovieSelected" MethodParameter="{Binding Path=SelectedItem, ElementName=MoviesList}" TriggerEvent="MouseDoubleClick" RebindParameterDynamically="True" Width="0" Height="0" /> |
There are two things different about our usage of TriggerAction here. The first difference is the addition of the MethodParameter property, which we are binding to the SelectedItem property on the MoviesList element. The second is setting RebindParameterDynamically to true.
The MethodParameter property on TriggerAction is where you bind whatever you want from the view to be passed back your view model. This can be something on the element you are listening for events on or something somewhere else on the view.
The RebindParameterDynamically property is really cool. When this is set to true, TriggerAction will go out and rebind to the method parameter before calling back to your method so that you are always sending back the latest and greatest. Since not all of the properties you want to bind to raise property changed events, this is a huge benefit.
Now, on to the view model. As I mentioned before, when looking for methods on our view model, TriggerAction will look for methods with either 0 or 2 parameters. Since we need that MethodParameter passed in, we will need the 2 parameter version.
1 2 3 4 5 |
public void MovieSelected(object sender, ExecuteEventArgs args) { var movie = args.MethodParameter as Movie; // Do Stuff. } |
This is a typical event handler method signature. The event args that are passed through are ExecuteEventArgs, which have some useful properties. The property we care about right now is the MethodParameter property, which needs to be cast before we use it because it is of type Object. Once we cast it as our Movie business object, the view model is free to do what it needs with it.
Although commanding is a decent start to executing methods on your view model, TriggerAction is a much more robust solution. With drag-and-drop designer support, the ability to bind a method parameter and the ability to have that method parameter dynamically updated at execution time, TriggerAction is an extremely powerful way to wire arbitrary events from your view to your view model.
I’ve been working with MVVM on WPF applications for well over a year now on two major projects. As the UI architect for both projects, I was the guy who had to figure out how to make things work in a way that was extensible and testable. With each WPF project I did that leveraged MVVM, I found there were common problems that needed to be solved. These common problems include communication between views, decoupled/testable navigation between views and commanding. To solve these problems, I initially developed a solution and refactored as needed to fit the different scenarios I encountered.
After spending over a year with the solution, I feel that it stabilized well enough to be confident that I had the foundation for a more general purpose solution. I have taken what I did on both projects and what I learned from them while doing it and created a library that I am calling MVVM Fabric. The (mostly selfish) goal with MVVM Fabric was to create an MVVM library that I could weave into other projects with minimal effort.
The real trick was taking what I had integrated into my most recent project and extracting it in such a way that I could turn it into a library and keep it usable.
MVVM Fabric is the result of that exercise. It is a WPF-centric library, written in C# 4.0, which helps address communication, navigation and commanding in an application leveraging MVVM. It provides core functionality and leverages dependency injection to provide extensibility.
I have posted the library along with a sample application which uses it out on github: https://github.com/brentedwards/MvvmFabric.
If you have attended my presentation WPF with MVVM: From the Trenches or looked at the presentation materials, you will likely notice many similarities. That presentation and the resulting sample application were both based on the same projects as MVVM Fabric. So, I refactored that sample application to eat my own dog food and work out some kinks. The result is something that I am happy with, though will likely be further extended as I (or you) see fit.
I plan to write several blog posts to provide a more in-depth introduction and explanation of the library (and reasons behind the decisions I made) in coming days.
If you have heard my presentation, I hope that you found it useful. To give you a chance to review, here are the presentation materials I used.
Slides: http://www.slideshare.net/brentledwards/wpf-with-mvvm-from-the-trenches
Code: http://github.com/brentedwards/Movies
If you have seen my presentation, I would really appreciate some feedback.
Chippewa Valley Code Camp 2010
I’ve been working with WPF a lot lately for a client project and I’ve learned some pretty cool tricks along the way. I am planning to do a bunch of posts describing many of these tricks in the near future. The first cool trick I will be talking about is how to make a control that switches between editable mode and read-only mode using only XAML, kind of.
I say ‘kind of’ because we will have some code to make it happen, but not in the code-behind. Rather than use a code-behind, we will be leveraging the Model-View-ViewModel (MVVM) design pattern to keep our code separate and testable.
Let’s dive right into the code by taking a look at the view model. Since we will be leveraging WPF’s awesome data binding, we need to prepare the view model to allow WPF to keep track of property changes. To do this, our view model will implement INotifyPropertyChanged. Doing so will allow the WPF binding engine to listen for changes and update the view accordingly.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
public class SampleViewModel : INotifyPropertyChanged { #region INotifyPropertyChanged Members public event PropertyChangedEventHandler PropertyChanged; #endregion private void NotifyPropertyChanged(String propertyName) { if (PropertyChanged != null) { var args = new PropertyChangedEventArgs(propertyName); PropertyChanged(this, args); } } } |
You’ll notice that I added a method called NotifyPropertyChanged. This is just to simplify the process of raising the event from the property setters.
Next up we will set up the properties that the view will be binding to. Our example is very simple, so there will only be two properties in the view model: IsReadOnly and Name.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
private Boolean _IsReadOnly; public Boolean IsReadOnly { get { return _IsReadOnly; } set { _IsReadOnly = value; NotifyPropertyChanged("IsReadOnly"); } } private String _Name = "Bob Lablaw"; public String Name { get { return _Name; } set { _Name = value; NotifyPropertyChanged("Name"); } } |
Notice that both of the setters make a call to NotifyPropertyChanged, giving the name of the respective property. That is what will signal the binding engine to update anything that is bound to one of those two properties.
That’s it for the view model. We’re keeping things simple. Let’s move on to the view itself. First things first, we need to set up the view model as the DataContext.
1 2 3 4 5 6 7 8 9 |
<Window x:Class="DataTemplatesTriggers.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:vm="clr-namespace:DataTemplatesTriggers.ViewModels" Title="Window1" Height="300" Width="300"> <Window.DataContext> <vm:SampleViewModel /> </Window.DataContext> </Window> |
Next up we are going to set up some the style for the ContentControl.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
<Window.Resources> <Style x:Key="NameStyle" TargetType="ContentControl"> <Style.Triggers> <DataTrigger Binding="{Binding IsReadOnly}" Value="True"> <Setter Property="ContentControl.Template"> <Setter.Value> <ControlTemplate> <Grid> <Label Content="{Binding Name}" /> </Grid> </ControlTemplate> </Setter.Value> </Setter> </DataTrigger> <DataTrigger Binding="{Binding IsReadOnly}" Value="False"> <Setter Property="ContentControl.Template"> <Setter.Value> <ControlTemplate> <Grid> <TextBox Text="{Binding Path=Name, UpdateSourceTrigger=PropertyChanged}" /> </Grid> </ControlTemplate> </Setter.Value> </Setter> </DataTrigger> </Style.Triggers> </Style> </Window.Resources> |
Now, this is where the magic happens. You’ll see that we have a style here with two DataTriggers. Both of the DataTriggers bind to the IsReadOnly property of our view model. One of the DataTriggers handles when IsReadOnly is True and the other handles when IsReadOnly is False.
If IsReadOnly is True, we set the Template to a Grid with a static Label. The Label is bound to the Name property.
If IsReadOnly is False, we set the Template to a Grid with a TextBox. The TextBox also binds to the Name property and sets UpdateSourceTrigger=PropertyChanged. The reason for this is that the binding would normally wait to trigger an update to the property until it loses focus. Setting UpdateSourceTrigger=PropertyChanged will trigger the update with every key press.
The only missing piece to this puzzle is to place the actual ContentControl.
1 2 3 4 5 6 |
<Grid Margin="10"> <StackPanel Orientation="Vertical"> <CheckBox Content="Read Only" IsChecked="{Binding IsReadOnly}" /> <ContentControl Style="{StaticResource NameStyle}" /> </StackPanel> </Grid> |
To use the style we created above, we simply need to bind the Style of the ContentControl to the Style with the Key Name. You’ll also notice that I have placed a CheckBox in there as well, giving a way to test that the whole operation works.
So, that pretty much wraps it up. We now have a control that completely changes it’s look based on only a boolean value. Although this example is quite simple, this approach can be applied to more complex situations. You can take the solution at the end of the post and poke around a little.
Hopefully this has been helpful! Have fun with it!
I’ve been working with WPF a lot lately for a client project and I’ve learned some pretty cool tricks along the way. I am planning to do a bunch of posts describing many of these tricks in the near future. The first cool trick I will be talking about is how to make a control that switches between editable mode and read-only mode using only XAML, kind of.
I say ‘kind of’ because we will have some code to make it happen, but not in the code-behind. Rather than use a code-behind, we will be leveraging the Model-View-ViewModel (MVVM) design pattern to keep our code separate and testable.
Let’s dive right into the code by taking a look at the view model. Since we will be leveraging WPF’s awesome data binding, we need to prepare the view model to allow WPF to keep track of property changes. To do this, our view model will implement INotifyPropertyChanged. Doing so will allow the WPF binding engine to listen for changes and update the view accordingly.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
public class SampleViewModel : INotifyPropertyChanged { #region INotifyPropertyChanged Members public event PropertyChangedEventHandler PropertyChanged; #endregion private void NotifyPropertyChanged(String propertyName) { if (PropertyChanged != null) { var args = new PropertyChangedEventArgs(propertyName); PropertyChanged(this, args); } } } |
You’ll notice that I added a method called NotifyPropertyChanged. This is just to simplify the process of raising the event from the property setters.
Next up we will set up the properties that the view will be binding to. Our example is very simple, so there will only be two properties in the view model: IsReadOnly and Name.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
private Boolean _IsReadOnly; public Boolean IsReadOnly { get { return _IsReadOnly; } set { _IsReadOnly = value; NotifyPropertyChanged("IsReadOnly"); } } private String _Name = "Bob Lablaw"; public String Name { get { return _Name; } set { _Name = value; NotifyPropertyChanged("Name"); } } |
Notice that both of the setters make a call to NotifyPropertyChanged, giving the name of the respective property. That is what will signal the binding engine to update anything that is bound to one of those two properties.
That’s it for the view model. We’re keeping things simple. Let’s move on to the view itself. First things first, we need to set up the view model as the DataContext.
1 2 3 4 5 6 7 8 9 |
<Window x:Class="DataTemplatesTriggers.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:vm="clr-namespace:DataTemplatesTriggers.ViewModels" Title="Window1" Height="300" Width="300"> <Window.DataContext> <vm:SampleViewModel /> </Window.DataContext> </Window> |
Next up we are going to set up some the style for the ContentControl.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
<Window.Resources> <Style x:Key="NameStyle" TargetType="ContentControl"> <Style.Triggers> <DataTrigger Binding="{Binding IsReadOnly}" Value="True"> <Setter Property="ContentControl.Template"> <Setter.Value> <ControlTemplate> <Grid> <Label Content="{Binding Name}" /> </Grid> </ControlTemplate> </Setter.Value> </Setter> </DataTrigger> <DataTrigger Binding="{Binding IsReadOnly}" Value="False"> <Setter Property="ContentControl.Template"> <Setter.Value> <ControlTemplate> <Grid> <TextBox Text="{Binding Path=Name, UpdateSourceTrigger=PropertyChanged}" /> </Grid> </ControlTemplate> </Setter.Value> </Setter> </DataTrigger> </Style.Triggers> </Style> </Window.Resources> |
Now, this is where the magic happens. You’ll see that we have a style here with two DataTriggers. Both of the DataTriggers bind to the IsReadOnly property of our view model. One of the DataTriggers handles when IsReadOnly is True and the other handles when IsReadOnly is False.
If IsReadOnly is True, we set the Template to a Grid with a static Label. The Label is bound to the Name property.
If IsReadOnly is False, we set the Template to a Grid with a TextBox. The TextBox also binds to the Name property and sets UpdateSourceTrigger=PropertyChanged. The reason for this is that the binding would normally wait to trigger an update to the property until it loses focus. Setting UpdateSourceTrigger=PropertyChanged will trigger the update with every key press.
The only missing piece to this puzzle is to place the actual ContentControl.
1 2 3 4 5 6 |
<Grid Margin="10"> <StackPanel Orientation="Vertical"> <CheckBox Content="Read Only" IsChecked="{Binding IsReadOnly}" /> <ContentControl Style="{StaticResource NameStyle}" /> </StackPanel> </Grid> |
To use the style we created above, we simply need to bind the Style of the ContentControl to the Style with the Key Name. You’ll also notice that I have placed a CheckBox in there as well, giving a way to test that the whole operation works.
So, that pretty much wraps it up. We now have a control that completely changes it’s look based on only a boolean value. Although this example is quite simple, this approach can be applied to more complex situations. You can take the solution at the end of the post and poke around a little.
Hopefully this has been helpful! Have fun with it!