Alternatively: How to subscribe to the PropertyChanged event defined by INotifyPropertyChanged thru the databinding of two dependency properties?
I have two separate user controls inside my main window. One control contains the parameters that affect the other control, let’s call it the display control. I want the parameter control to act as the datasource of the display control so that when I change a parameter in the parameter control, the display control be listening and reacts accordingly.
For this I created a class that implements INotifyPropertyChanged that stores these parameters and created dependencies properties of this class type in both controls. I was expecting that if I binded one control property to the other I would get the desired behaviour, but unfortunately I am missing something important because the display control is not reacting.
On a closer inspection with the debugger, I notice that my event PropertyChangedEventHandler PropertyChanged was always null when a property had changed, and everything I have read indicates, that no one is listening.
Because the display control is created in real time, I have to create the binding programmatically like this:
var DispayControlValuesBinding = new Binding();
DispayControlValuesBinding.Source = DisplayControlsControl;
DispayControlValuesBinding.Path = new PropertyPath("DisplayControlValues");
DispayControlValuesBinding.Mode = BindingMode.OneWay;
DispayControlValuesBinding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
DispayControlValuesBinding.NotifyOnSourceUpdated = true;
//
graph.SetBinding(Graph.DisplayControlValuesProperty, DisplayControlValuesBinding);
Both controls have a dependency property called DispayControlValues. I try to bind the DisplayControlControl’s DisplayControlValues property to the graph control’s DisplayControlValues property.
When the application runs, it initializes the parameter control, then with a user request a display control is created programmatically and the binding is made. Then I change a value in the parameter control, this is catch by the parameters class that implements the INotifyPropertyChanged interface but because no one is listening, the event handler is null and here is where I am stuck.
Your help is greatly appreciated!
Here are more details as requested:
I have one user control that exposes the parameters that changes the behaviour of another control. This control has a dependency property that contains parameter details and implements the INotifyPropertyChanged interface.
Here is the class:
public class ZoomGraphControlValues : INotifyPropertyChanged
{
private bool _displayRaw;
public bool DisplayRaw
{
get { return _displayRaw; }
set
{
_displayRaw = value;
OnPropertyChanged(new PropertyChangedEventArgs("DisplayRaw"));
}
}
private bool _enableFit;
public bool EnableFit
{
get { return _enableFit; }
set
{
_enableFit = value;
OnPropertyChanged(new PropertyChangedEventArgs("EnableFit"));
}
}
public ZoomGraphControlValues()
{}
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(PropertyChangedEventArgs e)
{
if (PropertyChanged != null)
PropertyChanged(this, e);
}
}
Here is the dependency property:
public ZoomGraphControlValues ControlValues
{
get { return (ZoomGraphControlValues)GetValue(ControlValuesProperty); }
set { SetValue(ControlValuesProperty, value); }
}
public static readonly DependencyProperty ControlValuesProperty =
DependencyProperty.Register("ControlValues", typeof(ZoomGraphControlValues), typeof(ZoomGraphControls), new PropertyMetadata(null, OnControlValuesPropertyChanged));
private static void OnControlValuesPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var myObj = d as ZoomGraphControls;
myObj.OnControlValuesPropertyChanged(e);
}
private void OnControlValuesPropertyChanged(DependencyPropertyChangedEventArgs e)
{
if (ControlValues != null)
{
IniValues();
}
}
Then I have the display user control. This control also implements a dependency property of the same type as the other control and I want this control to be the target of the binding, so that when I change values in the parameter control, this control reflect the changes.
Here is the dependency property of this control:
public ZoomGraphControlValues ZoomGraphControlValues
{
get { return (ZoomGraphControlValues)GetValue(ZoomGraphControlValuesProperty); }
set { SetValue(ZoomGraphControlValuesProperty, value); }
}
public static readonly DependencyProperty ZoomGraphControlValuesProperty =
DependencyProperty.Register("ZoomGraphControlValues", typeof(ZoomGraphControlValues), typeof(zoomGraph), new PropertyMetadata(null, OnZoomGraphControlValuesPropertyChanged));
private static void OnZoomGraphControlValuesPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var myObj = d as zoomGraph;
myObj.OnZoomGraphControlValuesPropertyChanged(e);
}
private void OnZoomGraphControlValuesPropertyChanged(DependencyPropertyChangedEventArgs e)
{
if (ZoomGraphControlValues != null)
{
// update the control with the new parameters
ShowRawData(ZoomGraphControlValues.DisplayRaw);
SetChartBehabiour();
}
}
The Parameters control is initialized since the beginning of the application cycle. The display control gets created as per user request into a tab, so I have to create the control programmatically and thereby the binding as well:
//create the tab and wire tab events
//…
//create a display control
var graph = new zoomGraph();
// initialize the parameters class
var zgcv = new ZoomGraphControlValues
{
DisplayRaw = true,
ChartBehaviour = ChartBehaviour.Zoom
};
//assign the parameters class to the parameters user control dependency property
ZoomGraphControlsControl.ControlValues = zgcv;
//create the binding of the parameter control to the display control by linking their respective dependency properties
var zoomGraphControlValuesBinding = new Binding();
zoomGraphControlValuesBinding.Source = ZoomGraphControlsControl;
zoomGraphControlValuesBinding.Path = new PropertyPath("ControlValues");
zoomGraphControlValuesBinding.Mode = BindingMode.TwoWay;
zoomGraphControlValuesBinding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
zoomGraphControlValuesBinding.NotifyOnSourceUpdated = true;
zoomGraphControlValuesBinding.NotifyOnTargetUpdated = true;
graph.SetBinding(zoomGraph.ZoomGraphControlValuesProperty, zoomGraphControlValuesBinding);
//…
// add the user control to a tab
When I change a parameter in the parameter control I can see that it tries to fire the OnPropertyChanged event but it is always null. Because of this I think I am lacking something.
You are setting the binding mode to “OneWay” which means the view model will never get updated when the value changes in the view. Change the Binding mode to “TwoWay” and try again.
Also, check if you are changing the complete instance of “DisplayControlValues” or just properties on that class, because your binding is only set to fire when the entire instance changes, not its properties.
In addition to that, keep in mind that you can bind properties of two different controls using the Binding.ElementName property, which would make it unnecessary for you to create a view model, unless there is anything in the code behind you need to do when these values change.
If you post more code and XAML it will be easier to find the most appropriate way to solve your issue.