It's an old question, but I also found useful to bypass the event using a property-like custom event as in here. You can use a general EventHandler or you can be more specific (RoutedEventHandler, MouseButtonEventHandler, etc) to avoid later casts. For instance, to bypass a click event, you could write in your custom control class:
public readonly object objectLock = new object();
public event RoutedEventHandler CustomClick
{
add{ lock (objectLock) { myClickableInnerControl.Click += value;}}
remove {lock (objectLock) { myClickableInnerControl.Click -= value; }}
}
and for a PreviewMouseDown event, it would be something like:
public readonly object objectLock = new object();
public event MouseButtonEventHandler CustomPreviewMouseDown
{
add{ lock (objectLock) { myInnerControl.PreviewMouseDown += value;}}
remove {lock (objectLock) { myInnerControl.PreviewMouseDown -= value; }}
}
Where myInnerControl would be your canvas in this case.
Then you can initialize the event from xaml as
<local:myClickableControl x:Name="ClickCtrl1" CustomClick="ClickCtrl1_CustomClick" />
or
<local:myCustomControl x:Name="CustomCtrl1" CustomPreviewMouseDown="CustomCtrl1_CustomPreviewMouseDown" />
And from code behind:
ClickCtrl1.CustomClick+=ClickCtrl1_CustomClick;
or
CustomCtrl1.CustomPreviewMouseDown+=CustomCtrl1_CustomPreviewMouseDown;
You can also subscribe your callback to several inner controls events (being careful when they overlap as some events like previewMouseDown are not only fired by the front control but also by the controls underneath).
public readonly object objectLock = new object();
public event MouseButtonEventHandler CustomPreviewMouseDown
{
add{ lock (objectLock)
{
myInnerControl1.PreviewMouseDown += value;
myInnerControl2.PreviewMouseDown += value;
}}
remove {lock (objectLock)
{
myInnerControl1.PreviewMouseDown -= value;
myInnerControl2.PreviewMouseDown -= value;
}}
}
(If the inner controls partially overlap, you can use the corresponding eventArgs Handled property in your callback method to avoid repetitions)
Finally, you can add a layer of control to the event fired by your inner control:
bool MousePreviewDownUsed = false;
event MouseButtonEventHandler _myPreviewMouseDownEvent = null;
public event MouseButtonEventHandler CustomPreviewMouseDown
{
add
{
lock (objectLock)
{
_myPreviewMouseDownEvent += value;
if (value != null && !MousePreviewDownUsed)
{
myInnerControl.PreviewMouseDown += myInnerControl_PreviewMouseDown;
MousePreviewDownUsed = true;
}
}
}
remove
{
lock (objectLock)
{
if (_myPreviewMouseDownEvent != null)
{
_myPreviewMouseDownEvent -= value;
if ((_myPreviewMouseDownEvent == null ||
_myPreviewMouseDownEvent.GetInvocationList().Length == 0)
&& MousePreviewDownUsed)
{
_myPreviewMouseDownEvent = null;
myInnerControl.PreviewMouseDown -= myInnerControl_PreviewMouseDown;
MousePreviewDownUsed = false;
}
}
}
}
}
private void myInnerControl_PreviewMouseDown(object sender, MouseButtonEventArgs e)
{
// Do some previous operations or control whether the event must be broadcasted
_myPreviewMouseDownEvent?.Invoke(sender, e);
}
This event is initialized from xaml or code behind the same way as before.