依赖属性问题

时间:2010-10-18 21:27:06

标签: wpf dependency-properties

我有一个依赖属性绑定到文本块。根据依赖属性,如果值更改,它将反映文本块中的值。财产中的数据来自实时设备。现在,无论何时出现任何数据,它都会传播到依赖属性并将到达文本块。但现在我发现客户想要的是,如果相同的值达到5次,则更改文本框的背景颜色。

但我无法收到更改通知。在这个时刻,我们很难改变设计。

你能告诉我一些解决方法以及通过依赖属性接收所有通知值是相同还是不同的方法?

4 个答案:

答案 0 :(得分:0)

我不确定你的目的是什么,但听起来你想跟踪来自Feed的实时值的“新鲜”或“陈旧”程度。如果是这样的话,INotifyPropertyChanged(Dependency Properties背后的力量)可能不会让你开心,因为它将完全取决于该接口的实现,以确定在采样时是否会被告知样本已经改变(它们的概念不同)。

根据您对此的控制程度,我建议在ViewModel中实现“陈旧”跟踪(您正在使用MVVM,对吗?)

类似的东西:

Model.cs:

using System;
using System.Windows.Threading;

namespace WpfApplication1
{
  public class Model
  {
    private readonly double[] _data = new[] { 2.3, 2.4, 2.5, 2.4, 2.1, 2.1, 2.1, 2.1, 2.0, 2.1, 2.0, 2.1, 2.2, 2.2, 2.2, 2.2, 2.2, 2.4 };
    private readonly DispatcherTimer _timer = new DispatcherTimer();
    private int _nextSample;


    public Model()
    {
      _timer.Interval = new TimeSpan(0, 0, 0, 1);
      _timer.Tick += _timer_Tick;
      _timer.Start();
    }

    public event EventHandler<SampleTakenEventArgs> SampleTaken;

    private void _timer_Tick(object sender, EventArgs e)
    {
      if (SampleTaken != null)
      {
        SampleTaken(this, new SampleTakenEventArgs { SampleValue = _data[_nextSample] });
      }
      _nextSample = (++_nextSample%_data.Length);
    }
  }
}

View.xaml:

<Window x:Class="WpfApplication1.View"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <StackPanel>
        <TextBlock Text="{Binding Sample}"/>
        <TextBlock Text="{Binding StaleCount}"/>
    </StackPanel>
</Window>

View.xaml.cs:

using System.Windows;

namespace WpfApplication1
{
  public partial class View : Window
  {
    public View()
    {
      InitializeComponent();
      DataContext = new ViewModel();
    }
  }
}

ViewModel.cs:

using System.ComponentModel;

namespace WpfApplication1
{
  public class ViewModel : INotifyPropertyChanged
  {
    private readonly Model _model;
    private double _sample;
    private int _staleCount;

    public ViewModel()
    {
      _model = new Model();
      _model.SampleTaken += _model_SampleTaken;
    }

    public double Sample
    {
      get { return _sample; }
      set
      {
        _sample = value;
        OnPropertyChanged("Sample");
      }
    }

    public int StaleCount
    {
      get { return _staleCount; }
      set
      {
        _staleCount = value;
        OnPropertyChanged("StaleCount");
      }
    }

    #region INotifyPropertyChanged Members

    public event PropertyChangedEventHandler PropertyChanged;

    #endregion

    private void _model_SampleTaken(object sender, SampleTakenEventArgs e)
    {
      if (e.SampleValue == Sample)
      {
        StaleCount++;
      }
      else
      {
        StaleCount = 0;
      }
      Sample = e.SampleValue;
    }

    protected void OnPropertyChanged(string propertyName)
    {
      var propertyChanged = PropertyChanged;
      if (propertyChanged != null)
      {
        propertyChanged(this, new PropertyChangedEventArgs(propertyName));
      }
    }
  }
}

答案 1 :(得分:0)

警告:这是基于上述问题的黑客攻击,这不是理想的设计,但应该实现OP的目标。

您可以在当前绑定中滑动IMultiValueConverter并在XAML中执行类似的操作...

<TextBlock Name="TextBlock">
    <TextBlock.Background>
        <MultiBinding Converter="{StaticResource MyConverter}">
            <Binding Path="ViewModelProperty"></Binding>
            <Binding ElementName="TextBlock"></Binding>
        </MultiBinding>
    </TextBlock.Background>
    <TextBlock.Text>
        <MultiBinding Converter="{StaticResource MyConverter}">
            <Binding Path="ViewModelProperty"></Binding>
            <Binding ElementName="TextBlock"></Binding>
        </MultiBinding>
    </TextBlock.Text>
</TextBlock>

然后在IMultiValueConverter中,样本将是......

public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
    String text = (String)values[0];
    TextBlock reference = (TextBlock)values[1];

    if (targetType == typeof(String))
        return text;
    else if (targetType == typeof(Brush))
    {
        int count = 0;
        if (reference.Tag == null)
            reference.Tag = count;

        count = (int)reference.Tag;
        if (++count == 5)
            return Brushes.Red;
        else
            return Brushes.White;
    }
    else
        throw new NotSupportedException();
}

我正在做的是利用您现有的属性并基本上重载它,允许您将TextBlock.Background属性绑定到ViewModel上已存在的同一属性。请注意在TextBlock中传递MultiBinding实例的用法。

需要注意的是,如果你的设计在实例中移动,那么计数将是不正确的,整个解决方案都会有缺陷......不知道......在初始问题中没有足够的信息。再次这是一个黑客,如果你有更多的权限进行更改,有更好的方法来做到这一点。

答案 2 :(得分:0)

您可以更改DependencyProperty的实现吗?您可以使用INotifyPropertyChanged将其实现为属性,如果可以,您将能够实现所需的计数器逻辑。

当值没有改变时,DependencyProperty的回调不会触发,所以如果你不能改变它的实现,那么你需要在其他地方挂钩代码......

答案 3 :(得分:0)

感谢您的回复...我知道这违背了我们理想的设计...但由于这已经与我们的大部分工作有关,最近客户改变了要求,因为想要打印这个值以及颜色。

所以我有一种方法可以解决它使用属性元数据中的强制回调而不是propertychnage事件。

解决了我的问题。现在我正在为我的单一控件执行此操作,我需要此功能,现在我也能够获得恒定值。

再次感谢