绑定到ViewModel中的属性的DataTrigger不会在DataGrid的Button中触发

时间:2016-02-29 11:59:39

标签: c# wpf mvvm controltemplate datatrigger

我创建了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>
使用上述Button

DataGrid中的

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>                    

我的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");
           }
    }
}

我想要的是当我点击按钮<Button ContentTemplate="{StaticResource ButtonOneDataTemplate}"/>时,Template应该替换为{DynamicResource imgDown}{DynamicResource imgUp}DataTrigger取决于IsImageChanged值。

但是,如果我点击Button,则DataTrigger未被触发(Controltemplates,例如imgUpimgDown未被更改)。如何从我的ViewModel实现这一目标?

1 个答案:

答案 0 :(得分:2)

问题是DataGrid列不是可视化树的一部分,因此它不会继承DataContext。为了能够在ButtonOneDataTemplate中使用DataTriggers,您需要使用该模板的按钮具有正确的DataContext。有一个技巧,如何为不在VisualTree中的元素提供DataContext,描述为here

将该解决方案应用于您的代码,我们将拥有以下内容:

代理

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>