|
|
Comments and Discussions
|
|
 |

|
In the article, the application's view is partitioned into a simple <Window> XAML and several <UserControl> elements. This structure is not arbitrary. In particular, my <Button> only worked once I restructured my application to be consistent with the aformentioned layout. Previously, my test project used a single <Window> control to represent the view. ...just an heads up if anyone else was surprised by this.
|
|
|
|

|
Josh, thank you so much for sharing this kind of stuff.
I have a View (Reasons) that has a child view (SelectedQuestions). The selected questions has a datagrid on it. I need to notify the parent view Reasons when a selection is made and the row index of the datagrid on the SelectedQuestions view. When that selection is made in the SelectedQuestions view, the Reason view will enable buttons and populate other datagrids.
Are these routed commands what I am looking for to solve this? I am new to WPF and what direction to go with this issue.
|
|
|
|

|
... stop promoting your book, it's not that fresh anymore, isn't it? How about just posting some nice new snipets instead?
|
|
|
|

|
Hi , one of the comments seems to indicate that this article is deprecated, in which case , what is it replaced with ? I am trying to bind commands to the View model and not the code behind and would like the easiest solution as is available in VS 2010 .
|
|
|
|

|
I like the CommandSinkBinding.CommandSink's Cannot-set-more-than-once-Setter: "maybe public", right?
-- Modified Friday, August 20, 2010 3:02 PM
|
|
|
|

|
An ideal solution to my particular problem giving me the confidence to move on. Losing 1 mark because the source code contained some very relavent code which is missing from the article and confused me a little.
But then being new to WPF and MVVM I am easily confused at the moment.
Thanks for this article.
|
|
|
|

|
Hey Josh - I've been reading lots about MVVM and your name comes up a lot. I appreciate that this article is probably deprecated, but I am struggling over some of the 'problems' that MVVM is attempting to solve - and thought this may be a good place to ask the questions..
Above you say:
There are several distinct benefits in having the routed commands in the View talk directly to the ViewModel.
1. Bypassing the code-behind of the View means the View is that much less coupled to a ViewModel.
2. It also means that the ViewModel is not dependent on the View’s code-behind to properly handle a routed command’s events and delegate those calls off to the correct members on the ViewModel objects.
3. Not only that, but it reduces the amount of coding required to create a View, which is important when working in the Designer-Developer workflow.
(my numbering)
1. I don't get this? Why does it mean that? Don't both the Xaml and C# code behind get compiled into a single class? Sure, having a direct reference in the code behind to an instance of the VM may be a little tightly coupled - but would not using an interface avoid very tight coupling - and be somewhat more robust than using what amount to magic strings in the Xaml?
2. What you say is true - but the VM is dependent on the View to properly handle a routed commend - I don't see the difference other than one is in Xaml and the other C# - the VM is dependent, in fact, on neither, as it is dependent on the object created using c# and Xaml
3. OK - I see that can be the case - although I think this drive to have no code-behind leaving us open to having issues with the designers relying on magic strings (e.g. the names of properties) which is gonna be harder to test than ensuring the view implements an interface (although there's no way I can think of to ensure the design uses the interface methods)
I'm not being critical of your work - I am just displaying my ignorance. I figure, with so many people looking at MVVM with WPF I'm just not getting it...
Cheers
___________________________________________
.\\axxx
(That's an 'M')
|
|
|
|

|
hi, firstly thanks for the great article(s), have really helped me thus far.
Id like to use/execute a command when any item in a list view is selected.
can this be done with either the Listviews ItemContainerStyle or the listViews SelectionChanged event?
thanks.
|
|
|
|

|
My problem with this approach is also my problem with the rather crude Microsoft ICommand scheme, it really is not very clear or flexible. I think that what is needed is something similar to the Binding for data, in fact the same syntax could be used. The ICommand mixes two functions, which I think is wrong. The CanExecute is actually a very good idea, but why not use existing data binding syntax to set the enabled property. Might even what to extend the concept of the ICommand to include more than just the Execute and CanExecute for the button, have the option to include other button attributes such as tooltip and caption to support internationalization also. Anyway I think that there should be a new concept for events where any event can use binding whose implementation would be similar to the current data binding, but would support events instead. The current concept only supports click events, and there are other events which it is often great to be able to support in the MVVM environment. In fact if I could just bind to the state of the button (pushed, not pushed), I could provide a lot of the functionality using databinding. what I would not have is the ability to include parameters. Now if I could do something like this in XAML, I think it may go a long way to simplifying for the developers the MVVM:
Sign In·Permalink | |
|
|
|
|

|
I have a window which contains a TabControl. I've set it up such that each TabItem has its own VM. DataBinding is working fine, but Commanding via the CommandSinkBinding only works if I register for those commands on a VM assigned as the DataContext of the entire Window. Any ideas off the top of your head?
Thanks,
Kelly
|
|
|
|

|
Hi,
Love your stuff. I was just wondering how this fit in with your MVVMFoundation toolkit and the RelayCommand ?
Thanks!
|
|
|
|

|
Hi,
I'm not really sure if this is the correct place to ask this question , but maybe you can help me out.
I'm creating all ribbon stuff(tab, group, controls) dynamically by code behind. I want to fill all tabs and groups from database. But when i wanted to set the LabelTitle, ToolTipTitle, and ToolTipDescription for the RibbonButton, i noticed that they must go in a RibbonCommand and then set that Command to the Button. right?. When i do it by xaml there is no problem. But when i do it on code behind , the labelTitle appears, but the RibbonButton is disabled. I read something about this problem, and it says that RibbonCommand needs to have Execute and CanExecute. My question is, how can i deal with that by code behind.
I'm sorry if this is a easy question , but i'm learning WPF and this new control.
Here is my code:
'TAB
Dim rbnTab As New RibbonTab
rbnTab.Label = "Orders"
'GROUP
Dim rbnGroup As New RibbonGroup
'COMMAND FOR THE GROUP
Dim rbnGroupCommand As New RibbonCommand
rbnGroupCommand.LabelTitle = "Grower Order"
'BUTTON
Dim rbnButton1, rbnButton2 As New RibbonButton
rbnButton1.Content = "Grower Order"
rbnButton2.Content = "Purchase Order"
Dim rbnButtonCommand1 As New RibbonCommand
rbnButtonCommand1.LabelTitle = "Grower"
rbnButtonCommand1.ToolTipTitle = "Grower Order"
rbnButtonCommand1.ToolTipDescription = "This option allows you to create new Grower Orders"
rbnButton1.AddHandler(RibbonButton.ClickEvent, New RoutedEventHandler(AddressOf RibbonButton_Click))
rbnButton2.AddHandler(RibbonButton.ClickEvent, New RoutedEventHandler(AddressOf RibbonButton_Click))
'here is my problem. When i set the command , the ribbonButton appears disabled
rbnButton1.Command = rbnButtonCommand1
rbnGroup.Command = rbnGroupCommand
rbnGroup.Controls.Add(rbnButton1)
rbnGroup.Controls.Add(rbnButton2)
rbnTab.Groups.Add(rbnGroup)
ribbon.Tabs.Add(rbnTab)
'On the XMAL there is just this:
I will really apreciate your help.
Thanks in advance.
|
|
|
|

|
Are command binding thread safe?
TIA
Yazid
|
|
|
|

|
Hello again,
I notice within XAML all the Commands call a static property.
For example
Button
Command="vm:PersonViewModel.SpeakCommand"
CommandParameter="Howdy partner!"
Content="Speak"
Margin="0,0,6,0"
Width="60"
Can it be non static?
The other question I have is if PersonViewModel expects an object in the constructor how do I pass such an object.
TIA
Yaz
|
|
|
|

|
Hello,
Excellent article, to understand it I wrote several UNIT tests and then I wanted to define several listeners using the commandBinding. for example
Button
Command="vm:PersonViewModel.SpeakCommand"
CommandParameter="Howdy partner!"
Content="Speak"
Margin="0,0,6,0"
Width="60"
Using XAML, can I have many listener?
I wanted many listeners, so what I did is that in the code behind I defined a click event and I also raise an event so that anyboby listening will get it rather than just PersonViewModel.
I did this by defining an IView which has an event and then passing the IView in the constructor of the listeners (eg. in PersonViewModel I added a constructur which expects an IView).
TIA
YAz
|
|
|
|

|
Excellent Article,
I wanted to test you project so I divided it into four different projects
Views
Models
Commands
ViewModel
I then Added a test project to write unit tests for Models, Commands, ViewModel. I tried to write a test for the ViewModel (
// CanExecute
Person[] person = Person.GetPeople();
PersonViewModel personViewModel = new PersonViewModel(person[0]);
personViewModel.CanExecuteCommand(?
In the ? it expects an ICommand and I could not find a Command that implements an ICommand. It would be great if you added UNIT tests.
Still it is an excellent article.
Regards
Yaz
|
|
|
|

|
Josh, Thank you for the great articles and examples!
Is there any examples where RoutedCommands are used for multiple instances of the same view and viewmodel?
I think the greatest advantage of RoutedCommands is the notion of a context.
Example:
Top level menu Command="Cut"
If there is a TextBox on your view and some text is selected in it a user can use the top level menu to cut the text in the textbox.
And if the model view have
CommandBinding bindingCut = new CommandBinding(ApplicationCommands.Cut, CommandHandlerCut);
CommandManager.RegisterClassCommandBinding(typeof(ExecuteCommandView), bindingCut);
or even
CommandBinding bindingCut = new CommandBinding(ApplicationCommands.Cut, CommandHandlerCut);
CommandManager.RegisterClassCommandBinding(typeof(Control), bindingCut);
The top level menu 'Cut' would both work for a text selected in a text box and fire the CommandHandlerCut if any other control have focus i.e a button.
Questions:
Does the code above breaks MVVM pattern? Should viewmodel be completely unaware about its view. including type? How about using typeof(Control)?
I use Josh article in MSDN magazine http://msdn.microsoft.com/en-us/magazine/dd419663.aspx[^]as an example for my application.
In my application the main view has a tabcontrol.
The link between the view and viewmodel is through a datatemplate
DataTemplate DataType="{x:Type ViewModel:MyViewModel}"
View:MyView
DataTemplate
tabcontrol tabitems are also generated with a template.
The only difference from the original article: I use RoutedCommands. For some reason if I use the RegisterClassCommandBinding as shown above the commands are always routed to the first tab view model. Any idea why?
I.e. if I created several tabs and each of them created a command binding in the viewmodel as shown above all of them are handeled by the first tab page viewmodel. If I create a simple application that does not use DataTemplate and ItemTemplates it works. Tryed to use attached properties - does not work. i.e.
<Button x:Name="m_SaveButton" ViewModel:AttachedProperties.RegisterCommandBindings="{Binding CommandBindings}" Command="Save" etc…
Thank you. Please help.
|
|
|
|

|
Hi Josh,
I think you've undersold the awesomeness of what you've done here. It is flexible in that it appears to make it easy to add input bindings and stock commands to commands handled by a view model. My question is how can a command get added at the top application menu level that applies to the currently selected person? By example I've added a "Scythe Menu" and some keyboard shortcuts as explained below. The "Kill All" menu and "Ctrl+K" gestures work. The "Del" gesture works. The "Delete" menu does not. Why not? I tried setting FocusManager.IsFocusScope on the CommunityView to no avail. What is the best way to do something like this with MVVM?
PersonViewModel.cs: Added one of the "Stock" WPF Commands
public PersonViewModel(Person person) {
_commandSink.RegisterCommand(
System.Windows.Documents.EditingCommands.Delete,
param => this.CanDie,
param => this.Die());
Personview.xaml: Added an input binding for the stock command the "Stock" WPF Commands
<UserControl.CommandBindings>
<jas:CommandSinkBinding Command="vm:PersonViewModel.DieCommand" />
<jas:CommandSinkBinding Command="vm:PersonViewModel.SpeakCommand" />
<jas:CommandSinkBinding Command="EditingCommands.Delete" />
</UserControl.CommandBindings>
<UserControl.InputBindings>
<KeyBinding x:Uid="KeyBindingDelete"
Command="EditingCommands.Delete"
Gesture="Del" />
</UserControl.InputBindings>
DemoWindow.xaml: Added input bindings for both & a top level menu
<Window
x:Class="VMCommanding.DemoWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:view="clr-namespace:VMCommanding.View"
xmlns:vm="clr-namespace:VMCommanding.ViewModel"
FontSize="13"
ResizeMode="NoResize"
SizeToContent="WidthAndHeight"
Title="ViewModel Commanding Demo"
WindowStartupLocation="CenterScreen"
xmlns:jas="clr-namespace:VMCommanding"
jas:CommandSinkBinding.CommandSink="{Binding}"
>
<Window.CommandBindings>
<jas:CommandSinkBinding Command="vm:CommunityViewModel.KillAllMembersCommand" />
</Window.CommandBindings>
<Window.InputBindings>
<KeyBinding x:Uid="KeyBindingKillAll"
Command="vm:CommunityViewModel.KillAllMembersCommand"
Gesture="Ctrl+K" />
<KeyBinding x:Uid="KeyBindingDelete"
Command="EditingCommands.Delete"
Gesture="Del" />
</Window.InputBindings>
<Window.DataContext>
<vm:CommunityViewModel/>
</Window.DataContext>
<Window.Content>
<DockPanel>
<Menu DockPanel.Dock="Top">
<MenuItem Header="_Scythe">
<MenuItem Command="vm:CommunityViewModel.KillAllMembersCommand"
Header="Kill All"
InputGestureText="Ctrl+K"
/>
<MenuItem Command="EditingCommands.Delete"
Header="Delete"
InputGestureText="Del" />
</MenuItem>
</Menu>
<view:CommunityView FocusManager.IsFocusScope="True" />
</DockPanel>
</Window.Content>
</Window>
If you are intersted I could zip up the modified project and sent it along.
Sincerely,
-Ron
|
|
|
|

|
Hi there Josh,
that was exactly I was looking for.
Kind regards,
Sörnt
|
|
|
|

|
Great article, thanks a lot ( got my 5 cents )
It would be interesting to see if the same solution could be applied to handle both regular CommandBindings as well as RibbonCommands ( from Office Fluent UI Pack ).
|
|
|
|

|
Josh, Before i start i must say excellent articles. Keep em coming. After using your approach on the separation of the commands from the view models i was having difficulty on binding the child items of tree views and context menus. Also all the xaml was starting to look a messy so i thought i've have a go at doing this another way and was wondering what you think. My approach was not to use CommandSinks but instead to use reflection, attributes and a single RoutedCommand which the called the relevant methods based on the CommandParameter. The xaml code is as follows: <UserControl.CommandBindings> <CommandBinding Command="msg:CommandControl.ExternalCommand" CanExecute="CanExecute" Executed="Executed" /> </UserControl.CommandBindings>
<UserControl.DataContext> <vm:AllSolutionsViewModel /> </UserControl.DataContext> <UserControl.Resources> <ContextMenu x:Key="SolutionMenu"> <MenuItem Header="Add Application2" Command="msg:CommandControl.ExternalCommand" CommandParameter="AddApplication" /> <MenuItem Header="Delete Solution" Command="msg:CommandControl.ExternalCommand" CommandParameter="DeleteSolution" /> </ContextMenu> <ContextMenu x:Key="ApplicationMenu"> <MenuItem Header="Add Channel" Command="msg:CommandControl.ExternalCommand" CommandParameter="AddChannel"/> </ContextMenu> </UserControl.Resources> <TreeView ItemsSource="{Binding Path=Solutions}"> <TreeView.Resources> <HierarchicalDataTemplate DataType="{x:Type vm:SolutionViewModel}" ItemsSource="{Binding Path=Applets}" > <StackPanel Orientation="Horizontal"> <Button Content="Add Application" Command="msg:CommandWindow.ExternalCommand" CommandParameter="AddApplication"></Button> <TextBlock Text="{Binding Path=SolutionName}" ContextMenu="{StaticResource SolutionMenu}" Tag="{Binding}"/> </StackPanel> </HierarchicalDataTemplate> <HierarchicalDataTemplate DataType="{x:Type vm:ApplicationViewModel}"> <TextBlock Text="{Binding Path=ApplicationName}" ContextMenu="{StaticResource ApplicationMenu}"/> </HierarchicalDataTemplate> </TreeView.Resources> </TreeView>
The 'CommandControl' class derived from UserControl and the application UserControl is derived from CommandCommand. The CommandCOntrol class can be seen here: public class CommandControl: UserControl { public CommandWindow() { // This is the actual routed commands are found and stored ExternalCommands.SetCommands(GetType().Assembly); } public static readonly RoutedCommand ExternalCommand = new RoutedCommand(); public void CanExecute(object sender, CanExecuteRoutedEventArgs e) { e.CanExecute = ExternalCommands.CallCanExecute((string)e.Parameter, ((FrameworkElement)e.OriginalSource).DataContext); e.Handled = true; }
public void Executed(object sender, ExecutedRoutedEventArgs e) { ExternalCommands.CallExecute((string)e.Parameter, ((FrameworkElement)e.OriginalSource).DataContext); }</pre>
The ExternalCommand class is as follows: public static class ExternalCommands { private static Dictionary<string, ExecuteMethods> ExecuteHandlers = new Dictionary<string, ExecuteMethods>(); public static void SetCommands(Assembly asm) { foreach (Type type in asm.GetTypes()) { foreach (AddRoutedCommandAttribute attr in type.GetCustomAttributes(typeof(AddRoutedCommandAttribute), true)) { MethodInfo execute = type.GetMethod(attr.CommandName); MethodInfo canExecute = type.GetMethod("Can" + attr.CommandName); ExecuteMethods em = new ExecuteMethods(execute,canExecute) ; ExecuteHandlers.Add(attr.CommandName, em); } } }
public static void CallExecute(string commandName, object DataContext) { ExecuteHandlers[commandName].ExecuteHandler.Invoke(null, new object[] { DataContext }); }
public static bool CallCanExecute(string commandName, object DataContext) { if (!ExecuteHandlers.ContainsKey(commandName)) throw new ConfigurationException(string.Format("Execute command: '{0}' not found.", commandName)); if (ExecuteHandlers[commandName].CanExecuteHandler == null) return true; return (bool)ExecuteHandlers[commandName].CanExecuteHandler.Invoke(null,new object[]{DataContext}) ; }
class ExecuteMethods { public MethodInfo ExecuteHandler { get; private set; } public MethodInfo CanExecuteHandler { get; private set; } public ExecuteMethods(MethodInfo executeHandler, MethodInfo canExecuteHandler) { ExecuteHandler = executeHandler; CanExecuteHandler = canExecuteHandler; } } }
And the Attribute class looks like this [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] public class AddRoutedCommandAttribute : Attribute { public string CommandName { get; private set; } public AddRoutedCommandAttribute(string commandName) { CommandName = commandName; } }
Now all you have to do is create a new class in the applicaiton that would look something like this: [AddRoutedCommand("AddApplication")] [AddRoutedCommand("DeleteSolution")] public static class SolutionViewCommands { public static bool CanAddApplication(SolutionViewModel model) { return true; } public static void AddApplication(SolutionViewModel model) { MessageBox.Show(model.SolutionName); } // Will always be diplayed.. public static void DeleteSolution(SolutionViewModel model) { MessageBox.Show("DeleteSolution " + model.SolutionName); } } Ok i've not bullet proofed the code but you get the general idea John K. errrr...
|
|
|
|

|
If so, would you please forward them to me?
Thank you,
Troy
|
|
|
|

|
Hello ,
Thanks for post, this solution is perfect when we want to bind to a command that is hosted in the parent view. so routedevents are prefect.
But as i see you have neglegted the ExecutedRoutedEventArgs and CanExecutedRoutedEventArgs parameters in your method and these can be of great value specially when checking for the source of the event.
BR
Shahbour
|
|
|
|

|
Hi,
i was trying to understand your code, but the one question that i cannot answer is, why changes the "Kill All" button to disabled, if you kill all 3 People one after another? Through some logging i found out, that somehow for each button click each CanExecute-Method is executed atleast twice.
Where is the point of interest which queries all CanExecute-Methods everytime?
|
|
|
|

|
Hi Josh.
I'm quite new to WPF and must thank you for your great tutoring. I'm implementing your command mechanism in a TreeView. However, there I've encountered a case in which enabling or disabling a button is dependent in data which resides in one of the nodes predecessors. I'm trying to implement a mechanism in which the windows View model would "Post" a question which would be answered by the relevant predecessor. What is the best MVVM way for doing so?
Thanks,
Izhar Lotem
|
|
|
|

|
Hi Josh, Excellent 5/5.
Happy Coding
Prasad
Thanks and Regards,
prasad
|
|
|
|

|
Hi
could you give any recommendations how to implementent an undo / redo functionality on top of this?
Thanks
|
|
|
|

|
Great article!
I still have some problems in converting the code to VB.NET. In particolar the code:
handler = delegate
{
elem.Loaded -= handler;
ProcessCommandSinkChanged(depObj, sink);
};
elem.Loaded += handler;
isDelayed = true;
uses anonymous delegates that are not yet available in VB.NET.
Can you please give me some help in translating this part?
Thanks a lot,
Marco Ragogna
|
|
|
|

|
Hi Josh,
Great article as usual! I have been trying to get this pattern to work when the data is hierarchical and displayed in a TreeView, and the commands are in a ContextMenu. I have come up with a solution and was hoping to get your input.
The main problem is the way WPF routes commands through the ContextMenu. The CanExecute/Execute events start at the MenuItem and bubble to the ContextMenu as normal, but then routing is transferred to the focused element in the ContextMenu's parent focus scope - this might be the TreeViewItem, or the TreeView or even the parent Window, but is definitely not the elements defined by the DataTemplate for the TreeViewItem's Content. You can see this in CommandManager.OnCanExecute if you have the WPF source.
The solution I came up with works as follows. First I modified your example to add a Family class to the model to introduce a little hierarchy (and corresponding FamilyViewModel). A Family has a Name and a People collection, and CommunityViewModel now has a Families collection instead of People.
Then I modified CommunityView.xaml and replaced the ItemsControl with a TreeView:
<TreeView MinWidth="200" MinHeight="200"
ItemsSource="{Binding Families}"
jas:CommandSinkBinding.CommandSink="{Binding RelativeSource={RelativeSource Self}, Path=SelectedValue}">
<TreeView.ItemContainerStyle>
<Style TargetType="{x:Type TreeViewItem}">
<Setter Property="IsExpanded" Value="True" />
<EventSetter Event="MouseRightButtonDown"
Handler="TreeViewItem_MouseRightButtonDown" />
</Style>
</TreeView.ItemContainerStyle>
<TreeView.CommandBindings>
<jas:CommandSinkBinding Command="vm:PersonViewModel.DieCommand" />
<jas:CommandSinkBinding Command="vm:PersonViewModel.SpeakCommand" />
</TreeView.CommandBindings>
<TreeView.Resources>
<HierarchicalDataTemplate DataType="{x:Type vm:FamilyViewModel}"
ItemsSource="{Binding People}">
<TextBlock Text="{Binding Name}"/>
</HierarchicalDataTemplate>
<DataTemplate DataType="{x:Type vm:PersonViewModel}">
<view:PersonView />
</DataTemplate>
</TreeView.Resources>
</TreeView>
As you can see the CommandBindings and CommandSink for a PersonViewModel have moved to the TreeView. CommandSink is now bound to the TreeView's SelectedValue (more on this later). A right click hander was added to TreeViewItem via ItemContainerStyle to ensure the clicked item is selected when the context menu is displayed (sorry this pollutes the code-behind ).
private void TreeViewItem_MouseRightButtonDown( object sender, MouseEventArgs e )
{
var item = sender as TreeViewItem;
if ( item != null )
{
item.Focus();
e.Handled = true;
}
}
PersonView.xaml was replaced with a single TextBlock with a ContextMenu:
<TextBlock x:Name="textBlock">
<TextBlock.Text>
<MultiBinding StringFormat="{}{0} ({1})">
<Binding Path="Name"/>
<Binding Path="Age"/>
</MultiBinding>
</TextBlock.Text>
<TextBlock.ContextMenu>
<ContextMenu>
<MenuItem Header="Speak" Command="vm:PersonViewModel.SpeakCommand"
CommandParameter="Hello from the Tree!"/>
<MenuItem Header="Die" Command="vm:PersonViewModel.DieCommand"/>
</ContextMenu>
</TextBlock.ContextMenu>
</TextBlock>
Finally I modified CommandSinkBinding to allow the CommandSink property to be modified, so the SelectedValue binding works:
public ICommandSink CommandSink
{
get { return _commandSink; }
set
{
if ( value == null && _commandSink != null )
{
base.CanExecute -= this.OnCanExecute;
base.Executed -= this.OnExecuted;
}
else if ( value != null && _commandSink == null )
{
base.CanExecute += this.OnCanExecute;
base.Executed += this.OnExecuted;
}
_commandSink = value;
}
}
static void ProcessCommandSinkChanged(DependencyObject depObj, ICommandSink commandSink)
{
CommandBindingCollection cmdBindings = GetCommandBindings(depObj);
if (cmdBindings == null)
throw new ArgumentException("The CommandSinkBinding.CommandSink attached property was set on an element that does not support CommandBindings.");
foreach (CommandBinding cmdBinding in cmdBindings)
{
CommandSinkBinding csb = cmdBinding as CommandSinkBinding;
if (csb != null) csb.CommandSink = commandSink;
}
}
private void OnCanExecute( object sender, CanExecuteRoutedEventArgs e )
{
bool handled;
e.CanExecute = _commandSink.CanExecuteCommand( e.Command, e.Parameter, out handled );
e.Handled = handled;
}
private void OnExecuted( object sender, ExecutedRoutedEventArgs e )
{
bool handled;
_commandSink.ExecuteCommand( e.Command, e.Parameter, out handled );
e.Handled = handled;
}
I also allow CommandSink to be set to null in case SelectedValue becomes null, and remove the event handlers in this case. This seems to work OK given a brief amount of testing. It also works if you add InputGestures to either the Command or the TreeView. My main concern is that you had some important reason why CommandSinkBinding.CommandSink couldn't be set more than once.
An alternative approach might be to set CommandSink on the TreeViewItem via ItemContainerStyle, and also somehow set CommandBindings on the TreeViewItem, unfortunately this isn't a dependency property, but maybe you could do it with an attached property.
This approach should also work for ListViews, but you would probably want to set the ContextMenu in ItemContainerStyle as you wouldn't want to change the ItemTemplate for a ListView. Unfortunately there seems to be a bug in the XAML parser that throws an InvalidCastException when you try to add a ContextMenu to a Setter. If you create the Style programaticaly it works.
Sorry for the long-winded post! Looking forward to hearing your response
Phil
modified on Thursday, December 18, 2008 10:18 AM
|
|
|
|

|
Hello Josh!
First, I would like to thank you for all your work... you have contributed immensely to the developer community at large and have found many of your articles extremely helpful... I don't see how you have the time for all of it!
I have been using the (Data-)Model, View, View-Model approach extensively in my WPF projects and was recently experimenting with the command binding implementation you've provided and it works great! However, I just recently ran into a problem where I run into a wall of bricks
I've created an abstract view-model class called "TestViewModelBase" that implements your ICommandSink interface (as well as INotifyPropertyChanged) that will serve as a base for my view models. Now let's say that I want to create a command in my base class whose Can and Execute methods are abstract so that the derived view-models can perform their own implementation of the command. Let's call this command "TestCommand".
I now derive two classes from "TestViewModelBase" and I call them "ViewModelA" and "ViewModelB" respectively. ViewModelA and ViewModelB both implement the CanTest method as true, just to keep things simple for our test. Now in "ViewModelA" I set the Test command implementation to simply spit out the string "ViewModelA" to the console and "ViewModelB" will spit out the string "ViewModelB". This way, we can tell easily which implementation of TestCommand was clicked.
Now let's create a fresh new project with a main window. Let's also add the following user-control :
...
xmlns:local="clr-namespace:TestCommandBinding"
common:CommandSinkBinding.CommandSink="{Binding}"
>
<frameworkelement.commandbindings>
</frameworkelement.commandbindings>
<button content="{Binding Name}" width="100" height="27" verticalalignment="Center" horizontalalignment="Center">
Command="local:TestViewModelBase.TestCommand"
/>
</button>
Now in the main window we will add the following :
xmlns:local="clr-namespace:TestCommandBinding"
Title="Window1" Height="300" Width="300"
DataContext="{Binding RelativeSource={RelativeSource Self}}"
>
<frameworkelement.resources>
</frameworkelement.resources>
<button content="ViewModelA" width="100" height="27" verticalalignment="Top" horizontalalignment="Left" click="Button_Click" />
<button content="ViewModelB" width="100" height="27" verticalalignment="Top" horizontalalignment="Right" click="Button_Click_1" />
and in the code-behind we do this :
private void Button_Click(object sender, RoutedEventArgs e)
{
MyTestViewModel = new ViewModelA();
}
private void Button_Click_1(object sender, RoutedEventArgs e)
{
MyTestViewModel = new ViewModelB();
}
So now when we run the app the main window should contain two buttons called "ViewModelA" and "ViewModelB", and there should be a simple contentcontrol in the center of the window, with it's content bound to an instance of either ViewModelA or ViewModelB depending on whhich button I press. Currently it is null.
If I click on the ViewModelA button, I suddenly see an instance of my control appear containing it's own button. If I click on this button, it executes the TestCommand for ViewModelA's implementation, so you will see ViewModelA in the output window as expected. Now I click on the "ViewModelB" button, so right now the usercontrol in the middle of the window holds an instance of ViewModelB; the previous reference to ViewModelA was overwritten it should be in limbo waiting for garbage-collection at this point. Now I click on the button in the middle and expect it to execute ViewModelB's implementation of the TestCommand... but it doesn't!
Am I missing something or is this a limitation of the current framework? If you want the source code for this test solution fire me an email at AnthonyPaulO (letter O at the end, not a zero!) at hot-mail dot com.
Cheers!!!
Anthony
|
|
|
|

|
Thanks a lot, I'm beginner in WPF but i'm working hard to learn a lot of things.
I have made a test project to learn more on MVVM patter with Josh's commanding library, for interesting people you can check it out here :
http://cid-7c42d86c44c4badb.skydrive.live.com/self.aspx/Public/MVPTest.zip[^]
Does anyone know the best practices to put "add" and "edit" item in separate UserControl with MVVM pattern ? For example put "Add User Control" in the place of "User List" and when validate/cancel re-show "User List"
Generaly when we see MVVM Proof Of Concept, the example are just made to display a simple list.
In my test project i'm trying to build a more realistic real life application with :
- item list (with selection)
- associated item detail (with some actions on item)
- add an item in the same form with separate control (in order to apply transitions for example)
- edit item
I would be happy to have your ideas on the subject
PS : (For Josh) this modifications were made on you original code :
public ICommandSink CommandSink
{
get { return _commandSink; }
set
{
_commandSink = value;
base.CanExecute += (s, e) =>
{
bool handled;
e.CanExecute = _commandSink.CanExecuteCommand(e.Command, e.Parameter, out handled);
e.Handled = handled;
};
base.Executed += (s, e) =>
{
bool handled;
_commandSink.ExecuteCommand(e.Command, e.Parameter, out handled);
e.Handled = handled;
};
}
}
static void ProcessCommandSinkChanged(DependencyObject depObj, ICommandSink commandSink)
{
CommandBindingCollection cmdBindings = GetCommandBindings(depObj);
if (cmdBindings == null)
throw new ArgumentException("The CommandSinkBinding.CommandSink attached property was set on an element that does not support CommandBindings.");
foreach (CommandBinding cmdBinding in cmdBindings)
{
CommandSinkBinding csb = cmdBinding as CommandSinkBinding;
if (csb != null)
csb.CommandSink = commandSink;
}
}
|
|
|
|

|
Excellent article and exactly what I was looking for!
|
|
|
|

|
Please forgive the WPF newbie question. Are there are two CommandSinkBinding.CommandSink properties of the same name: one an instance property and the other an attached property? Or, does CommandSinkBinding have one hugeocomplicated implementation for one CommandSink attached property? If there are two different properties how are they used?
Sincerely,
-Ron
|
|
|
|

|
Very interesting article. As always, thank you for sharing this. One question, though.
In your previous article regarding ViewModel in WPF (Simplifying the WPF TreeView...) it is perfectly clear to me what is the benefit of using a separate ViewModel class to wrap individual template-generated items. However, in this case I do not understand what you are gaining by moving event handlers into a separate ViewModel. I originally thought the idea of a ViewModel was to make it independent of WPF so you could more easily port to another GUI framework later. However, the ViewModels in your example all use RoutedCommand which is a WPF class, so independence from WPF is not achieved. If I was going to create a "root" ViewModel for every screen in my program, in order to make it truly independent of WPF, I'd rather (a) simply have a code-behind file handle commands by invoking methods on the VIewModel, or (b) somehow move the commands and command registration from the ViewModel back to the code-behind file.
|
|
|
|

|
If we imagine that your ItemsControl is replaced by a listbox.
When we select an item on the listbox, we show the Person detail with same commands actions (Die, etc.) on the right in a single instance person view.
What is your recommendations to do that
|
|
|
|

|
When i try to put a thread in ViewModel it seems that commanding re work after user click on the UI.
For example, put this code PersonViewModel
System.Threading.ThreadPool.QueueUserWorkItem(new System.Threading.WaitCallback(
delegate
{
//simulate web service call
System.Threading.Thread.Sleep(5000);
_person.IsAlive = false;
this.OnPropertyChanged("CanDie");
this.OnPropertyChanged("CanSpeak");
}));
You need to click on UI to see buttons disabled, it's normal ? or i miss something.
Great job again !
|
|
|
|

|
How would this approach be localized? I'd like to be able to call a function which would fetch the strings, images, whatever from the resource
Thanks
|
|
|
|

|
One thing I like about your samples, Josh, is you are someone who is showing us how flexible and powerful WPF is as you are giving us clear, testable, structured examples of what you can do with this technology. As WPF is still fairly new, having someone who is showing us a disciplined approach to development with WPF is a great boon towards ensuring people produce high quality software. Thanks for your efforts! You truly deserve that MVP award from Microsoft!
Curtis
|
|
|
|

|
Why not just simply use the CommandManager to register the CommandBindings?
What I normally do is the following:
1. In the view, create an instance of my viewmodel as the DataContext, just like you did in this article.
2. Create the commands as static objects.
3. Set the Command property of a button for instance, as one of the commands.
4. In the constructor of the viewmodel, I register the commandbindings:
CommandManager.RegisterClassCommandBinding(typeof(DemoWindow), new CommandBinding(PersonViewModel.DieCommand, dieExecuted, canExecuteDie));
5. Implement the handlers (in this case, canExecuteDie & dieExecuted) for the commands in the viewmodel.
or is there something I'm missing with this approach?
Cheers!
|
|
|
|

|
I have done a little variant in the way the command binding bettwen the view and the viewmodel works.
What I don't like of these approach is the way that you must define the each command binding independly in the view: for each button (or other UIElement) you must define the command of the element and his commandbinding.
I think is more clear to let the viewmodel register all the bindings.
I have written an explanation here.
|
|
|
|
|

|
Great article about something we've been looking at for some time.
The thing we've been running into is that WPF only implements some actions as command triggers, i.e. clicks. What is the best way to trigger commands from other actions, such as focusing/defocusing, mouseover/mouseout, etc? We'd like to bind these to commands as well so we can completely decouple our UI from our application logic.
Any ideas or references to discussions of this topic?
Thanks!!
|
|
|
|

|
Man, where did you find the time to do this last night? I haven't been able to play with code like that since my bachelor days!
Any way, this is a fairly nice approach. It's definitely clean on the markup side, and I can imagine ways to make it cleaner on the code side. All those "if" statements in the ICommandSink interface are ugly, to say the least. However, a simple CommandDispatcher concept could simplify that on the code side (similar in nature to the CommandBindingCollection, but whose purpose is more like an MFC message map).
What I don't like, is the following:
"It is important to note that setting the attached CommandSink property only has an effect once for an element. You cannot set it again, nor set it to null. If you subsequently add a RelayCommandBinding to that element’s CommandBindings, you will have to explicitly set that object’s CommandSink property to an ICommandSink object. The CommandBindingCollection class does not provide collection change notifications, so I have no way of knowing if or when new items are added to the collection."
Those restrictions are precisely why I was not using the CommandBindings for this. So, you have a trade off. Nicer XAML with some usage restrictions, or less elegant XAML but no (or at least fewer) restrictions on usage.
William E. Kempf
|
|
|
|

|
Hi Josh,
First of all, thank you very much for this new article.
I'm trying to use it in a WPF application which already uses the ViewModel pattern with a TreeView (thanks to your other amazing articles on MVVM...)
I have a view which displays my TreeView: WorkspaceTreeView.
If I setup its data context to the top level of my ViewModel object, then I cannot execute command on lower ViewModel objects... (For example, I have SolutionViewModel, then ProjectViewModel, then FileViewModel...)
Any idea how I can achieve that ?
Regards,
Jeremy
|
|
|
|

|
Really cool stuff. Thanks for this Josh.
Jammer
Going where everyone here has gone before!
My Blog
|
|
|
|

|
I really like this approach and also Dan Crevier's encapsulated commands.
Both excellent.
I wanted to use something like this, but my team leader wants the ViewModel to be UI agnostic, such that the view could be WPF or ASP .NET or even a Winform.
I am assuming that because the ICommand interface is within the System.Windows.Input namespace this approach and (Dans for that matter) are tied to WPFism.
I guess you could use the System.Windows.Input by referencing the PresentationCore.dll, to allow Non WPF apps to use this approach. That just seems dirty to me. But it would work I guess.
What are your thoughts on this.
Don't get me wrong, this is great stuff though, its just my boss wants a totally UI agnostic ViewModel.
PS : Congrats on article 51
Sacha Barber
- Microsoft Visual C# MVP 2008
- Codeproject MVP 2008
Your best friend is you.
I'm my best friend too. We share the same views, and hardly ever argue
My Blog : sachabarber.net
|
|
|
|

|
Only a "Die"-button is really needed.
I´am just kidding. Good article.
|
|
|
|

|
Great article and well explained. I've been using the MVVM approach in WPF for the last few months now with quite a big project with a lot of success, but hadn't found a simple way of using RoutedCommands with the ViewModel without messy code. I've been using Dan Crevier’s CommandModel, but it's a bit heavyweight and you end up with lots of code-bloat with lots of classes for the commands.
I really like the lightweight approach you give. It seems relatively simple, yet powerful, to be able to direct the commands straight to the ViewModel.
I find the contents of the CanExecuteCommand() and ExecuteCommand() in the ViewModels to be a bit inelegant though:
if (command == xCommand)
xFunc();
else if (command == yCommand)
yFunc();
else if (command == zCommand)
zFunc();
etc.
If you have lots of commands it could get a bit messy and starts to have a bit of code-smell. But maybe that's the price to pay for being lightweight? I will certainly have a go at implementing your approach in my app.
I'm still learning WPF and articles like yours help us along the way!
|
|
|
|

|
I've come to work and a quick visit to your blog takes me to this article. The topic using Commands in conjunction with MVVM is keeping me busy all the time. So now....
[reading mode]
|
|
|
|
 |
|
|
General News Suggestion Question Bug Answer Joke Rant Admin
|
Reviews a clean and lightweight way to use RoutedCommands in the MVVM pattern.
| Type | Article |
| Licence | CPOL |
| First Posted | 24 Jul 2008 |
| Views | 226,494 |
| Downloads | 1,853 |
| Bookmarked | 127 times |
|
|