在带有用户控件的 Main Window 中使用 RoutedCommand

Using RoutedCommand in Main Window with User Controls

我正在尝试了解路由命令的工作原理,但我遇到了问题。我创建了一个 Main Window,其中包含 Button 和 ItemControl,其中 UserControls 作为其 Item 模板。

<Window>
<Grid>
<ItemsControl
            ItemsSource="{Binding CollectionOfUsers}">
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <uc:UserUserControl
                        Name="{Binding PersonName}"/>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
            <ItemsControl.ItemsPanel>
                <ItemsPanelTemplate>
                    <StackPanel />
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
        </ItemsControl>
<Button
      Command="{x:Static helpers:RoutedCommands.SendChangesCommand}"
      Content="SAVE"/>
</Grid>
</Window>

如果单击 Main Window 中的按钮,我想 运行 来自 ItemsControl 中每个 UserControl 的一些方法。

我已经在静态中创建了 RoutedCommand class:

public static class RoutedCommands
{
    public static readonly RoutedCommand SendChangesCommand = new RoutedCommand(); 
}

并将 UserControl 绑定到 RoutedCommand。

<UserControl.CommandBindings>
    <CommandBinding Command="{x:Static helpers:RoutedCommands.SendChangesCommand}"
                    Executed="CommandBinding_Executed"/>

代码隐藏中的方法:

private void CommandBinding_Executed(object sender, ExecutedRoutedEventArgs e)
{
      // Do something
}

以为当我单击按钮时它会在每个用户控件对象上触发方法,但遗憾的是这段代码不起作用 - 按钮被禁用。我错过了什么?

您 can/should 将 ItemsControl 的 ItemsSource 作为按钮的 CommandParameter 发送,然后对这些项目(模型)做任何您想做的事。通过适当的绑定,您可以在 UserControls(视图)中看到结果。举个例子:

假设这是 RoutedCommands:

public static class RoutedCommands
{
    public static readonly RoutedCommand SendChangesCommand = new RoutedCommand();

    public static void CanExecuteSendChangesCommand(object sender, CanExecuteRoutedEventArgs e)
    {
        e.CanExecute = true;
    }

    public static void ExecutedSendChangesCommand(object sender, ExecutedRoutedEventArgs e)
    {
       // Use  e.Parameter;
    }
}

并将命令添加到您的应用程序中的CommandBindings,例如:

    public MainWindow()
    {
        InitializeComponent();
        CommandBindings.Add(new CommandBinding(RoutedCommands.SendChangesCommand,                       RoutedCommands.ExecutedSendChangesCommand,RoutedCommands.CanExecuteSendChangesCommand));
    }

您可以像这样绑定 Command 参数:

<DockPanel>
    <Button DockPanel.Dock="Top" Content="Click Me" 
            Command="{x:Static local:RoutedCommands.SendChangesCommand}"
            CommandParameter="{Binding ElementName=ic, Path=ItemsSource}"/>
    <ItemsControl Name="ic" ItemsSource="{Binding CollectionOfUsers}">
        //...
    </ItemsControl>
</DockPanel>

Thought It will fire method on every User Control object when I click the button, but sadly this code doesn't work - button is disabled. What am I missing?

A RoutedCommand 从目标元素搜索可视树,即调用命令的元素,在本例中是您的 Button, 以及在其 CommandBindings 集合中具有匹配 CommandBinding 对象的元素,然后为该特定 CommandBinding.

执行 Execute 委托

这里的问题是 ItemsControl 中的 UserControl 元素不是 Button 的可视父元素,因此永远不会调用该命令。

如果将 CommandBinding 移动到父级 Grid,将启用 Button

<Grid>
    <Grid.CommandBindings>
        <CommandBinding Command="{x:Static local:RoutedCommands.SendChangesCommand}"
            Executed="CommandBinding_Executed"/>
    </Grid.CommandBindings>
    <ItemsControl
    ...

如果您真的想在单击 Button 时对 UserControls 执行某些操作,则使用 RoutedCommand 不是执行此操作的方法。

相反,您应该查看 MVVM design pattern and how to implement your custom ICommand or use a common implementation from any of the MVVM libraries out there. This is another story though but please refer to the following blog post for a brief introduction: https://blog.magnusmontin.net/2013/06/30/handling-events-in-an-mvvm-wpf-application/

MVVM 是 建议在构建基于 XAML 的应用程序时使用的设计模式,所有严肃的 WPF 开发人员都应该学习它。