0

I have the visibility of a progress bar bound to The following property within my viewmodel:

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

    }
}

Calculation is my model, which can change the value. When the value changes within the model, what do I need to do to make sure the view is aware of this change?

EDIT:

Here is the property within my model too. I am using onpropertychanged but its not making it to the view.

I am changing the value within the model, the view is bound to my viewmodel and the viewmodel si trying to return a value taken from the model. I am updating the value on the model, and cannot push the fact that it has updated the value all the way down to the view, I can only get the viewmodel to see it has changed...

pingu2k4
  • 956
  • 2
  • 15
  • 31
  • 1
    Can't you just send an event in your model when properties are changed? Did you try that already? – SuperOli Mar 24 '15 at 17:04
  • No one stops you from implementing the `INotifyPropertyChanged` in model objects - http://stackoverflow.com/questions/6922130/in-mvvm-model-should-the-model-implement-inotifypropertychanged-interface. – Eugene Podskal Mar 24 '15 at 17:10
  • Raise a PropertyChanged Notification https://msdn.microsoft.com/en-us/library/ms743695%28v=vs.110%29.aspx – Ganesh R. Mar 24 '15 at 17:12
  • @SuperOli I'm not too sure what you mean by that sorry? – pingu2k4 Mar 25 '15 at 15:34

2 Answers2

1

I updated the entire code. I hope it's clear now.

Define your control BindingMode = TwoWay

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

and call the OnPropertyChanged method on the setter of the property in your view model and also in your model

        //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));
        }
    }
Cristina Alboni
  • 1,014
  • 9
  • 15
  • The view is bound to the viewmodel, but the viewmodel returns a variable from a model and that variable is onlz ever updated within the model. I have tried this but it will not update... – pingu2k4 Mar 25 '15 at 15:28
  • This code will only trigger the UI update, when the 'InstallationOrderVisibility' property changes. Like other comments say, your model entities should also implement INotifyPropertyChanged in order to notify the viewmodel. – Cristina Alboni Mar 25 '15 at 15:54
  • this code doesnt relate to what I have though... This code returns a private bool, local to the same class whereas what I have is returning a public property from a different class. The property is changed in a different class. So instead of "return _installOrderVisibility; it should be "return calc.propertyName;" where calc refers to another class (my model). The calc.propertyName is the only actual value which ever changes. – pingu2k4 Mar 25 '15 at 16:33
  • I changed the code in my post to more detailed. I hope it helps to solve your problem. – Cristina Alboni Mar 26 '15 at 10:05
  • .PropertyChanged is not something thats being recognised in the VM. See image: http://imgur.com/rgj0COS – pingu2k4 Mar 26 '15 at 12:08
1

Your Viewmodel has to implement the INotifyPropertyChanged Interface. To fire it in your case your viewmodel must also be aware of changes in your model object. So your model object could also implement INotifyPropertyChanged, or you use some form of the observer pattern.

If your model implements INotifyPropertyChanged, your viewmodel must manually register for this event and implement an handler. This could in turn trigger the PropertyChange event of the viewmodel then.

Another but in my opinion ugly way would be to scan (per timer or background thread) through your viemodel and check if a value changed since the last scan and then trigger a property changed event.

The first solution could look like this:

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;
            }
        }
    }
}
Holger Thiemann
  • 1,042
  • 7
  • 17
  • With my viewmodel implementing the onpropertychanged event does nothing, as the variable is only ever set from within then model not inside the viewmodel. I have put an onpropertychanged event on the model, but this doesnt make it to the view. – pingu2k4 Mar 25 '15 at 15:30
  • I tried to clarify it in my anser a bit. Just implementing INotifyPropertyChanged in your model does nothing. Your viewmodel must register a handler for that event and delegate it to its own propertychange event if necessary. – Holger Thiemann Mar 26 '15 at 11:55
  • OK, that makes sense :) but I have no idea how to go about doing that... How would I do that? Thanks – pingu2k4 Mar 26 '15 at 12:09