当值从模型派生时,如何通知绑定元素哦值更改?

How to notify a bound element oh a value change when value derives from model?

在我的视图模型中,我可以看到绑定到以下 属性 的进度条:

public string CalcProgVisibility
{
    get
    {
        return Calculation.CalcProgVisibility;
    }
    set
    {

    }
}

计算是我的模型,可以改变数值。当模型中的值发生变化时,我需要做什么来确保视图意识到这一变化?

编辑:

这也是我模型中的 属性。我正在使用 on属性changed 但它没有进入视图。

我正在更改模型中的值,视图绑定到我的视图模型,视图模型试图 return 从模型中获取的值。我正在更新模型上的值,无法将它已更新值的事实一直推到视图,我只能让视图模型看到它已更改...

我更新了整个代码。我希望现在清楚了。

定义您的控件 BindingMode = TwoWay

<TextBox Visibility="{Binding Path=CalcProgVisibility, Mode=TwoWay}"...

并在您的视图模型和模型

中的 属性 的 setter 上调用 OnPropertyChanged 方法
        //Model
    public class Calculation : INotifyPropertyChanged
    {
        private string _calcProgVisibility;

        public string CalcProgVisibility
        {
            get { return _calcProgVisibility; }
            set
            {
                _calcProgVisibility = value;
                OnPropertyChanged("CalcProgVisibility");
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        protected void OnPropertyChanged(string propertyName)
        {
            RaisePropertyChanged(propertyName);
        }

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

            if (handler == null) return;

            handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }

    //ViewModel
    public class ViewModel : INotifyPropertyChanged
    {
        public ViewModel(Calculation model)
        {
            this.CalcProgVisibility = model.CalcProgVisibility;
            model.PropertyChanged += (s, e) => UpdateEntity(s as Calculation);
        }

        private void UpdateEntity(Calculation source)
        {
            CalcProgVisibility = source.CalcProgVisibility;
        }      

        private string _calcProgVisibility;

        public string CalcProgVisibility
        {
            get { return _calcProgVisibility; }
            set
            {
                _calcProgVisibility = value;
                OnPropertyChanged("CalcProgVisibility");
            }
        }

         public event PropertyChangedEventHandler PropertyChanged;

        protected void OnPropertyChanged(string propertyName)
        {
            RaisePropertyChanged(propertyName);
        }

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

            if (handler == null) return;

            handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }

您的 Viewmodel 必须实现 INotifyPropertyChanged 接口。要在您的情况下触发它,您的视图模型还必须知道模型对象的变化。所以你的模型对象也可以实现 INotifyPropertyChanged,或者你使用某种形式的观察者模式。

如果您的模型实现了 INotifyPropertyChanged,您的视图模型必须手动注册此事件并实现处理程序。这可能会触发 viewmodel 的 PropertyChange 事件。

另一种但在我看来丑陋的方法是扫描(每个计时器或后台线程)你的 viemodel 并检查自上次扫描以来值是否发生变化,然后触发 属性 changed 事件。

第一个解决方案可能如下所示:

using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.ComponentModel;
using System.Runtime.CompilerServices;

namespace Whosebug
{
    [TestClass]
    public class IntegrationTest
    {
        [TestMethod]
        public void NotifyPropertyChangeShouldFireOnViewModelWhenModelChanges()
        {
            //Arrange

            Model model = new Model();
            ViewModel sut = new ViewModel(model);
            bool notifyPropertyChangeOnViewModelWasCalled = false;
            sut.PropertyChanged += (sender, e) => { notifyPropertyChangeOnViewModelWasCalled = true; };

            //Act

            model.CalcValue = 4711;

            //Assert

            Assert.IsTrue(notifyPropertyChangeOnViewModelWasCalled, "NotifyPropertyChange was not fired on ViewModel");
        }
    }


    public class ObjectWithNotifyPropertyChanged : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
        protected void RaisePropertyChanged([CallerMemberName]string propertyName = "")
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }

    public class Model : ObjectWithNotifyPropertyChanged
    {
        private double calcValue;
        public double CalcValue
        {
            get
            {
                return calcValue;
            }
            set
            {
                if (calcValue != value)
                {
                    calcValue = value;
                    RaisePropertyChanged();
                }
            }
        }
    }

    public class ViewModel : ObjectWithNotifyPropertyChanged
    {
        public ViewModel(Model model)
        {
            this.model = model;
            model.PropertyChanged += model_PropertyChanged;
        }

        void model_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            switch (e.PropertyName)
            {
                case "CalcValue":
                    RaisePropertyChanged("CalcValue");
                    break;
            }
        }

        private Model model;

        public double CalcValue
        {
            get
            {
                return model.CalcValue;
            }
        }
    }
}