WPF tuto’s – Forward commands

With the MVVM pattern, it’s quite difficult to handle context menu commands because context menu are not in the same tree view and we generally don’t want to bind on business commands that are in menu item view models. It’s the same problem for tool windows and so on, because we want to reuse the existing commands.

I describe below the “Forward” command pattern used in CBR. Note that MVVM is implemented via MVVMLight.

First, extend your ViewModelBase to have a ViewModelBaseExtended that will implement a ForwardCommand for all your view models. With also an overrideable method GetForwardCommandContext

CommandContext is an helper class that will contain the command to execute as string and an additional command parameter

#region ----------------COMMANDS----------------

private ICommand forwardCommand;
 public ICommand ForwardCommand
 {
 get
 {
    if (forwardCommand == null)
            forwardCommand = new RelayCommand<string>(
  delegate(string param)
  {
     Messenger.Default.Send<CommandContext>(GetForwardCommandContext(param),
           ViewModelBaseMessages.ContextCommand );
  },
  delegate(string param)
  {
    return CanForwardCommand(param);
  });
  return forwardCommand;
  }
 }

protected virtual CommandContext GetForwardCommandContext(string param)
 {
 return new CommandContext();
 }

protected virtual bool CanForwardCommand(string param)
 {
 return false;
 }

#endregion
 }

public class CommandContext
 {
 public string CommandName { get; set; }
 public object CommandParameter { get; set; }
 }

ViewModelBaseExtended.cs

Then, in your MainViewModel, register to the same message your command is sending.

Messenger.Default.Register<CommandContext>(this, ViewModelBaseMessages.ContextCommand,
 (CommandContext o) =>
 {
   ExecuteDistantCommand( o );
 } );

 

internal void ExecuteDistantCommand(CommandContext context)
 {
   if (context != null)
   {
     ReflectionHelper.ExecuteICommand( this, context.CommandName, context.CommandParameter );
   }
 }

MainViewModel.cs

ReflectionHelper has got a method to execute a ICommand by reflexion

static public void ExecuteICommand(object commandTarget, string commandName, object commandParameter)
 {
   if (LogHelper.CanDebug())
     LogHelper.Begin("ReflectionHelper.");
 try
 {
   if ( commandTarget != null && !string.IsNullOrEmpty(commandName) )
   {
     //get the target type
     Type mySelf = commandTarget.GetType();

     //get the command as property
     PropertyInfo pInfo = mySelf.GetProperty(commandName);

     //retreive the real value as ICommand
     ICommand com = (ICommand)pInfo.GetValue(commandTarget, null);

    //Execute the command
    com.Execute(commandParameter);
   }
  }
   catch (Exception err)
   {
      LogHelper.Manage("ReflectionHelper.", err);
   }
   finally
   {
     LogHelper.End("ReflectionHelper.");
   } 
 }

ReflectionHelper.cs

Finally, somewhere in your XAML, bind your view element to the ForwardCommand

<MenuItem Command="{Binding ForwardCommand}" CommandParameter="CatalogOpenFileCommand">

Exemple : LibraryView.xaml

In the corresponding ViewModel, override the GetForwardCommandContext to determine the parameter you need – here I retreive the current book to execute the CatalogOpenFileCommand

protected override CommandContext GetForwardCommandContext(string param)
 {
   return new CommandContext()
   {
     CommandName = param,
     CommandParameter = (this.Catalogs.CurrentItem as CatalogViewModel).Data.CatalogFilePath
   };
 }

Exemple : LibraryViewModel.cs

That’s it ! See you in the next tutorial.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

w

Connecting to %s