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