WPF Command binding in DataTemplate

16,899

Solution 1

The first object that comes in mind to be attached to the command is the Border and since this latter doesn't have a Click event, I'm gonna use MouseLeftButtonDown, and since Commands are used only with Button-base controls (Button, RadioButton, CheckBox, RepeatButton ...) you will be needing EventTriggers, your DataTemplate should look like this:

<DataTemplate>
      <Border BorderThickness="1" BorderBrush="Gold">
            <i:Interaction.Triggers>
                    <i:EventTrigger EventName="MouseLeftButtonDown">
                          <command:EventToCommand  Command="{Binding RelativeSource={RelativeSource AncestorType=Window, Mode=FindAncestor}, Path=DataContext.MouseLeftButtonDown }"/>
                    </i:EventTrigger>
            </i:Interaction.Triggers>
            <StackPanel Orientation="Horizontal">
                 <TextBlock Text="{Binding Path=Name}" />
                 <TextBlock Text="{Binding Path=Price}" />
            </StackPanel>
      </Border>
 </DataTemplate>

Since your ItemsControl's source is bound to Products then, the DataTemplate's DataContext will be a Product object, to avoid that you should bind the command's source to the Window ancestor which its DataContext is bound to the ViewModel that contains the RelayCommand :

public class MainViewModel : ViewModelBase
{


    public class Product
    {
        public string Name { get; set; }
        public string Price { get; set; }
    } 

    public List<Product> Products
    {
        get
        {
            return new List<Product>()
                   {
                       new Product(){Name = "Product1",Price = "Price1"},
                       new Product(){Name = "Product2",Price = "Price2"}
                   };
        }
    }

    public RelayCommand MouseLeftButtonDown { get; set; }

    public MainViewModel()
    {
          MouseLeftButtonDown = new RelayCommand(()=> MessageBox.Show("Message","Hi"));
    }
}

PS : The command:EventToCommand is from MVVM-Light ,if you are not using MVVM-Light you can just go using this instead :

<i:Interaction.Triggers>
       <i:EventTrigger EventName="MouseLeftButtonDown">
              <i:InvokeCommandAction Command="{Binding RelativeSource={RelativeSource AncestorType=Window, Mode=FindAncestor}, Path=DataContext.MouseLeftButtonDown }" >            
              </i:InvokeCommandAction>
       </i:EventTrigger>
</i:Interaction.Triggers>

This should perfectly work, hope I explained well.

Solution 2

You may try something like this:

<DataTemplate>
       <Border BorderThickness="1" BorderBrush="Gold">
        <Border.InputBindings>
          <MouseBinding MouseAction="LeftClick" Command="{Binding DataContext.SomeCommand, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ItemsControl}}}"/>
        </Border.InputBindings>

         <StackPanel Orientation="Horizontal">
             <TextBlock Text="{Binding Path=Name}" />
             <TextBlock Text="{Binding Path=Price}" />
          </StackPanel>
          </Border>
 </DataTemplate>
Share:
16,899
Stacked
Author by

Stacked

A passionate software developer (.NET) MCSD: App Builder MCSA: Web Applications LinkedIn WordPress Blog

Updated on June 08, 2022

Comments

  • Stacked
    Stacked almost 2 years

    I'm using ItemsControl to hold my collection. The ItemsPanel is a Canvas, the ItemTemplate is a block of Border>StackPanel>TextBlocks I want to bind a command in the DataTemplate to catch the click on a block (item of my collection)

    Code:

       <Grid Grid.Row="1" Grid.Column="1" >
            <ItemsControl ItemsSource="{Binding Products}">
                <ItemsControl.ItemsPanel>
                    <ItemsPanelTemplate>
                        <helpers:DragCanvas 
                            HorizontalAlignment="Stretch" 
                            VerticalAlignment="Stretch"
                            AllowDragging="True"
                            AllowDragOutOfView="False" />
                    </ItemsPanelTemplate>
                </ItemsControl.ItemsPanel>
                <ItemsControl.ItemTemplate>
                    <DataTemplate>
                        <!-- The border and its content is what I see
                        on my canvas, I want to bind a command here (on click do something) -->
                        <Border BorderThickness="1" BorderBrush="Gold">
                            <StackPanel Orientation="Horizontal">
                                <TextBlock Text="{Binding Path=Name}" />
                                <TextBlock Text="{Binding Path=Price}" />
                            </StackPanel>
                        </Border>
                    </DataTemplate>
                </ItemsControl.ItemTemplate>    
            </ItemsControl>
        </Grid>
    
  • AymenDaoudi
    AymenDaoudi almost 10 years
    +1 for the input binding, -1 for the Command="{Binding SomeCommand}", the DataContext of DataTemplate is set to Product (Model) not to the ViewModel