Custom WPF command pattern example - wpf

I've done some WPF programing and one thing I never got was the command pattern. Every example seems to be for built in ones, edit, cut, paste. Anyone have an example or suggestion of best practice for custom commands?

Ah ha! A question I can answer! Firstly, I should mention that I have personally found it easier to define and hook up commands in code rather than in XAML. It allows me to hook up the handlers for the commands a little more flexibly than an all XAML approach does.
You should work out what commands you want to have and what they relate to. In my application, I currently have a class for defining important application commands like so:
public static class CommandBank
{
/// Command definition for Closing a window
public static RoutedUICommand CloseWindow { get; private set; }
/// Static private constructor, sets up all application wide commands.
static CommandBank()
{
CloseWindow = new RoutedUICommand();
CloseWindow.InputGestures.Add(new KeyGesture(Key.F4, ModifierKeys.Alt));
// ...
}
Now, because I wanted to keep the code all together, using a code only approach to Commands lets me put the following methods in the class above:
/// Closes the window provided as a parameter
public static void CloseWindowExecute(object sender, ExecutedRoutedEventArgs e)
{
((Window)e.Parameter).Close();
}
/// Allows a Command to execute if the CommandParameter is not a null value
public static void CanExecuteIfParameterIsNotNull(object sender, CanExecuteRoutedEventArgs e)
{
e.CanExecute = e.Parameter != null;
e.Handled = true;
}
The second method there can even be shared with other Commands without me having to repeat it all over the place.
Once you have defined the commands like this, you can add them to any piece of UI. In the following, once the Window has Loaded, I add command bindings to both the Window and MenuItem and then add an input binding to the Window using a loop to do this for all command bindings. The parameter that is passed is the Window its self so the code above knows what Window to try and close.
public partial class SimpleWindow : Window
{
private void WindowLoaded(object sender, RoutedEventArgs e)
{
// ...
this.CommandBindings.Add(
new CommandBinding(
CommandBank.CloseWindow,
CommandBank.CloseWindowExecute,
CommandBank.CanExecuteIfParameterIsNotNull));
foreach (CommandBinding binding in this.CommandBindings)
{
RoutedCommand command = (RoutedCommand)binding.Command;
if (command.InputGestures.Count > 0)
{
foreach (InputGesture gesture in command.InputGestures)
{
var iBind = new InputBinding(command, gesture);
iBind.CommandParameter = this;
this.InputBindings.Add(iBind);
}
}
}
// menuItemExit is defined in XAML
menuItemExit.Command = CommandBank.CloseWindow;
menuItemExit.CommandParameter = this;
// ...
}
// ....
}
I then also later have event handlers for the WindowClosing and WindowClosed events, I do recommend you make the actual implementation of commands as small and generic as possible. As in this case, I didn't try to put code that tries to stop the Window closing if there is unsaved data, I kept that code firmly inside the WindowClosing event.
Let me know if you have any follow up questions. :)

I blogged about a bunch of resources on WPF Commands along with an example last year at http://blogs.vertigo.com/personal/alanl/Blog/archive/2007/05/31/commands-in-wpf.aspx
Pasting here:
Adam Nathan’s sample chapter on Important New Concepts in WPF: Commands
MSDN article: The Command Pattern In WPF
Keyvan Nayyeri: How to Add Commands to Custom WPF Control
Ian Griffiths: Avalon Input, Commands, and Handlers
Wikipedia: Command Pattern
MSDN Library: Commanding Overview
MSDN Library: CommandBinding Class
MSDN Library: Input and Commands How-to Topics
MSDN Library: EditingCommands Class
MSDN Library: MediaCommands Class
MSDN Library: ApplicationCommands Class
MSDN Library: NavigationCommands Class
MSDN Library: ComponentCommands Class
Also buried in the WPF SDK samples, there's a nice sample on RichTextBox editing which I've extended. You can find it here: RichTextEditor.zip

In the September 2008 edition of the MSDN magazine, Brian Noyes has a excellent article about the RoutedCommand/RoutedEvents!!!
Here is the link:
http://msdn.microsoft.com/en-us/magazine/cc785480.aspx

The thing about XAML is that it is fine for 'simple' programs, but sadly, it doesn't work well when you want to do things like share functions. Say you have several classes and UI's all of which had commands that were never disabled, you'd have to write a 'CanAlwaysExecute' method for each Window or UserControl! That's just not very DRY.
Having read several blogs and through trying several things, I've made the choice to make XAML purely about looks, styles, animation and triggers. All my hooking up of event handlers and commanding is now down in the code-behind. :)
Another gotcha by the way is Input binding, in order for them to be caught, focus must be on the object that contains the Input bindings. For example, to have a short cut you can use at any time (say, F1 to open help), that input binding must be set on the Window object, since that always has focus when your app is Active. Using the code method should make that easier, even when you start using UserControls which might want to add input bindings to their parent Window.

Related

How to use MainWindow as ShellViewModel View?

I understand that by default CM will look for ShellView in Views folder to use as ShellViewModel View but I want to use the MainWindow instead... can this be done and how?
How it Works
CM uses a set of View/ViewModel Naming Conventions, generally speaking, if you have a ViewModel named FooViewModel CM will attempt to locate a type with a similar name of FooView or FooPage.
What if you really want "MainWindow" and "ShellViewModel"?
If you just wanted to use an existing "MainWindow" with an existing 'root viewmodel' then consider subclassing Bootstrapper<TRootModel> and override OnStartUp. This is a prescribed method, but can seem daunting.
(I have not tested this code.)
protected override void OnStartup(object sender, StartupEventArgs e)
{
var rootModel = IoC.Get<TRootModel>();
var rootView = new MainWindow();
ViewModelBinder.Bind(rootModel, rootView, this);
rootView.Show();
}
The above method, of course, would only apply to the initial view for the root view model shown during start-up. Future attempts to display a view for ShellViewModel may work, or they may result in errors, I am not certain.
Extending Conventions
There are a few ways to customize the convention itself. The most flexible and direct method is to intercept/hook Caliburn.Micro.ViewLocator.LocateForModelType, this allows you to modify the behavior/strategy applied during view location.
private static void CustomViewLocatorStrategy()
{
// store original implementation so we can fall back to it as necessary
var originalLocatorStrategy = Caliburn.Micro.ViewLocator.LocateForModelType;
// intercept ViewLocator.LocateForModelType requests and apply custom mappings
Caliburn.Micro.ViewLocator.LocateForModelType = (modelType, displayLocation, context) =>
{
// implement your custom logic
if (modelType == typeof(ShellViewModel))
{
return new MainWindow();
}
// fall back on original locator
return originalLocatorStrategy(modelType, displayLocation, context);
};
}
The above can be called from inside a Bootstrapper<TRootModel>.Configure override:
protected override void Configure()
{
CustomViewLocatorStrategy();
base.Configure();
}
This method is more likely to play well with CM (in terms of any view caching, namely.) However, it still breaks conventions, and it's still a fair amount of code.
Registering Additional Suffixes?
One thing I want to point out, but have not had a chance to play with, is ViewLocator.RegisterViewSuffix implementation. I believe if you executed ViewLocator.RegisterViewSuffix(#"Window") then you could rely on CM to map MainViewModel to MainWindow.
This would allow for more expressive suffixes (such as Window, Dialog, Form, or others you may want to use.) Personally I dislike the use of 'View' as a suffix, I believe it's too generic (after all, they are all Views.)
Caliburn.Micro doesn't look for ShellView by default, this is how things work. Let's say you have a bootstrapper defined like this:
class MyBootsrtapper : Bootstrapper<MyViewModel> { }
Then CM (Caliburn.Micro) will look for a view named MyView. So yes you can use MainWindow instead as long as your view model name is MainWindowViewModel.
I have answered the other question you have asked and it seems you don't fully comprehend CM so i really really advise you to Start Here and you can always check the projects Documentation on codeplex because it contains all updated information and documentation.
Edit:
Caliburn.Micro uses a simple naming convention to locate Views for
ViewModels. Essentially, it takes the FullName and removes “Model”
from it. So, given MyApp.ViewModels.MyViewModel, it would look for
MyApp.Views.MyView.
Taken from official documentation here.

WinForm text box: MenuStrip keyboard shortcuts overriding OS-level copy/paste

Update: I've figured out the source of the issue, now trying to figure out the best fix
I've got a Form with a customized MenuStrip, with all sorts of bells and whistles. Of note here, is that many of my MenuStrip items have keyboard shortcuts - namely ones for Cut/Copy/Paste.
It appears that the presence of this MenuStrip is overriding (and therefore cancelling) the default Cut/Copy/Paste keyboard shortcut behaviors for my text boxes (and other controls).
All of them.
.
I can't really say I have a reason for the MenuStrip Cut/Copy/Paste options, besides the fact that I would expect to see them there. That's how Office type programs operate, and it's something the user (myself included) would expect.
I could remove the Cut/Copy/Paste options from the MenuStrip, but that would be admitting defeat! So how do I keep my overly engineered MenuStrip from forcing me to implement custom code for EVERY control that's Cut/Copy/Paste friendly?
.
** Original Post: **I've got a TextBox control in a toolbar which is to be used throughout my program. Imagine my surprise when native OS-level Copy/Paste events were not supported by default.
Sure, I could code something manually, but when I right-click on the control, Cut/Copy/Paste are already built in. How can I leverage this existing functionality?
I figure adding a KeyDown event with Ctrl+C, P, and X would be about the maximum I should have to code. For those events I just call a built-in method or something. That, or find a setting that enables native cut/copy/paste.
What am I overlooking/missing?
Testing it out native copy and paste does work on a TextBox control unless you are overridding the ContextMenu or ContextMenuStrip, in that case you will need to use the ClipBoard Class to implement it yourself.
In looking at it further this MSDN Forum article discusses sending the Commands to the Native Textbox Control using the SendMessage Method. This is implemented in a Custom TextBox which sounds like what you are doing.
Small excerpt see article for further implementation:
protected void itemCut_Click(object sender, EventArgs e)
{
SendMessage(this.Handle, TextBoxMessages.WM_CUT, 0, 0);
}
public static class TextBoxMessages
{
public const int EM_UNDO = 0x00C7;
public const int WM_CUT = 0x0300;
public const int WM_COPY = 0x0301;
public const int WM_PASTE = 0x0302;
}
Easy Solution: Use the SendKeys.Send() call within the Click event.
SendKeys.Send("^X");
I'm doing something a little more complicated, so here's the details:
I'm making several Forms, which all share some custom controls: MenuStrip, StatusStrip, and a few other custom controls. I've decided to have the Forms all inherit from the same base class, to allow common implementation of lots of stuff.
public partial class CommonFormBase : Form
{
private void Initialize()
{
//Bind click event for custom MenuStrip to events in the local Form
CommonMenuStrip.Edit_Cut.Click += new EventHandler(Edit_Cut_Click);
CommonMenuStrip.Edit_Copy.Click += new EventHandler(Edit_Copy_Click);
CommonMenuStrip.Edit_Paste.Click += new EventHandler(Edit_Paste_Click);
}
//Implement Click events for the MenuStrip by calling local methods
internal void Edit_Cut_Click(object sender, EventArgs e) { Cut(); }
internal void Edit_Copy_Click(object sender, EventArgs e) { Copy(); }
internal void Edit_Paste_Click(object sender, EventArgs e) { Paste(); }
//Generic implementation of common commands for the CommonFormBase
public virtual void Cut() { SendKeys.Send("^X"); }
public virtual void Copy() { SendKeys.Send("^C"); }
public virtual void Paste() { SendKeys.Send("^V"); }
}
I implemented the MenuStrip's click event at the Form level (not the MenuStrip level), but in that event I only call a generic method, which does all the code. In this example it's overkill, but I have other MenuStrip commands that will change in functionality for different child Forms, so I figured having them all work the same would be easier.
Anyway, this works almost perfectly! It seems to push the shortcut-key-activated MenuStrip_Click event to the underlying control (or maybe the Form?), which then implements default shortcut key events.
The only thing it does wrong is it only triggers ONCE when you do Ctrl + V + V + V... or hold Ctrl+V. Still, that's just a matter of the trigger not recognizing multiple events, not an issue with the solution itself.

WPF - Custom Control + ICommand (How do I Implement this)?

Basically, I have a custom control FooControl.
public class FooControl : ItemsControl
{
//Code
}
I need to add some event handling, but rather than using a RoutedEvent I'd much more prefer to use Commanding instead. I'm not really sure how to go about doing this though. If I want it so that when Bar1Property (DependencyProperty) changes it raises the Execute associated execute property. I looked at the ButtonBase code through .NET Reflector and wow, that looks overly complicated. Is adding a command this complex?? Obviously I'd also have to make it so that my control enables/disables certain parts of itself depending on if the CanExecuteChanged is altered or not. But I guess that's another portion.
Here is my OnBar1Changed function so far...
private static void OnBar1Changed(DependencyObject obj, DependencyPropertyChangedEventArgs e)
{
FooControl element = (FooControl)obj;
//What to do here?
}
It sounds like by the way you are asking your question, you want to support commanding in your custom control (like for example Button supports). To do this you I recommend looking at how ICommandSource is implemented. Microsoft gives a great walk through on how you can implement it yourself:
http://msdn.microsoft.com/en-us/library/ms748978.aspx
At the simplest level, all you really need is something like:
FooControl element = obj as FooControl;
if (element == null) return;
if (element.MyCommand != null && element.CanExecute(this.CommandParameter)
{
element.MyCommand.Execute(this.CommandParameter);
}
You'd have to create Dependency Properties for both the Command and the CommandParameter, as well.
Hope that helps,

Getting non-UI objects to respond to WPF command bindings

I have a ViewModel class which i want to respond to the built in Refresh command whic is fired from a button but i'm not sure how to declare the CommandTarget.
Briefly, my code is as below
The ViewModel constructor and CanExecute and Executed event handlers -
public ViewModel()
{
CommandBinding binding = new CommandBinding(NavigationCommands.Refresh, CommandHandler);
binding.CanExecute += new CanExecuteRoutedEventHandler(binding_CanExecute);
binding.Executed += new ExecutedRoutedEventHandler(binding_Executed);
CommandManager.RegisterClassCommandBinding(typeof(ViewModel), binding);
}
void binding_Executed(object sender, ExecutedRoutedEventArgs e)
{
Debug.Print("Refreshing...");
}
void binding_CanExecute(object sender, CanExecuteRoutedEventArgs e)
{
e.CanExecute = true;
}
The markup is -
<Button Command="Refresh">refresh</Button>
Now, I've tried setting the CommandTarget on this button to {Binding Source={StaticResource ViewModel}} but i get a runtime saying Cannot convert the value in attribute 'CommandTarget' to object of type 'System.Windows.IInputElement'.
I'm new to commands so it's entirely possible I'm all kinds of wrong here. Anyhelp would be appreciated.
RoutedCommands and MVVM do not mix. RoutedCommands are tied to the visual tree and to rely on WPF's CommandBindings collection. You should implement your own ICommand classes that work with the MVVM pattern. Take a look at Prism's implementations for starters.
In my own MVVM projects, I have a couple of command implementations:
DelegateCommand. Calls provided delegates to determine whether the command can execute, and to execute the command.
ActiveAwareCommand. Works in conjunction with an interface (IActiveAware) and sends command executions to the currently active item. Multiple active aware implementations register themselves with the command, and the command automatically routes CanExecute / Execute calls to the currently active item.

Is there a way to bind the results of a public method in xaml.cs to a control in xaml?

Let's take a very simple example:
In my window1.xaml, i have a label
control named 'lblProduct'.
In my window1.xaml.cs, i have a
public method called
CalculateProduct(Int Var1, Int
Var2). CalculateProduct will, as
you may have guessed, calculate the
product of the variables passed in.
I'd like to simply bind the results of 'CalculateProduct' to my label. My actual use case is a little more complicated than this. However, if I could get this up and running not only would I be quite happy, I'd be able to figure out the rest.
I've seen interesting examples using the ObjectDataProvider to bind to a static method of a new class. While this is well and good, I don't feel the need to create a new class when I've already instantiated the one for my window. In addition, there may be other global variables that I'd like to take advantage of in my Window1 class.
Thanks for your time and help,
Abel.
It's quick and dirty but I'd probably just have CalculateProduct set a property with its result and databind to the property.
Yes, there is a way. It's not pretty. You have to add an xmlns:Commands attribute to your window1.xaml tag. I ended up bastardizing some code I found in this Code Project article.
Is the product that you want to display in the label something that's generated on load, or from another control event?
I'm not sure this will help you, but I ran into something similar where I was trying to generate XAML dynamically with XSLT. My solution worked, kind of...well, not really for what I was trying to do. But maybe it will help you.
As I said, you have to declare the xmlns in your page tag, like so:
<Page x:Class="WpfBrowserApplication1.Page1"
blah blah blah
xmlns:Commands="clr-namespace:WpfBrowserApplication1">
Then, define a static class in your application with the same namespace, pretty much the same as the example in the Code Project article, with handlers for a RoutedUICommand:
namespace WpfBrowserApplication1
{
public static class CommandHandlers
{
private static System.Windows.Input.RoutedUICommand _submitCommand;
static CommandHandlers()
{
_submitCommand = new System.Windows.Input.RoutedUICommand("Submit", "SubmitCommand", typeof(CommandHandlers));
}
public static void BindCommandsToPage(System.Windows.Controls.Page caller)
{
caller.CommandBindings.Add(new System.Windows.Input.CommandBinding(SubmitCommand, SubmitContact_Executed, SubmitContact_CanExecute));
}
public static System.Windows.Input.RoutedUICommand SubmitCommand
{
get { return _submitCommand; }
}
public static void SubmitContact_Executed(object sender, System.Windows.Input.ExecutedRoutedEventArgs e)
{
...do stuff...
}
public static void SubmitContact_CanExecute(object sender, System.Windows.Input.CanExecuteRoutedEventArgs e)
{
if (e.Source is System.Windows.Controls.Button)
e.CanExecute = true;
else
e.CanExecute = false;
}
}
}
The nasty part is that, so far as I've found, the only way to map things back to Page1.xaml is to cast the sender object and dig through the UI elements of the Page, similar to how you would dig through the DOM on a web page. I had some success with this, but certainly don't pretend to be an expert.
The last thing you have to do is wire up your control in the Page1.xaml.cs. In the XAML, you do it like so:
<Button Name="btnSubmit" Command="Commands:CommandHandlers.SubmitCommand" etc... />
In the code-behind, like so:
private void Page_Loaded(object sender, RoutedEventArgs e)
{
CommandHandlers.BindCommandsToPage(this);
}
I hope that helps, and good luck.
Why you not just set the label value in your CalculateProduct method before you return from the method. Basically way do you need data binding here? It is one way anyhow, since you are binding to a label.
ObjectDataProvider has an ObjectInstance property that you can assign your Window instance to.
aogan: The idea here is to leverage the flexibility of WPF databinding. I could set the entire UI in the code behind, but MS has developed this binding system and i wanted to easily take advantage of it. Also, this was a simple example for a more complicated problem.
To everyone else involved, i've gone with PITAdev's solution. Thanks for the help.

Resources