System.StackOverflowException WPF MVVM

4

我正在尝试使用MVVM在WPF中创建一个简单的数字时钟。 我有一个带有绑定的标签。 后台代码很简单,每秒钟引发一个属性更改事件,但是我遇到了stackoverflow异常。 请问有人能帮忙吗?

public partial class MainWindow : Window, INotifyPropertyChanged
{
    public MainWindow()
    {
        InitializeComponent();
        this.DataContext = this;
    }
    private string _lblValue;
    public string LabelValue
    {
        get
        {
            UpdateLabel();
            return _lblValue;
        }
        set
        {
            _lblValue = value;
            OnPropertyChanged(LabelValue);
        }
    }

    private void UpdateLabel()
    {
        _lblValue = System.DateTime.Now.ToString();
        //System.Threading.Thread.Sleep(2000);
        OnPropertyChanged("LabelValue");
    }

    public event PropertyChangedEventHandler PropertyChanged;
    protected void OnPropertyChanged(string propName)
    {
        var handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(propName));
        }
    }
}

作为一个侧面节点,你正在做的是违反MVVM模式的行为。Window是一个View类,与WPF框架紧密耦合。你的ViewModels不能依赖于WindowComponent或其他UI类。 - Tseng
3个回答

2
这是发生的事情:
  1. LabelValue的getter中调用UpdateLabel()函数。
  2. UpdateLabel()调用 OnPropertyChanged("LabelValue");
  3. 步骤2会导致UI检查属性LabelValue的更新值,也就是说它会调用LabelValue的getter。
  4. 回到步骤1。
以上所有步骤会一直重复,直到出现stackoverflow异常。尝试移除步骤2以解决问题。

2

正如har07所解释的那样,这是一个无限UI循环。这是我解决这个问题的方法。

public partial class MainWindow : Window, INotifyPropertyChanged
{
    public MainWindow()
    {
        InitializeComponent();
        this.DataContext = this;

        Task.Run(() => UpdateLabel());
    }

    private string _lblValue;
    public string LabelValue
    {
        get
        {
            return _lblValue;
        }
        set
        {
            _lblValue = value;
            OnPropertyChanged();
        }
    }

    private void UpdateLabel()
    {
        while (true)
        {
            LabelValue = System.DateTime.Now.ToString();
            System.Threading.Thread.Sleep(1000);
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
    protected void OnPropertyChanged([CallerMemberName] string propName = null)
    {
        var handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(propName));
        }
    }
}

如果这解决了你的问题,请将其标记为答案。谢谢。 - Stephen Zeng
谢谢Stephen。这个方法很有效。我一直在尝试一个简单的绑定和触发事件的例子,但是卡在那里了。感谢您的回复。 - yepimadotnetfreak

0
在您的情况下,最好使用一个间隔为一秒的计时器。
例如:

using System.Timers;
public partial class MainWindow : Window, INotifyPropertyChanged
{
    private Timer _clockTimer;

    public MainWindow()
    {
        InitializeComponent();
        this.DataContext = this;

       _clockTimer = new Timer(1000); // The interval is in milliseconds
       _clockTimer.Elapsed += (sender, e) =>
       {
           LabelValue = System.DateTime.Now.ToString();
       };
    }

    private string _lblValue;
    public string LabelValue
    {
        get
        {
            return _lblValue;
        }
        set
        {
            _lblValue = value;
            OnPropertyChanged("LabelValue");
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
    protected void OnPropertyChanged(string propName)
    {
        var handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(propName));
        }
    }
}


如果您对计时器有进一步的问题,您可以查看MSDN获取更多信息。


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