0

I have an MVVM application and part of the functionality is issuing a command in my viewmodel. The control which is bound to the command happens to reside in the rows of a DataGrid. Here is some XAML for that:

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

Notes: For various reasons, the "button" is actually a checkbox.

This works just fine as coded. Note there is a commented-out user control, which I can't get to work properly, but the "real" checkbox works just fine.

Here is XAML for the user control:

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

I didn't include all the XAML for the control template, as everything displays just fine.

Here is the code-behind:

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

I didn't show my VM code, but it contains the usual 3 methods, Command, CanExecute and Method. When I use the checkbox, the Command executes once (to initialize the Method), and thereafter the Method does fire when I click the checkbox.

When I use the user control instead of the normal checkbox, the Command in my VM fires once as expected. Thereafter, the method does not fire at all.

It seems that this is a common thing, to use a User Control instead of a native control, right? I can't figure out why my VM method will not fire using the User Control.

Can anybody shed some light on this for me? Thanks so much...

RMittelman
  • 319
  • 3
  • 16

1 Answers1

1

The first things to check in this case are the binding errors in the Visual Studio console, it can help you to target the error.

I think your problem comes from the Binding inside your UserControl. You try to bind your CheckBox's Command to the Command property of your DataContext. Instead, you have to bind it to the Command property of your UserControl, using 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>

Or 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>
Max
  • 1,810
  • 3
  • 26
  • 37
  • This is correct. I prefer the x:Name bindings myself, relative source bindings are a PITA. –  Jul 06 '15 at 16:42
  • @Will Yes, in this particular case, I would pick the ElementName. I think it really depends on the situation and the code readability, since they offer quite the same [performance](http://stackoverflow.com/questions/4317097/elementname-vs-relativeresource). – Max Jul 06 '15 at 16:51
  • Thanks so much Max. The first method above worked perfectly. I've been using WPF for over a year, but still feel like a noob sometimes. When I first built this control, I got the error that bindings can only be made to a dependency property of a dependency object. That's why I created those properties in code-behind. Now I guess I can remove those from the code-behind since I have the element name in the XAML. – RMittelman Jul 08 '15 at 12:21