WPF - 当属性发生变化时无论新值是什么都触发DataTrigger

29

我正在尝试在DataGrid中的单元格数值发生变化时,对单元格执行动画。

DataGrid本身绑定了一个普通的CLR对象ObservableCollection。在这种情况下,我们假设这些对象是具有“FirstName”、“LastName”和“Age”属性的“Person”对象。“Person”类实现了INotifyPropertyChanged接口,并且每个属性的setter中都有适当的onPropertyChanged调用。

这些都很好。在datagrid定义中,我设置了绘制每个单元格的DataTemplate,并附加了一个datatrigger...如下:

<DataGridTemplateColumn Header="FirstName">
    <DataGridTemplateColumn.CellTemplate>
        <DataTemplate>
            <Border Name="templateBorder">
                <TextBlock Name="templateTextBlock" Text="{Binding Path=FirstName}" />
            </Border>
            <DataTemplate.Triggers>
                <DataTrigger Binding="{Binding Path=FirstName}" Value="Richard">
                    <DataTrigger.EnterActions>
                        <BeginStoryboard>
                            <Storyboard AutoReverse="True">
                                <DoubleAnimation Storyboard.TargetName="templateTextBlock" Storyboard.TargetProperty="Opacity" To=".1" Duration="0:0:.5" />
                            </Storyboard>
                        </BeginStoryboard>
                    </DataTrigger.EnterActions>
                </DataTrigger>
            </DataTemplate.Triggers>
        </DataTemplate>
    </DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>

当我更新ObservableCollection中的对象时(例如更改FirstName值),DataGrid也会被更新。根据上面的示例,如果我将FirstName的值更改为“Richard”,那么动画也会被执行。

我的问题是,无论FirstName的新值是什么,我都需要运行我的动画。我已经搜索了网络,但迄今为止只能找到针对已知值触发触发器的示例,例如在我的示例中演示的那样,当FirstName为'Richard'时触发触发器。

我的问题是,如何在更新DataGrid中给定行的FirstName属性时触发datatrigger,而不管其值为何?

非常感谢。


为什么不尝试使用Visual State Manager...请参阅此帖子。https://dev59.com/3m_Xa4cB1Zd3GeqPzk95 - stromms
5个回答

48

感谢从这个问题的回答中得到的指针,我发现答案是使用EventTrigger和TargetUpdated RoutedEvent。

<DataTemplate>
    <Border Name="templateBorder">
        <TextBlock Name="templateTextBlock" Text="{Binding Path=FirstName, NotifyOnTargetUpdated=True}" />
    </Border>
    <DataTemplate.Triggers>
        <EventTrigger RoutedEvent="Binding.TargetUpdated">
            <BeginStoryboard>
                <Storyboard AutoReverse="True">
                    <DoubleAnimation Storyboard.TargetName="templateTextBlock" Storyboard.TargetProperty="Opacity" To=".1" Duration="0:0:.5" />
                </Storyboard>
            </BeginStoryboard>
        </EventTrigger>
    </DataTemplate.Triggers>
</DataTemplate>

除了 EventTrigger 之外,唯一需要的就是在设置 TextBlock 的绑定时将“NotifyOnTargetUpdated=True”。

谢谢。


这是正确的做法,它可以工作。我唯一的问题是EventTriggers不支持进入和退出动作。所以你只能启用AutoReverse来反转任何动画。 - Matt Becker
如果您正在使用“用户控件”并在后台交换ViewModel以适应正确的页面,那么这个方法似乎存在问题。 - Samir Banjanovic

3

看起来你需要一个事件触发器,以便在事件发生时执行X操作,而不是使用数据触发器。

虽然我没有亲自尝试过,但应该可以引发你的自定义事件FirstNameChanged,并响应执行触发器动作。


1
  <Storyboard x:Key="MessageStoryBoardEntry" FillBehavior="Stop">

            <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.X)">
                <EasingDoubleKeyFrame KeyTime="0:0:00.30" Value="0"/>
                <EasingDoubleKeyFrame KeyTime="0:0:03" Value="0"/>
                <EasingDoubleKeyFrame KeyTime="0:0:03.20" Value="1500"/>
            </DoubleAnimationUsingKeyFrames>
        </Storyboard>

        <Storyboard x:Key="MessageStoryBoardExit" FillBehavior="Stop">

            <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.X)">
                <EasingDoubleKeyFrame KeyTime="0:0:0.001" Value="1500"/>
            </DoubleAnimationUsingKeyFrames>
        </Storyboard>

0

你能用值转换器来编写一些黑客代码吗?

<DataTrigger Binding="{Binding Path=FirstName, Converter=FirstNameConverter}" Value="MakeItSo">

并且

class FirstNameConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return "MakeItSo";
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
...
    }
}

我猜这取决于WPF是否在每次属性更改时调用转换器,或者它首先评估值。我还没有尝试过,这只是一个想法...


嗨,马克 - 感谢您的建议。我不确定为什么,但这似乎会触发数据网格中每一行的转换器 - 无论该行的值是否已更改。 - Peanut

0

你可以尝试将TextBlock的DataContext设置为FirstName属性,然后使用DataContextChanged事件。

或者你可以使用PropertyChanged事件,并过滤你想要的属性。

无论哪种方式,我认为你都需要使用一个事件。


这只是一直在处理事件。 - user15719632

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接