What is wrong with this Model?

Viewed 153

Perhaps it is a simple answer but I tried a lot of things without success. The problem is that my "PropertyChange" is always null in spite _gauges have values as picture at annex. UPDATE - I added more code (WpfControl is where WindowsFormsHost is defined. MyControl is the "Form" that is hosted at my WPF App

StackPanel

<StackPanel>
    <local:WpfControl Width="500" GaugesStatus="{Binding Gauge}" />
</StackPanel>
    

ViewModel

    public class ViewModel : INotifyPropertyChanged
        {
            
            public static readonly ViewModel instanceRet = new ViewModel();
            public ViewModel()
            { 
            }
    
            public static ViewModel InstanceRet => instanceRet;
                           
            private Gauges _gauges;
            public Gauges Gauge
            {
                get { return _gauges; }
                set
                {
                    _gauges = value;
                    OnPropertyChanged("Gauge");
                }
            }
    
            public event PropertyChangedEventHandler PropertyChanged;
    
            protected virtual void OnPropertyChanged(string propertyName)
            {
                if (PropertyChanged != null)
                {
                    PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
                }
            }
    
    

Code behind

 public test()
 {
    InitializeComponent();
    DataContext = new ViewModel();

    if (AltAircraft.Text != "AltAircraft")
    {
        Gauges gauge = new Gauges();
        gauge = new Gauges 
            { 
             Altitude = Convert.ToDouble(AltAircraft.Text), 
             AirSpeed = zSpeedKTS, 
             Heading = headingToWp, 
             PitchAngle = 0.123, 
             RollAngle = 0, TurnRate = 0 
            };
         ViewModel.InstanceRet.Gauge=gauge;
    }
    
 public class Gauges
 {
       public double  TurnRate { get; set; }
       public double  Altitude { get; set; }
       public double  RollAngle { get; set; }
       public double  PitchAngle { get; set; }
       public double  VerticalSpeed { get; set; }
       public double  Heading { get; set; }
       public double  AirSpeed { get; set; }
 }

WpfControl

    <UserControl x:Class="Testminimums.WpfControl"
                 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
                 xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
                 xmlns:local="clr-namespace:TestMinimums"
                 mc:Ignorable="d" 
                 d:DesignHeight="600" d:DesignWidth="600">
        
        <WindowsFormsHost Name="MyHost">
            <local:MyControl />
        </WindowsFormsHost>
        
    </UserControl>

enter image description here

2 Answers

It's hard to say for sure with only bits and pieces of code, but I strongly suspect the problem is that you've got two different ViewModel instances:

  • The one you're setting as the DataContext (DataContext = new ViewModel();)
  • The semi-singleton one accessed as ViewModel.InstanceRet

I would strongly advise getting rid of InstanceRet entirely - it feels like it's asking for trouble. Instead, just change your test constructor to:

public test()
{
    InitializeComponent();
          
    var vm = new ViewModel();
    DataContext = vm;

    if (AltAircraft.Text != "AltAircraft")
    {
        // Note: I've no idea where this data will come from, given
        // that we're in a constructor...
        Gauges gauge = new Gauges
        {
            Altitude = Convert.ToDouble(AltAircraft.Text),
            AirSpeed = zSpeedKTS,
            Heading = headingToWp,
            PitchAngle = 0.123,
            RollAngle = 0,
            TurnRate = 0
        };
        vm.Gauge = gauge;
    }
}

The ViewModel instance used by your control as the DataContext i.e. binding source is not the same instance that you modify in the test() constructor. You set the Gauge property on the static instance that is not used by the UI for data binding, therefore there is no listener for the PropertyChanged event of this static instance.

Why would you create a static instance of the ViewModel in the first place? You should create an instance and pass it (the same instance!) around your application where it is needed. Introducing a static instance also introduces some serious limitations and problems. You should avoid doing this in general.

If you really believe you need to share an instance by making it static, then at least make sure to use it exclusively. This means, don't crate an instance of ViewModel explicitly. For this reason, the constructor of ViewModel must be private. The field instanceRet should also be private:

public class ViewModel : INotifyPropertyChanged
{            
  private static readonly ViewModel instanceRet = new ViewModel();
 
  // Enforce the use of the static instance
  // by defining the constructor private.
  private ViewModel()
  { 
  }
    
  public static ViewModel InstanceRet
  {
    get
    {
      return instanceRet;
    }
  }
           
  private Gauges _gauges;
  public Gauges Gauge
  {
    get { return _gauges; }
    set
    {
      _gauges = value;
      OnPropertyChanged("Gauge");
    }
  }
    
  public event PropertyChangedEventHandler PropertyChanged;    
  protected virtual void OnPropertyChanged(string propertyName)    
    => this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}

Example

public test()
{
  InitializeComponent();
          
  DataContext = ViewModel.InstanceRet;

  if (AltAircraft.Text != "AltAircraft")
  {
    Gauges gauge = new Gauges();
    gauge = new Gauges { Altitude = Convert.ToDouble(AltAircraft.Text), AirSpeed = zSpeedKTS, Heading = headingToWp, PitchAngle = 0.123, RollAngle = 0, TurnRate = 0 };
    ViewModel.InstanceRet.Gauge = gauge;
  }
}
Related