更新具有无限可能条件的wpf样式

时间:2011-04-22 00:48:13

标签: wpf styles inotifypropertychanged datatrigger ivalueconverter

我有一个DataGrid,其中的行代表我正在ping的主机和一个名为Lost的列,它代表丢失的ICMP数据包随着时间的推移而增加的值。我把整个INotifyPropertyChanged的东西都弄下了,我看到价值在增加。我想要做的是写一个Style,它会相对于Lost列的值逐步将行的背景颜色从白色变为深红色。

如果可能的话,我想写一个TriggerDataTrigger,其设置值设置为ValueConverter,这将计算所需的颜色,但到目前为止,我写了一个风格,每次丢失的单元格的值发生变化时都会更新,这是不成功的。当我加载新的数据上下文并切换回来时(仅用于测试),我只看到颜色的差异。

这是我尝试过的:

    <Style x:Key="DownStyle" TargetType="{x:Type DataGridRow}">
        <Setter Property="Background" Value="{Binding Converter={StaticResource BackgroundConverter}}" />
    </Style>

我无法看到这与DataTrigger一起工作,因为你必须指定一个值,而且值是无限的(或者我猜的是Int32.MaxValue)。虽然我也尝试为value属性指定ValueConverter,但也不起作用。

不过,我想尽可能避免代码隐藏。

修改 瑞克:我曾经尝试过这样的事情:

    <Style x:Key="DownStyle" TargetType="{x:Type DataGridRow}">
        <Style.Triggers>
            <DataTrigger Binding="{Binding Converter={StaticResource LostColumnValueConverter}}" Value="Somenumber">
                <Setter Property="Background" Value="{Binding Converter={StaticResource BackgroundConverter}}" />
            </DataTrigger>
        </Style.Triggers>
    </Style>

我想我理解需要让Trigger实际绑定到将会发生变化的事情(在这种情况下,我觉得我也被迫使用ValueConverter来获取列的值,有更直接的方法吗?),但即使我这样做,我还应该指定DataTrigger的值?

修改 所以在我的情况下,我继续做了以下事情(目前这只会修改TextBlock的背景):

<DataGridTemplateColumn Header="Lost" Width="Auto">
    <DataGridTemplateColumn.CellTemplate>
        <DataTemplate>
            <TextBlock Text="{Binding Lost, NotifyOnTargetUpdated=True}">
                <TextBlock.Triggers>
                    <EventTrigger RoutedEvent="Binding.TargetUpdated">
                        <BeginStoryboard>
                            <Storyboard>
                                <ObjectAnimationUsingKeyFrames Duration="0" Storyboard.TargetProperty="Background">
                                    <DiscreteObjectKeyFrame KeyTime="0" Value="{Binding Converter={StaticResource BackgroundConverter}}" />
                                </ObjectAnimationUsingKeyFrames>
                            </Storyboard>
                        </BeginStoryboard>
                    </EventTrigger>
                </TextBlock.Triggers>
            </TextBlock>
        </DataTemplate>
    </DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>

对我来说似乎是正确的,但由于某种原因只能运作一次。我在TargetUpdated定义上添加了一个单独的TextBlock事件处理程序,以查看是否确实在每次更改时都调用了该事件。 我EventTrigger上必须遗漏一些东西。可能与Storyboard有关。 无论如何,对于这么简单的事情来说,这一切似乎都非常冗长,所以我继续使用代码隐藏路线。

2 个答案:

答案 0 :(得分:1)

您使用转换器正确。您正在使用的技术有时称为“binning”,它将大量整数映射到固定的一组小值。它也用于创建直方图。

就未更新而言,绑定表达式必须更具体,才能检索Lost属性,否则在Lost更改时不会重新评估它。更改后,您还需要更新转换器。

答案 1 :(得分:1)

我认为Triggers和DataTriggers在这种情况下无法提供帮助,因为datagrigger的值不稳定。更糟糕的是,它不是依赖属性,你无法绑定它。在我看来,更好的方法是使用EventTrigger。

    <Window.Resources>
    <BeginStoryboard x:Key="bsbPing">
        <Storyboard>
            <DoubleAnimation Duration="0:0:0.2" Storyboard.TargetProperty="FontSize" To="{Binding Path=PingValue}"  />
        </Storyboard>
    </BeginStoryboard>
</Window.Resources>

<Grid>
    <StackPanel>
        <TextBox Name="txbPingValue" Text="{Binding Path=PingValue}">
            <TextBox.Triggers>
                <EventTrigger RoutedEvent="TextBox.TextChanged">
                    <EventTrigger.Actions>
                        <StaticResource ResourceKey="bsbPing" />
                    </EventTrigger.Actions>
                </EventTrigger>
            </TextBox.Triggers>
        </TextBox>
        <Button Name="btnPing" Click="btnPing_Click">Ping</Button>
    </StackPanel>
</Grid>

和代码:

    public partial class Window7 : Window
{
    public Ping MyPing { get; set; }

    public Window7()
    {
        InitializeComponent();

        MyPing = new Ping { PingValue = 20.0 };
        this.DataContext = MyPing;

    }

    private void btnPing_Click(object sender, RoutedEventArgs e)
    {
        MyPing.PingValue += 10;
    }
}

public class Ping : INotifyPropertyChanged
{
    private double pingValue;
    public double PingValue 
    {
        get
        {
            return pingValue;
        }
        set
        {
            pingValue = value;
            NotifyPropertyChanged("PingValue");
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    private void NotifyPropertyChanged(String info)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(info));
        }
    }

}