![]() |
Platforms, Frameworks & Libraries »
Windows Presentation Foundation »
General
Advanced
License: The Code Project Open License (CPOL)
WPF Commands Return ValueBy Kobi UdiAllows WPF commands to interact back with the command sources |
C#, Windows, .NET 2.0, .NET 3.0, .NET 3.5, XAML, WPF, Architect, Dev
|
|
Advanced Search Add to IE Search |
|
|
|
||||||||||||||||

This issue suggests an implementation of extending WPF routed commands in a way that enables them interaction back with the command sources for synchronization purposes.
At first glance, WPF commands looked like… sort of events, that's what I thought, till I read a bit more about them. WPF commands are a great way to separate the command logic from its trigger sources (command sources, the ones that invoke the commands) and customize different logic on various targets. Routed command bubbles and tunnels through the element tree allowing each element to define its ability to execute the command and execute it when all the proper conditions add up.
One of its big strengths are a set of ready to use commands which have a built in support as part of some of the controls for performing specific command functionality corresponding to the element it is occurring on.
While examining and using WPF commands, along with its benefits, its deficiencies started to come out.
One main shortage and the topic of our article is the inability of the command source to get updates from the command itself, it just wasn't handled by Microsoft.
Let's use an example to clear things up. Take a simple player application for example, which allows the user to play a media file by either clicking a play/pause toggle button or selecting a play/pause entry from a menu bar. Since both scenarios run the same functionality, both controls hook up the same command which get handled in the same target, the player form in this case, which is also the visual parent of both controls. The first scenario of clicking the toggle button works like a charm. But in the second scenario of clicking the menu entry "Play/Pause" is a whole other story. While the media file plays the toggle button stays apathetic to the new condition. Not only that, WPF commands suggest no support for such a scenario. It doesn't allow any kind of back door to the command sources. This article addresses the aforementioned WPF commands deficiency and suggests an appropriate solution for most uses.
There are several ways of solving/bypassing the problem. Let's review two main solutions which solve our problem while maintaining a loosely coupled UI.
A known and spoken solution proposes sending a custom object as the command property which comprises a value for the command sources which actuated the command to use as a return value. After each concrete command execution, all concrete command sources compel updating. Further information on that approach can be found at Extending WPF Commands by Patrick Klug.
Just to point out the main pros and cons for comparison:
CanExecute method invocations (one for its official part in WPF commanding mechanism and the other for the spoken solution) This solution suggests a custom command that leverages the existing one in a way that enables a return value per command, meaning that each source control attached to a concrete custom command can be notified on changes and access the return value to refresh itself.
static, you can have only one return value per command. Can be overcome by using a custom object (maybe some kind of a collection) as the return value. But this is an infrequent scenario and won't be addressed on this issue. Since originally I used the propose design as a solution to a player we developed at work, I decided to exemplify it on a player common scenario, playing a media file (a virtual one :-))from either a play/pause toggle button or a play/pause menu entry. As opposed to the toggle button which changes its state correspondingly playing or paused, the menu stays as is regardless of the media file state.


Actually I use it on numerous and disparate scenarios using all kinds of command source controls combination involving two or more of them.
Like almost everything in life, this solution comprises three parts:
And you're ready to go. Yes, it's that simple!!!
The engine that runs this solution is the CustomCommand class which inherits the RoutedCommand WPF class.
public class CustomCommand : RoutedCommand
{
public delegate void ReturnValueChangedHandler(object sender, EventArgs e);
//an event for command sources on return value change
public event ReturnValueChangedHandler ReturnValueChanged;
private object returnValue;
public CustomCommand(string Name, Type OnerType): base(Name, OnerType)
{
}
//the return value
public object ReturnValue
{
get
{
return returnValue;
}
set
{
returnValue = value;
ReturnValueChanged(this, new EventArgs());
}
}
}
The idea is to expand the command so it would carry a return value along with it aka ReturnValue and a ReturnValueChanged event to notify to whoever wants to listen, in fact to the command sources that rely on it. As you can see, that event raises on each ReturnValue set.
Since in our example, the toggle button is the only command source that needs the command return value, we'll see just the following code snippet:
//listening to ReturnValueChanged event and setting the
//toggle button state correspondingly
((CustomCommand) Commands.Commands.ToggleCommand).ReturnValueChanged += (sender, e) =>
{
toggleBtn.IsChecked =
(bool)((CustomCommand)Commands.Commands.ToggleCommand).ReturnValue;
};
The only thing left is setting the appropriate return value on command execution.
private void CommandBinding_Executed(object sender, ExecutedRoutedEventArgs e)
{
//setting the return value
//in the real world we probably won't have to hold a state flag
//"isPlay" we'll figure that out as part of the alg
if (e.Parameter == null)
//the command came from menu
((CustomCommand)e.Command).ReturnValue = isPlay = !isPlay;
else
//the command came from toggle button
((CustomCommand) e.Command).ReturnValue = isPlay = (bool)e.Parameter;
// TODO: insert command logic here
e.Handled = true;
}
As you can see, after only three simple steps you have the whole commanding return value mechanism ready to go.
Attached is a demo app for clarifications (VS 2008 project).
| You must Sign In to use this message board. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
General
News
Question
Answer
Joke
Rant
Admin
|
PermaLink |
Privacy |
Terms of Use
Last Updated: 7 Aug 2008 Editor: Deeksha Shenoy |
Copyright 2008 by Kobi Udi Everything else Copyright © CodeProject, 1999-2009 Web18 | Advertise on the Code Project |