Reputation: 38094
I've created ControlTemplates
:
<Window.Resources>
<ControlTemplate x:Key="imgNo" TargetType="{x:Type Control}">
<Image Source="pack://application:,,,/Images/up.png"/>
</ControlTemplate>
<ControlTemplate x:Key="imgUp" TargetType="{x:Type Control}">
<!--<TextBlock Text="Up"/>-->
<Image Source="pack://application:,,,/Images/up.png"/>
</ControlTemplate>
<ControlTemplate x:Key="imgDown" TargetType="{x:Type Control}">
<Image Source="pack://application:,,,/Images/downArrow.png"/>
</ControlTemplate>
<DataTemplate x:Key="ButtonOneDataTemplate">
<Control x:Name="theControl" Template="{DynamicResource imgNo}" />
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding IsImageChanged}" Value="true">
<Setter TargetName="theControl" Property="Template" Value="{DynamicResource imgUp}" />
</DataTrigger>
<DataTrigger Binding="{Binding IsImageChanged}" Value="false">
<Setter TargetName="theControl" Property="Template" Value="{DynamicResource imgDown}" />
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</WindowResources>
and Button
in DataGrid
which uses above ControlTemplates
:
<DataGrid ItemsSource="{Binding Persons}" Grid.Row="1" AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding IdPerson}">
<DataGridTextColumn.HeaderTemplate>
<DataTemplate>
<Border Background="Violet">
<StackPanel>
<Button ContentTemplate="{StaticResource ButtonOneDataTemplate}"
Command="{Binding DataContext.HelloCommand, RelativeSource=
{RelativeSource AncestorType=Window}}"
CommandParameter="{Binding DataContext.Hello,
RelativeSource={RelativeSource AncestorType=DataGrid}}"/>
</StackPanel>
</Border>
</DataTemplate>
</DataGridTextColumn.HeaderTemplate>
</DataGridTextColumn>
</DataGrid.Columns>
</DataGrid>
My ViewModel
:
public class MainWindowViewModel:ViewModelBase
{
public RelayCommand HelloCommand { get; set; }
public MainWindowViewModel()
{
LoadPersons();
HelloCommand = new RelayCommand(SayHello);
}
int helloCounter = 0;
private void SayHello(object obj)
{
if (helloCounter % 2 == 0)
IsImageChanged = true;
else
IsImageChanged = false;
helloCounter++;
}
private bool isImageChanged=true;
public bool IsImageChanged
{
get { return isImageChanged; }
set { isImageChanged = value;
OnPropertyChanged("IsImageChanged");
}
}
}
What I want is when I click on the button <Button ContentTemplate="{StaticResource ButtonOneDataTemplate}"/>
, then Template
should be replaced to {DynamicResource imgDown}
or {DynamicResource imgUp}
. DataTrigger
depends on IsImageChanged
value.
However, if I click on the Button
, then DataTrigger
is not fired(Controltemplates
such as imgUp
, imgDown
are not changed). How can I achieve this from my ViewModel?
Upvotes: 0
Views: 461
Reputation: 1491
Problem is that DataGrid column is not a part of a visual tree, and because of that it does not inherit DataContext. To be able to use DataTriggers in your ButtonOneDataTemplate you need that button, you applying this template to, has correct DataContext. There is a trick, how to provide DataContext to elements that are not in VisualTree, described here
Applying that solution to your code we'll have the following:
Proxy
public class BindingProxy : Freezable
{
#region Overrides of Freezable
protected override Freezable CreateInstanceCore()
{
return new BindingProxy();
}
#endregion
public object Data
{
get { return (object)GetValue(DataProperty); }
set { SetValue(DataProperty, value); }
}
// Using a DependencyProperty as the backing store for Data. This enables animation, styling, binding, etc...
public static readonly DependencyProperty DataProperty =
DependencyProperty.Register("Data", typeof(object), typeof(BindingProxy), new UIPropertyMetadata(null));
}
Window.Resources
<local:BindingProxy x:Key="proxy" Data="{Binding}" />
<DataTemplate x:Key="ButtonOneDataTemplate">
<Control x:Name="theControl" Template="{DynamicResource imgNo}" Foreground="Orange"/>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=DataContext.IsImageChanged}" Value="True">
<Setter TargetName="theControl" Property="Template" Value="{DynamicResource imgUp}" />
</DataTrigger>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=DataContext.IsImageChanged}" Value="False">
<Setter TargetName="theControl" Property="Template" Value="{DynamicResource imgDown}" />
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
HeaderTemplate
<DataGridTextColumn.HeaderTemplate>
<DataTemplate>
<Border Background="Violet">
<StackPanel>
<Button ContentTemplate="{StaticResource ButtonOneDataTemplate}"
DataContext="{Binding Path=Data, Source={StaticResource proxy}}"
Command="{Binding DataContext.ButtonClick, RelativeSource={RelativeSource AncestorType=Window}}"
CommandParameter="{Binding DataContext, RelativeSource={RelativeSource AncestorType=DataGrid}}"/>
</StackPanel>
</Border>
</DataTemplate>
</DataGridTextColumn.HeaderTemplate>
Upvotes: 2