My custom control shows an image. It has event handlers that allow the user to pan/drag the image and zoom it in or out. It exposes two DependencyProperties
ImageCenter- The current center point of the control in Image coordinatesImageRect- The current bounds of the control in Image coordinates
The client is allowed to bind to both of these properties simultaneously, but if they do, at least one of those bindings MUST use BindingMode.OneWayToSource. So you can force the view to show the image centered on a certain coordinate (without changing zoom) or you can force the view to show a specific Rect of the image (so changing zoom and panning at the same time) but you cannot do both.
(This reminds me a bit of how you may bind ItemsControl.ItemsSource or explicitly set its children in XAML but you may not do both. This is still more complicated behavior than I would like but for now I feel I need it.)
Given this requirement, what is the proper protocol to disallow a violation of the binding rule?
- I assume I need to check the binding in
PropertyChangedCallbackfunction for each property, is that correct? I would prefer to do so less frequently but I do not see any sort ofBindingSetorBindingClearedevent that I can hook on to. And theValidateValueCallbacksignature won't permit this sort of check. - When I detect an invalid situation, what is the proper thing to do? Throw an exception?
public static readonly DependencyProperty ImageCenterProperty =
DependencyProperty.Register(
nameof(ImageCenter),
typeof(Point),
typeof(LayerView),
new FrameworkPropertyMetadata(
new Point(-1, -1),
FrameworkPropertyMetadataOptions.AffectsRender,
(o, a) => { (o as LayerView)?.OnImageCenterChanged(a); }));
private void OnImageCenterChanged(DependencyPropertyChangedEventArgs args)
{
var bebCenter = BindingOperations.GetBindingExpressionBase(this, ImageCenterProperty);
var bebRect = BindingOperations.GetBindingExpressionBase(this, ImageRectProperty);
if (bebCenter != null && bebRect != null)
{
// Code here to
// a) get the specific binding type and mode of each binding
// b) check to see if one of them is not readonly and if so...
// c) ... do what? Throw an exception?
}
}
public Point ImageCenter
{
get => (Point)GetValue(ImageCenterProperty);
set => SetValue(ImageCenterProperty, value);
}
public static readonly DependencyProperty ImageRectProperty =
DependencyProperty.Register(
nameof(ImageRect),
typeof(Rect),
typeof(LayerView),
new FrameworkPropertyMetadata(
Rect.Empty,
FrameworkPropertyMetadataOptions.AffectsRender,
(o, a) => { (o as LayerView)?.OnImageRectChanged(a); }));
private void OnImageRectChanged(DependencyPropertyChangedEventArgs args)
{
var bebCenter = BindingOperations.GetBindingExpressionBase(this, ImageCenterProperty);
var bebRect = BindingOperations.GetBindingExpressionBase(this, ImageRectProperty);
if (bebCenter != null && bebRect != null)
{
// Code here to
// a) get the specific binding type and mode of each binding
// b) check to see if one of them is not readonly and if so...
// c) ... do what? Throw an exception?
}
}
public Rect ImageRect
{
get => (Rect)GetValue(ImageRectProperty);
set => SetValue(ImageRectProperty, value);
}