How to bind a RelayCommand(MVVM) to a RoutedCommand? (CommandBinding)

放肆的年华 提交于 2019-12-11 08:15:10

问题


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:


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


来源:https://stackoverflow.com/questions/25809088/how-to-bind-a-relaycommandmvvm-to-a-routedcommand-commandbinding

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!