Home > Blockchain >  What is wrong with this Model?
What is wrong with this Model?

Time:09-14

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

CodePudding user response:

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;
    }
}

CodePudding user response:

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;
  }
}

CodePudding user response:

we have here one part of a WPF app hosting a Winforms Control and dependency register so here the thks to contributors.

In opposition to the lot of examples of winforms apps that host wpf controls if you want the inverse you begin with Valiana/Velianaire https://github.com/velianarie/WfControlHostedInWpfControl (I only removed the "icommand" and used the BionicCode for final binding )

Also and big thks to @BionicCode because it was the Master Key to bind both worlds

  • Related