WPF Command binding in DataTemplate
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>
Stacked
A passionate software developer (.NET) MCSD: App Builder MCSA: Web Applications LinkedIn WordPress Blog
Updated on June 08, 2022Comments
-
Stacked almost 2 years
I'm using
ItemsControl
to hold my collection. TheItemsPanel
is aCanvas
, theItemTemplate
is a block ofBorder
>StackPanel
>TextBlocks
I want to bind a command in theDataTemplate
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 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