开发者

Command binding in multiwindow WPF app

My application can have multiple designer windows. Each window constitutes of several user controls which communicates dynamically with the help of RelayCommands. I created the following class as the backbone of the commanding infrastructure.

public static class Commands
{
    public static readonly RoutedCommand EntityEditRequest = new RoutedCommand();
    public static  RelayCommand EntityEditorChangeRequest;
    public static RelayCommand XMLUpdateRequest;
    public static RelayCommand SaveRequest;   
}

Each viewmodel for the user controls will do something like this in the constructor

 public XMLEditorViewModel()
 {
        Commands.Commands.SaveRequest = new RelayCommand(Save_Executed);
        Commands.Commands.XMLUpdateRequest = new RelayCommand(UpdateXML); 
 }

However, I completely missed the point that the application can have multiple windows. When each window is opened the static Commands are set for that particular window.

Example:

Window A is opened-the constructors for the usercontrols set the RelayCommands and all is well.

Window B opened-the constructors for the usercontrols set the RelayCommands. Window A's command binding is lost!

So when I change the tab to Window A(the windows are tabbed) no commands are working.

I need some idea so that when I change the tab the active window always sets the commands. I can try to put the commanding in tab_selection_changed event, but somehow it is looking bad to me. Is there a proper way to do this? Any help is much appreciated.

Edit:

The question proved a bit confusing among the readers. I am not trying to make multiple subscribers for a command. At any given point only one window is active. This window consists several user controls-some of them loaded dynamically with the help of commands; but each command is handled by a single view model class-so no multi subscribers. My problem is the application can load multiple windows in tabs-only one window is active at any given point-but the user can do to a different tab and make another window active. As the view model constructor assigns the static RelayCommands, when each new window is loaded the static comm开发者_StackOverflowand is set to a new binding.

Window A opened-window A view model constructor sets the static command bind to its object command handler. Window A is active. Commanding is fine.

Window B loaded-window B view model constructor sets the static command bind to its object command handler. Window B is active. Commanding is fine.

Now, User select the Window A tab to set the Window A as active. Commanding wont work. Of course it wont as the Command is bind to Window B command handler.

Theoretically static commands can handle the scenario as at any given point there will be only one active window. But how??


The global command should be a CompositeCommand or similar approach (CompositeCommand is from Prism). This will allow multiple children to register with the command.

  public static CompositeCommand SaveCommand = new CompositeCommand();

The command can then be accessed across the ViewModels or where applicable like so...

  SaveCommand = new DelegateCommand<object>(Save, CanExecuteSave);
  GlobalCommands.SaveCommand.RegisterCommand(SaveCommand);

You can then leverage the IActiveAware interface to define which Window is the active Window and act on the command accordingly.

There is also an MSDN posting on creating globally available commands. Don't forget to unregister the command to avoid a memory leak.


Any reason why have you decided to put it into static class?

class XMLEditorViewModel
{
    public ICommand SaveRequest { get; private set; }

    public XMLEditorViewModel()
    {
        SaveRequest = new RelayCommand(Save_Executed)?
    }
}


Commands that are not view specific can be defined on static classes.

Commands that are view specific should either be defined on view-model, passed as DataContext to view, enabling separate implementation for different views with different view models, or at least have the views pass a CommandParameter that can be used to either identify them (e.g. reference to the view) or their DataContext.

If the commands are static, register them once only, perhaps on a singleton used by view models.


create a globally available command, create an instance of the DelegateCommand or the CompositeCommand and expose it through a static class.

public static class GlobalCommands { public static CompositeCommand MyCompositeCommand = new CompositeCommand(); } In your module, associate child commands to the globally available command.

GlobalCommands.MyCompositeCommand.RegisterCommand(command1); GlobalCommands.MyCompositeCommand.RegisterCommand(command2); To increase the testability of your code, you can use a proxy class to access the globally available commands and mock that proxy class in your tests.

The following code example shows how to bind a button to the command in WPF.

Execute My Composite Command

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜