MVVM从用户控件执行命令

时间:2015-07-06 16:01:56

标签: c# xaml mvvm user-controls

我有一个MVVM应用程序,部分功能是在我的viewmodel中发出命令。绑定到命令的控件恰好位于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。当我使用复选框时,Command执行一次(以初始化Method),然后当我单击复选框时,Method会触发。

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

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

有人可以为我阐明这一点吗?非常感谢...

1 个答案:

答案 0 :(得分:1)

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

我认为您的问题来自Binding内的UserControl。您尝试将CheckBox Command绑定到 DataContext Command属性。相反,您必须使用Command将其绑定到 UserControl ElementName属性:

<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>