|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Announcements
Want a new Job?
Chapters
Services
Feature Zones
|
Note: This is an unedited contribution. If this article is inappropriate,
needs attention or copies someone else's work without reference then please
Report This Article
![]()
IntroductionThis issue suggests an implementation of extending WPF routed commands in a way that enables them back interaction with the command sources for synchronization purposes. BackgroundAt first glance WPF commands looked like… sort of events, that what I thought, till I read a bit more about them. WPF commands are great way to separate the command logic from its trigger sources (command sources, the ones that invoke the commands) and customize different logics on various targets. Routed commands 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 adds up. One of its big strengths are a set of ready to use commands which has a build 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 profits its deficiencies started to come out. The problemOne main shortage and the topic of our article is the inability of the command source to get updates from the command itself, it's just wasn’t handle by Microsoft. Let's use an example to clear thing 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 stay apathetic to the new condition. Not only that WPF commands suggest no support for such a scenario it doesn't allows any kind of back way door to the command sources. This article addresses the aforementioned WPF commands lack and suggests an appropriate solution for most uses. Solutions:There are several ways of solving/by passing the problem. Let's review two main solutions which solve our problem while maintaining a loosely coupled UI: 1. Use our own class as a command parameter.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 main pros and cons for comparison: Pros:
Cons:
2. Customize RoutedCommand to embrace a return value.This solution suggest a custom command that leverage 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 notify on changes and access the return value to refresh itself. Pros:
Cons:
The SolutionSince originally I used the propose design as a solution to a player we develop 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 the media file state.
Actually I use it on numerous and disparate scenarios using all kind of command source controls combination involving two or more of them. Like almost everything in life this solution composes of three parts:
And you're ready to go. Yes, it's that simple!!! Creating the custom command:The engine that runs this solution is the 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 Make sure all command source controls give ear to return value changes.Since in our example the toggle button is the only command source who 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; }; Setting the command return value on command handling.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 wont have to hold a state flag "isPlay" we'll figure that out as a 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; } ConclusionAs 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 (VS2008 project).
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||