How to bind a RelayCommand(MVVM) to a RoutedComman

2019-08-14 05:14发布

I want to create a custom class of a CommandBinding, where a RelayCommand of my ViewModel is executed when the RoutedCommand is executed.

Currently there is only the possibility to create CommandBindings which have Executed methods in the codebehind class. Example:

   <CommandBinding Command="ApplicationCommands.Close" Executed="CloseCommandHandler"
                CanExecute="CanExecuteHandler"/>

This needs the CloseCommandHandler methode in the code behind.

I would want to write the following.

   <CommandBinding RoutedCommand="ApplicationCommands.Close" Command={Binding Path=CloseCommand}/>

The only problem is that i can't find the bubble down and up event of the RoutedCommands. There is no

OnPreviewCommand(object command, object commandParammeter)
OnCommand(object command, object commandParammeter)

Where is the RoutedCommand bubble down and up handled?

1条回答
劫难
2楼-- · 2019-08-14 05:55

I came up with a solutions of my own. Its not the most beautiful, but its working.

I derived from the ContentControl. The new Control has a RoutedCommandBindings property, which contains a list of "sort of" CommandBindings between RoutedCommands and RelayCommands.

It can be used like this.

<CSControls:RoutedCommandBinder>
   <CSControls:RoutedCommandBinder.RoutedCommandBindings>
      <CSControls:RoutedCommandBindingCollection>
         <CSControls:RoutedCommandBinding RoutedCommand="{x:Static ApplicationCommands.New}" Command="{Binding Path=AddInstanceCommand}"/>
      </CSControls:RoutedCommandBindingCollection>
   </CSControls:RoutedCommandBinder.RoutedCommandBindings>
   <CSControls:RoutedCommandBinder.Content>
      <!-- Every RoutedCommand of type ApplicationCommands.New will execute the binded RelayCommand "AddInstanceCommand-->
   </CSControls:RoutedCommandBinder.Content>
</CSControls:RoutedCommandBinder>

Here is the CustomControl code.

public class RoutedCommandBinder : ContentControl
{
    public RoutedCommandBinder()
    {
        this.DataContextChanged += RoutedCommandBinder_DataContextChanged;
    }

    public static readonly DependencyProperty RoutedCommandBindingsProperty = DependencyProperty.Register("RoutedCommandBindings", typeof(RoutedCommandBindingCollection), typeof(RoutedCommandBinder), new PropertyMetadata(new RoutedCommandBindingCollection(), OnRoutedCommandBindingsChanged));
    public RoutedCommandBindingCollection RoutedCommandBindings
    {
        get { return (RoutedCommandBindingCollection)this.GetValue(RoutedCommandBindingsProperty); }
        set { SetValue(RoutedCommandBindingsProperty, value); }
    }

    private static void OnRoutedCommandBindingsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        RoutedCommandBinder binder = (RoutedCommandBinder)d;
        binder.CommandBindings.Clear();
        SetDataContextForCommandBindings(binder);
        if (e.NewValue != null)
        {
            RoutedCommandBindingCollection bindings = (RoutedCommandBindingCollection)e.NewValue;
            foreach (RoutedCommandBinding binding in bindings)
            {
                binder.CommandBindings.Add(new CommandBinding(binding.RoutedCommand, binder.RoutedCommandExecuted, binder.CanExecuteRoutedEventHandler));
            }
        }
    }

    private void RoutedCommandBinder_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
    {
        SetDataContextForCommandBindings(this);
    }

    private static void SetDataContextForCommandBindings(RoutedCommandBinder binder)
    {
        if (binder.DataContext != null && binder.RoutedCommandBindings != null)
        {
            foreach (RoutedCommandBinding binding in binder.RoutedCommandBindings)
            {
                binding.DataContext = binder.DataContext;
            }
        }
    }

    private void RoutedCommandExecuted(object sender, ExecutedRoutedEventArgs e)
    {
        RoutedCommandBinding binding = this.RoutedCommandBindings.FirstOrDefault(t => t.RoutedCommand == e.Command);
        if (binding != null)
        {
            binding.Command.Execute(e.Parameter);
        }
    }

    private void CanExecuteRoutedEventHandler(object sender, CanExecuteRoutedEventArgs e)
    {
        RoutedCommandBinding binding = this.RoutedCommandBindings.FirstOrDefault(t => t.RoutedCommand == e.Command);
        if (binding != null)
        {
            e.CanExecute = binding.Command.CanExecute(e.Parameter);
        }
    }
}

public class RoutedCommandBindingCollection : List<RoutedCommandBinding>
{ 
}

public class RoutedCommandBinding : FrameworkElement
{
    public static readonly DependencyProperty CommandProperty = DependencyProperty.Register("Command", typeof(ICommand), typeof(RoutedCommandBinding), new PropertyMetadata(null));
    public ICommand Command
    {
        get { return (ICommand)this.GetValue(CommandProperty); }
        set { SetValue(CommandProperty, value); }
    }

    public static readonly DependencyProperty RoutedCommandProperty = DependencyProperty.Register("RoutedCommand", typeof(RoutedCommand), typeof(RoutedCommandBinding), new PropertyMetadata(null));
    public RoutedCommand RoutedCommand
    {
        get { return (RoutedCommand)this.GetValue(RoutedCommandProperty); }
        set { SetValue(RoutedCommandProperty, value); }
    }
}
查看更多
登录 后发表回答