【问题标题】:MVVM Execute Command from a User Control来自用户控件的 MVVM 执行命令
【发布时间】:2015-07-06 16:01:56
【问题描述】:

我有一个 MVVM 应用程序,部分功能是在我的视图模型中发出命令。绑定到命令的控件恰好位于 DataGrid 的行中。这是一些 XAML:

<DataGridTemplateColumn Width="25">
    <DataGridTemplateColumn.CellTemplate>
        <DataTemplate>

            <!--<base:DeleteButton  HorizontalAlignment="Center" ToolTip="Delete Polygon"
           Visibility="{Binding Path=CanDeleteFromUI, Mode=OneWay, Converter={StaticResource BooleanToVisibilityConverter}}" 
Command="{Binding Path=DataContext.DeletePolygonCommand, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}" CommandParameter="{Binding}"/>-->

            <CheckBox Template="{StaticResource RemoveXButtonTemplate}" Margin="0,0,3,0" HorizontalAlignment="Center" ToolTip="Delete Polygon" Cursor="Hand" Visibility="{Binding Path=CanDeleteFromUI, Mode=OneWay, Converter={StaticResource BooleanToVisibilityConverter}}"
    Command="{Binding Path=DataContext.DeletePolygonCommand, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}" 
    CommandParameter="{Binding}" >
            </CheckBox>
        </DataTemplate>
    </DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>

注意:由于各种原因,“按钮”实际上是一个复选框。

这在编码时工作得很好。请注意,有一个注释掉的用户控件,我无法正常工作,但“真实”复选框工作正常。

这是用户控件的 XAML:

<UserControl x:Class="Athena.Infrastructure.DeleteButton"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             mc:Ignorable="d" >
    <Grid>
        <CheckBox Command="{Binding Path=Command}" CommandParameter="{Binding Path=CommandParameter}" Cursor="Hand">
            <CheckBox.Template>
                <ControlTemplate>
                    <Border Width="14" Height="14" Background="#00000000" Margin="2,0,2,0">
                    ....
                    ....
                </ControlTemplate>
            </CheckBox.Template>
        </CheckBox>
    </Grid>
</UserControl>

我没有包含控件模板的所有 XAML,因为一切都显示得很好。

下面是代码:

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

    public static readonly DependencyProperty CommandProperty = DependencyProperty.Register("Command", typeof(ICommand), typeof(DeleteButton));
    public ICommand Command
    {
        get { return (ICommand) GetValue(CommandProperty); }
        set{SetValue(CommandProperty, value);}
    }

    public static readonly DependencyProperty CommandParameterProperty = DependencyProperty.Register("CommandParameter", typeof(object), typeof(DeleteButton));
    public object CommandParameter
    {
        get { return (object) GetValue(CommandParameterProperty); }
        set { SetValue(CommandParameterProperty, value); }
    }
}

我没有展示我的 VM 代码,但它包含常用的 3 种方法,Command、CanExecute 和 Method。当我使用复选框时,命令执行一次(以初始化方法),然后当我单击复选框时方法会触发。

当我使用用户控件而不是普通复选框时,我的 VM 中的命令会按预期触发一次。此后,该方法根本不会触发。

使用用户控件而不是本机控件似乎很常见,对吧?我无法弄清楚为什么我的 VM 方法不会使用用户控件触发。

有人可以帮我解释一下吗?非常感谢...

【问题讨论】:

    标签: c# xaml mvvm user-controls


    【解决方案1】:

    在这种情况下,首先要检查的是 Visual Studio 控制台中的绑定错误,它可以帮助您定位错误。

    我认为您的问题来自您的UserControl 中的Binding。您尝试将CheckBoxCommand 绑定到DataContextCommand 属性。相反,您必须使用 ElementName 将其绑定到 UserControlCommand 属性:

    <UserControl x:Class="Athena.Infrastructure.DeleteButton"
                 ...
                 x:Name="deleteButton">
        <Grid>
            <CheckBox Command="{Binding Path=Command, ElementName=deleteButton}"
                      CommandParameter="{Binding Path=CommandParameter, ElementName=deleteButton}"
                      Cursor="Hand">
                ...
            </CheckBox>
        </Grid>
    </UserControl>
    

    RelativeSource:

    <UserControl x:Class="Athena.Infrastructure.DeleteButton"
                 ...
                 xmlns:local="clr-namespace:Athena.Infrastructure">
        <Grid>
            <CheckBox Command="{Binding Path=Command, RelativeSource={RelativeSource AncestorType={x:Type local:DeleteButton}}}"
                      CommandParameter="{Binding Path=CommandParameter, RelativeSource={RelativeSource AncestorType={x:Type local:DeleteButton}}}"
                      Cursor="Hand">
                ...
            </CheckBox>
        </Grid>
    </UserControl>
    

    【讨论】:

    • 这是正确的。我自己更喜欢 x:Name 绑定,相对源绑定是 PITA。
    • @Will 是的,在这种特殊情况下,我会选择 ElementName。我认为这真的取决于情况和代码可读性,因为它们提供完全相同的performance
    • 非常感谢马克斯。上面的第一种方法效果很好。我已经使用 WPF 一年多了,但有时仍然觉得自己像个菜鸟。当我第一次构建这个控件时,我得到了一个错误,即只能对依赖对象的依赖属性进行绑定。这就是我在代码隐藏中创建这些属性的原因。现在我想我可以从代码隐藏中删除这些,因为我在 XAML 中有元素名称。
    猜你喜欢
    • 2012-04-21
    • 2011-02-05
    • 1970-01-01
    • 2015-09-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-02-26
    • 1970-01-01
    相关资源
    最近更新 更多