5,443,978 members and growing! (21,329 online)
Email Password   helpLost your password?
Platforms, Frameworks & Libraries » Windows Presentation Foundation » General     Advanced License: The Code Project Open License (CPOL)

WPF Commands Return Value

By Kobi Udi

Allows WPF commands to interact back with the command sources
C# (C# 1.0, C# 2.0, C# 3.0, C#), Windows, .NET (.NET, .NET 2.0, .NET 3.5, .NET 3.0), XAML, WPF, Architect, Dev

Posted: 7 Aug 2008
Updated: 7 Aug 2008
Views: 1,572
Bookmarked: 10 times
Announcements
Want a new Job?



Search    
Advanced Search
Sitemap
4 votes for this Article.
Popularity: 2.49 Rating: 4.14 out of 5
0 votes, 0.0%
1
0 votes, 0.0%
2
1 vote, 25.0%
3
1 vote, 25.0%
4
2 votes, 50.0%
5
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
main_play.pngmain_pause.png

Introduction

This issue suggests an implementation of extending WPF routed commands in a way that enables them back interaction with the command sources for synchronization purposes.

Background

At 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 problem

One 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:

  • Solve the problem.
  • Keep the opportunity of using WPF supported commands.

Cons:

  • Force customization of each and every single control that functions as a command source.
  • Cause superfluous CanExecute method invocations (one for its official part in WPF commanding mechanism and the other for the spoken solution).

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:

  • Solve the problem.
  • Do not require custom controls.

Cons:

  • Eliminate the ability to use WPF supported command.
  • Since commands are 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 address on this issue.

The Solution

Since 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.

main_play_mouse.pngmain_pause_mouse.pngmain_menu_mouse.png

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:

  1. Creating the custom command.
  2. Make sure all command source controls give ear to return value changes.
  3. Applying the return value to the command on command handling.

And you're ready to go. Yes, it's that simple!!!

Creating the custom command:

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 whom ever want to listen, in fact to the command sources that relies on it. As you can see that event raises on each ReturnValue set.

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;
        }

Conclusion

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 (VS2008 project).

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Kobi Udi



Occupation: Software Developer
Company: Elbit Systems
Location: Israel Israel

Other popular Windows Presentation Foundation articles:

Article Top
Sign Up to vote for this article
You must Sign In to use this message board.
FAQ FAQ Noise ToleranceSearch Search Messages 
 Layout  Per page   
 Msgs 1 to 4 of 4 (Total in Forum: 4) (Refresh)FirstPrevNext
Subject  Author Date 
QuestionThe project does not load in VS2005membertal_segal21:24 11 Aug '08  
AnswerRe: The project does not load in VS2005memberKobi Udi21:33 12 Aug '08  
GeneralGood idea, but...membermbelli5:30 8 Aug '08  
GeneralRe: Good idea, but... [modified]memberKobi Udi11:48 9 Aug '08  

General General    News News    Question Question    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

PermaLink | Privacy | Terms of Use
Last Updated: 7 Aug 2008
Editor:
Copyright 2008 by Kobi Udi
Everything else Copyright © CodeProject, 1999-2008
Web20 | Advertise on the Code Project