在XAML中设置命令目标

8

我很难理解RoutedCommand的CommandTarget属性。

基本上,我有一些静态命令,在用户控件(而不是窗口)中实现。我在用户控件中创建一个命令绑定。如果我在用户控件中声明按钮,那么我就能使用我的路由事件。但是,当按钮在用户控件之外时,我就无法使用我的路由事件。我认为命令目标将解决我的问题。

那么,如何为工具栏用户控件的按钮设置命令目标,以便调用容器的Executed和CanExecuted?

micahtan更改后的编辑代码,但我仍然无法执行CanExecute或Execute。

窗口XAML:

<Window x:Class="RoutedCommands.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:RoutedCommands"
    xmlns:toolbar="clr-namespace:RoutedCommands.Toolbar"
    Title="Window1" Height="300" Width="300">
    <StackPanel>
        <local:Container Width="100" Height="25" x:Name="MyContainer" />
        <toolbar:Toolbar Width="100" Height="25" CommandTarget="{Binding MyContainer}" />
    </StackPanel>
</Window>

工具栏 XAML:

<UserControl x:Class="RoutedCommands.Toolbar.Toolbar"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:RoutedCommands"
    x:Name="MyToolbar"
    Height="300" Width="300">
    <Grid>
        <Button Command="{x:Static local:Commands.MyCommand}" Content="Try Me" CommandTarget="{Binding ElementName=MyToolbar, Path=CommandTarget, Mode=OneWay}" />
    </Grid>
</UserControl>

工具栏 CS:

    public partial class Toolbar : UserControl
    {
        public Toolbar()
        {
            InitializeComponent();
        }

        // Using a DependencyProperty as the backing store for CommandTarget.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty CommandTargetProperty =
                DependencyProperty.Register("CommandTarget", typeof(IInputElement), typeof(Toolbar), new UIPropertyMetadata(null));

        public IInputElement CommandTarget
        {
            get { return (IInputElement)GetValue(CommandTargetProperty); }
            set { SetValue(CommandTargetProperty, value); }
        }
    }

容器 XAML:

<UserControl x:Class="RoutedCommands.Container"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:RoutedCommands"
    Height="300" Width="300">
    <UserControl.CommandBindings>
        <CommandBinding Command="{x:Static local:Commands.MyCommand}" CanExecute="CommandBinding_CanExecute" Executed="CommandBinding_Executed" />
    </UserControl.CommandBindings>
    <Grid>
        <Button Command="{x:Static local:Commands.MyCommand}" Content="Click Me" />
    </Grid>
</UserControl>

容器 CS:

public partial class Container : UserControl
{
    public Container()
    {
        InitializeComponent();
    }

    private void CommandBinding_Executed(object sender, ExecutedRoutedEventArgs e)
    {
        Console.WriteLine("My Command Executed");
    }

    private void CommandBinding_CanExecute(object sender, CanExecuteRoutedEventArgs e)
    {
        Console.WriteLine("My Command Can Execute");
        e.CanExecute = true;
    }
}

RoutedCommands:

namespace RoutedCommands
{
    public static class Commands
    {
        public static readonly RoutedUICommand MyCommand = new RoutedUICommand(); 
    }
}

我还没有得到我的问题的答案,但是我正在尝试根据目前所拥有的内容进行工作。 - kevindaub
发布了一些代码,应该可以让你的场景正常工作。 - micahtan
这没有真正帮助。我今晚稍后会再试一些。 - kevindaub
2个回答

8
如果您想使用CommandTargets,我建议在您的自定义UserControl上创建一个CommandTarget DependencyProperty,类似于ButtonBase上定义的方式。
之后,将您的按钮的CommandTarget设置为您的自定义UserControl的CommandTarget。
编辑:代码示例
如果您正在执行MVVM架构,则Rudi的评论是有效的 - RelayCommands或其他形式的包装委托在这种情况下效果很好。根据您的代码示例,似乎您没有使用该方法,因此我的原始评论。
至于代码,您只需要更改ToolBar类。这假定您的MyCommand类继承自RoutedUICommand。这是XAML:
<UserControl
    x:Class="WPFCommandTarget.CustomToolBar"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:WPFCommandTarget"
    x:Name="theControl">
    <Grid>
        <Button
            x:Name="theButton"
            Command="{x:Static local:Commands.MyCommand}"
            CommandTarget="{Binding ElementName=theControl, Path=CommandTarget, Mode=OneWay}"
            Content="Try Me" />
    </Grid>
</UserControl>

以下是代码后端:

使用 System.Windows; 使用 System.Windows.Controls;

namespace WPFCommandTarget
{
    /// <summary>
    /// Interaction logic for CustomToolBar.xaml
    /// </summary>
    public partial class CustomToolBar : UserControl
    {
        public CustomToolBar()
        {
            InitializeComponent();
        }

        public IInputElement CommandTarget
        {
            get { return (IInputElement)GetValue(CommandTargetProperty); }
            set { SetValue(CommandTargetProperty, value); }
        }

        // Using a DependencyProperty as the backing store for CommandTarget.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty CommandTargetProperty =
            DependencyProperty.Register("CommandTarget", typeof(IInputElement), typeof(CustomToolBar), new UIPropertyMetadata(null));
    }
}

请注意,我已经在我的测试项目中更改了一些类名/命名空间。您需要根据自己的需求进行更改。

1

你有没有考虑使用RelayCommand或DelegateCommand!它们可能更适合你的需求?

关于如何使用RelayCommand,可以阅读Josh的this文章作为示例。

Brian Noyes也有一篇优秀的文章here可供参考。


@rudigrobler - 你确定在这种情况下RelayCommands会起作用吗?他的代码示例中Container和ToolBar是兄弟节点,它们之间没有任何引用关系。 - micahtan
Relay/DelegateCommand不是框架的一部分...您可以从Josh的文章中获取它,或者下载Prism! Relay/DelegateCommand根本不依赖于Visual tree...为每个命令指定一个委托并执行即可... - rudigrobler

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接