当值来自模型时,如何通知绑定元素值变化?

时间:2015-03-24 16:54:46

标签: c# wpf mvvm view model

我有一个进度条的可见性,该进度条绑定到我的viewmodel中的以下属性:

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

    }
}

计算是我的模型,它可以改变价值。当模型中的值发生变化时,我需要做些什么才能确保视图知道此更改?

编辑:

这也是我模型中的属性。我正在使用onpropertychanged但它没有使它成为视图。

我正在更改模型中的值,视图绑定到我的viewmodel并且viewmodel尝试返回从模型中获取的值。我正在更新模型上的值,并且无法推动它已将值一直更新到视图的事实,我只能获取viewmodel以查看它已更改...

2 个答案:

答案 0 :(得分:1)

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

定义您的控件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));
        }
    }

答案 1 :(得分:1)

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

如果您的模型实现了INotifyPropertyChanged,则您的viewmodel必须手动注册此事件并实现处理程序。这可以反过来触发viewmodel的PropertyChange事件。

另一个但在我看来,丑陋的方式是通过您的viemodel扫描(每个计时器或后台线程)并检查自上次扫描后值是否发生了变化,然后触发属性更改事件。

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

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

namespace StackOverflow
{
    [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;
            }
        }
    }
}