首页 文章

具有线程更新属性的MVVM Model类

提问于
浏览
0

我刚开始使用MVVM设计模式,并基于此YouTube视频https://www.youtube.com/watch?v=EpGvqVtSYjs中显示的示例构建了我自己的小项目,源代码在此处http://danderson.io/posts/mvvm-session-01-02-demo-source-code-downloads/ . 除了示例之外,我在Model中创建了一个新线程,它每秒都会更新一些Model属性 . 它运作良好;我的视图中的文本框每秒都像预期的那样更新 . 但是,在Model和绑定上实现了INotifyPropertyChanged的示例是从View到Model的属性 . 如果我理解了MVVM模式,后者描述的方法是针对MVVM模式的,那么应该在ViewModel上实现INotifyPropertyChanged,而View应该绑定到ViewModel中的属性 . 这正是我在我的小项目上尝试的,但我不知道ViewModel应该如何知道模型的属性是否更新以将PropertyChanged事件抛出到View . Model,ViewModel和View绑定代码的代码粘贴在下面 . 我的奋斗的任何想法都非常受欢迎,提前谢谢 .

Model类:

public class Customer
{
    private Thread _thread;

    /// <summary>
    /// Initializes a new instance of the Customer class.
    /// </summary>
    public Customer() {
        _thread = new Thread(Temporal);
        _thread.IsBackground = true;
        _thread.Start();
    }

    private string _Name;
    /// <summary>
    /// Gets or sets the Customer's name.
    /// </summary>
    public String Name {
        get {
            return _Name;
        }
        set {
            _Name = value;
        }
    }

    public void Temporal()
    {
        int i = 0;

        while (true)
        {
            Name = "Customer #" + i.ToString();
            i++;
            System.Threading.Thread.Sleep(1000);                
        }
    }
}

ViewModel类:

internal class CustomerViewModel : INotifyPropertyChanged
{
    /// <summary>
    /// Initializes a new instance of the CustomerViewModel class.
    /// </summary>
    public CustomerViewModel() {
        _Customer = new Customer();
    }        

    private Customer _Customer;

    public string Name
    {
        get { return _Customer.Name }
        set
        {
            _Customer.Name = value;
            OnPropertyChanged("Name");
        }
    }           

    #region INotifyPropertyChanged Members

    public event PropertyChangedEventHandler PropertyChanged;

    private void OnPropertyChanged(string propertyName) {
        PropertyChangedEventHandler handler = PropertyChanged;

        if (handler != null) {
            handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }

    #endregion
}

对于我的视图中的绑定,我使用以下内容:

Text="{Binding CustomerViewModel.Name, UpdateSourceTrigger=PropertyChanged}"

1 回答

  • 0

    您的代码中存在许多问题 .

    Issue 1

    您的代码将无法编译,因为您的 CustomerViewModel 未使用 Customer 的实例,但它正在使用 Customer 类 . 请查看下面的代码并在线阅读我的评论:

    public string Name
    {
        get { return Customer.Name } // <-- Should be _Customer.Name
        set
        {
            Customer.Name = value; // <-- Should be _Customer.Name
            OnPropertyChanged("Name");
        }
    }
    

    Issue 2

    当你的线程更改 Customer 实例时, CustomerViewModel 完全没有意识到这种变化 . 没有任何规则写在你的模型不能有 PropertyChanged . 因此,要么在 Customer 类中使用自定义事件或 PropertyChanged . 像这样:

    public class Customer : INotifyPropertyChanged
    {
        // other code...
        private string _Name;
        public String Name
        {
            get
            {
                return _Name;
            }
            set
            {
                _Name = value;
                OnPropertyChanged(nameof(Name));
            }
        }
    
        public event PropertyChangedEventHandler PropertyChanged;
    
        private void OnPropertyChanged(string propertyName)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
    
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    
        //... other code
    }
    

    所以现在你的 Customer 类能够在订阅者的属性发生变化时通知订阅者 .

    Issue 3

    虽然你的 CustomerViewModel 有关于 PropertyChanged 的代码,但它没有实现 INotifyPropertyChanged ,所以无论谁使用它,例如你的视图,都不知道它是可观察的 . 因此,如果您的 CustomerViewModel 更改,视图将不会知道 . 因此它不会更新 .

    因此,更改 CustomerViewModel 中的代码以实现 INotifyPropertyChanged 并订阅 Customer.PropertyChanged 然后触发视图以更新自身 .

    internal class CustomerViewModel : INotifyPropertyChanged
    {
        public CustomerViewModel()
        {
            _Customer = new Customer();
            // Subscribe to the PropertyChanged event
            _Customer.PropertyChanged += _Customer_PropertyChanged;
        }
    
        private void _Customer_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            // Check if Name changed, if yes, trigger the event so subscribers (view) can update.
            if (e.PropertyName == nameof(Customer.Name))
            {
                OnPropertyChanged(nameof(Name));
            }
        }
    
        private Customer _Customer;
    
        public string Name
        {
            get { return _Customer.Name; }
            set
            {
                _Customer.Name = value;
                OnPropertyChanged("Name");
            }
        }
    
        #region INotifyPropertyChanged Members
    
        public event PropertyChangedEventHandler PropertyChanged;
    
        private void OnPropertyChanged(string propertyName)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
    
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    
        #endregion
    }
    

    最后这里是XAML:

    <TextBox Text="{Binding Path=Name}">
    

相关问题