Reputation: 355
What I want to do is to bind my usercontrol's label to a property value in ViewModel. But I also want to get notified when the label changed ( and to do other work like extract the label's new value to modify grid width and so on).
How to do this?
what I did is:
Have a viewmodel with an Voltage property, which is what I want to display.
UnitVm.cs
private int m_V;
public int VoltInVm
{
get
{ return m_V; }
set
{
if (m_V != value)
{
Set<int>(ref m_V, value, nameof(Volt));
}
}
}
and my usercontrol: Unit.cs
public partial class Unit : UserControl
{
public static readonly DependencyProperty VoltProperty =
DependencyProperty.Register("Volt", typeof(int), typeof(Unit),
new FrameworkPropertyMetadata(0, FrameworkPropertyMetadataOptions.AffectsRender, (o, e) => ((Unit)o).OnVoltChanged(o, e)));
private void OnVoltChanged(double dVolt)
{
double dWidth;
if (double.TryParse(strVal, out dWidth))
{
dWidth = dVolt / 380 * 100;
if (dWidth > 100)
dWidth = 100;
gridVolt.ColumnDefinitions[0].Width = new GridLength(dWidth, GridUnitType.Star);
gridVolt.ColumnDefinitions[1].Width = new GridLength(100 - dWidth, GridUnitType.Star);
}
}
public int Volt
{
get { return (int)GetValue(VoltProperty); }
set
{
SetValue(VoltProperty, value);
}
}
the DependencyProperty of VoltProperty is defined, and the work I want to do is written inside OnVoltChanged.
I mean when accepting change from ViewModel, I can call OnVoltChanged.
To use the usercontrol of Unit in a main window:
<DockPanel DataContext="{Binding UnitVm, Source={StaticResource Locator}}">
<Viewbox
<Label x:Name="lblVolt" Content="{Binding VoltInVm}" />
</Viewbox>
</DockPanel>
lblVolt binding to UnitVm context can update with new voltage values correctly. But how to bind to DependencyProperty of Volt in Unit? And is this the right way?
Thanks in advance.
Ting
Upvotes: 0
Views: 337
Reputation: 128042
The view model property setter is not implemented correctly.
It should look like shown below, i.e. use the correct property name nameof(VoltInVm)
and probably not check m_V != value
before calling Set
, because that is already done by the Set
method.
private int voltInVm;
public int VoltInVm
{
get { return voltInVm; }
set { Set<int>(ref voltInVm, value, nameof(VoltInVm)); }
}
When you now bind the UserControl's property like
<local:Unit Volt="{Binding VoltInVm}"/>
the PropertyChangedCallback of the Volt
dependency property will be called each time the VoltInVm
property changes its value.
It is however unclear what (o, e) => ((Unit)o).OnVoltChanged(o, e)
in the dependency property registration is supposed to be. It should certainly look like this:
(o, e) => ((Unit)o).OnVoltChanged((int)e.NewValue)
and the method should be declared with an int
argument instead of double
:
private void OnVoltChanged(int volt) ...
Or - certainly better - change all voltage property types to double
, in the control and in the view model.
Upvotes: 1