WPF绑定未从DispatcherTimer更新

时间:2015-09-29 14:51:27

标签: c# wpf data-binding

以下是我遇到的问题的简化版本。这是一个相当普遍的问题,但我很难找到解决方案。

我已经将一个实例化的类绑定到主窗口上的某个项目。此类包含DispatcherTimer,用于更新值。在给出的示例中,它每秒将此值递增1。

我希望我的表单上的绑定项通过相应地更新其值来反映此更改,但它永远不会更新。

从阅读StackOverflow上类似问题的其他回答我感觉这是由于主要UI线程的性质分别运行到导致增量的线程。

我试图通过每次调用我的DispatcherTimer来更新此绑定时,我的头撞在墙上。

以下是我想要每秒更新的表单元素:

<TextBox Text="{Binding val}" Width="100"/>

接下来,这是包含计时器和我的应用程序配置的类的实例化:

BasicTimer basictimer;
public MainWindow()
{
  InitializeComponent();
  basictimer = new BasicTimer();
  DataContext = basictimer;
}

最后,这是我创建的课程。创建时,它会配置一个计时器,用于每秒更新一次值。每次更新此值时,我都希望主UI被通知更改并相应地更新。但是,这条消息似乎没有通过。

  class BasicTimer: INotifyPropertyChanged
  {
    DispatcherTimer _timer;

    uint _val = 10;
    public uint val
    {
      get
      {
        return _val;
      }
      set
      {
        if(_val!=value)
        {
          _val = value;
          OnPropertyChanged("Value");
        }
      }
    }

    public BasicTimer()
    {
      _timer = new DispatcherTimer();
      _timer.Tick += new EventHandler(TimerTick);
      _timer.Interval = new TimeSpan(0, 0, 1);
      _timer.Start();
    }


    private void TimerTick(object sender, EventArgs e)
    {
      val++;
      Console.WriteLine(val);
    }

    public event PropertyChangedEventHandler PropertyChanged;

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

我认为我已经设法避免了忘记INotifyPropertChanged的常见陷阱,其他模型的其他绑定值工作得很好。只是这个属性正在通过我遇到问题的主题进行更新。我也尝试使用简单的计时器创建一个类似的计时器,但我遇到了同样的问题。

非常感谢任何想法,谢谢!

1 个答案:

答案 0 :(得分:2)

我认为您的问题出在OnPropertyChanged的调用中:

uint _val = 10;
public uint val
{
  get
  {
    return _val;
  }
  set
  {
    if(_val!=value)
    {
      _val = value;
      OnPropertyChanged("Value");
    }
  }
}

那应该是

OnPropertyChanged("val");

OnPropertyChanged调用中的字符串必须与属性名称匹配。

修改

您希望传递给OnPropertyChanged的名称始终与属性名称匹配的原因是因为数据绑定订阅了对象的PropertyChanged事件,并且正在监视该字符串中的值参数传递给它的事件处理程序。如果传递的名称与其查找的名称不匹配,则会忽略该通知。它仅在名称匹配时更新绑定到该属性的控件的值。

正如Aron在评论中提到的,您可以使用CallerMemberAttribute方法中的OnPropertyChanged来确保属性名称始终正确传递给方法。根据{{​​3}}的答案,您的方法如下所示:

protected void OnPropertyChanged([CallerMemberName] string PropertyName = null)
{
  if (PropertyChanged != null)
  {
    PropertyChanged(this, new PropertyChangedEventArgs(PropertyName));
  }
}

然后,您将使用属性的setter中没有参数来调用它,并且名称将始终正确。

正如链接问题的答案所说,此代码编译成IL代码,与您在调用中对字符串进行硬编码时产生的代码相同,因此这个技巧将始终有效并且速度也一样快。