I'm building a custom control in WPF and running into some difficulties with capturing input mouse events. I've read the various documents on routed events and class event handlers however it's not really working for me. I am new to WPF as having mostly worked with Forms in the past.
Given the following custom control that can contain multiple children:
// Parent.cs
[ContentProperty(nameof(Children))]
public class Parent : Control
{
private DrawingGroup _backingStore = new DrawingGroup();
public List<UIElement> Children { get; } = new List<UIElement>();
static Parent()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(Parent), new FrameworkPropertyMetadata(typeof(Parent)));
}
protected override void OnPreviewMouseMove(MouseEventArgs e)
{
// default event handler
}
protected override void OnRender(DrawingContext drawingContext)
{
/*do some custom drawing*/
var backingContext = _backingStore.Open();
// draw an X indicating the background
backingContext.DrawRectangle(Background, new Pen(Brushes.White, 1), new Rect(0, 0, Width, Height));
backingContext.DrawLine(pen, new Point(0, 0), new Point(Width - 1, Height - 1));
backingContext.DrawLine(pen, new Point(0, Height - 1), new Point(Width - 1, 0));
backingContext.Close();
drawingContext.DrawDrawing(_backingStore);
}
protected override int VisualChildrenCount => Children.Count;
protected override Visual GetVisualChild(int index) => Children[index];
protected override Size ArrangeOverride(Size arrangeBounds)
{
foreach (FrameworkElement child in Children)
child.Arrange(new Rect(0, 0, arrangeBounds.Width, arrangeBounds.Height));
return new Size(arrangeBounds.Width, arrangeBounds.Height);
}
}
// Child.cs
[ContentProperty(nameof(Children))]
public class Child : Control
{
public List<UIElement> Children { get; } = new List<UIElement>();
static Child()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(Parent), new FrameworkPropertyMetadata(typeof(Parent)));
}
protected override void OnPreviewMouseMove(MouseEventArgs e)
{
// NEVER FIRED
}
protected override void OnRender(DrawingContext drawingContext)
{
/*do some custom drawing*/
}
// same as Parent
}
// TestWindow.xaml
<Window x:Class="TestApp.TestWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:TestApp"
Title="TestWindow" Height="450" Width="800">
<Grid>
<local:Parent Background="White">
<local:Child Background="Red" />
<local:Child Background="Green" />
</local:Parent>
</Grid>
</Window>
// ParentStyle.xaml
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:TestApp">
<Style TargetType="local:Parent">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:Parent">
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="local:Child">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:Child">
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
I've found that Parent
receives the raised mouse move events. However its children do not receive any mouse events. They aren't propagating downward, and while I could iterate through the Children and call RaiseEvent(e) that introduces other problems (hit testing, etc) and seems like the wrong answer.