为什么不在自定义FrameworkElement上触发MouseMove?

时间:2014-11-26 15:57:47

标签: c# wpf custom-controls

我无法在自定义FrameworkElement上触发MouseMove事件,该事件将用作绘图的主机。

案例显示在下一个示例代码中:

namespace WpfAppTest
{
  public class VisualPresenter : FrameworkElement
  {
    private readonly List<Visual> VisualChildren = new List<Visual>();
    public Size ViewSize = new Size(500, 300);

    public VisualPresenter()
    {
        var DrwVis = new DrawingVisual();
        using (var Context = DrwVis.RenderOpen())
            Context.DrawDrawing(
                  new GeometryDrawing(Brushes.LightSkyBlue, null,
                                      new RectangleGeometry(new Rect(ViewSize))));
        this.VisualChildren.Add(DrwVis);
    }

    protected override int VisualChildrenCount { get { return VisualChildren.Count; } }

    protected override Visual GetVisualChild(int index)
    {
        if (index < 0 || index >= VisualChildren.Count) throw new ArgumentOutOfRangeException();
        return VisualChildren[index];
    }

    protected override Size MeasureOverride(Size AvailableSize)
    { return this.ViewSize; }

    protected override Size ArrangeOverride(Size FinalSize)
    { return base.ArrangeOverride(FinalSize); }

    protected override void OnMouseMove(MouseEventArgs e)
    {
        // Why this is not fired when the mouse is over???
        Application.Current.MainWindow.Title = "Moving at: " + e.GetPosition(null);
    }
  }
}

这个“自定义控件”(如果这个概念适用于此处)可以在插入主窗口xaml时轻松测试...

<Window x:Class="WpfAppTest.MainWindow"
        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:WpfAppTest"
        mc:Ignorable="d"
        Title="MainWindow" Height="700" Width="600">
    <Grid>
        <local:VisualPresenter />
    </Grid>
</Window>

那么,缺少什么?

更新1: 我发现捕获鼠标时会触发mousemove事件,例如在VisualPresenter构造函数中添加下一行时:

this.Loaded += (s, e) => CaptureMouse();

更新2: 或者,也可以触发mousemove事件,而不是使用List,而是使用VisualCollection来注册子项。但是我更喜欢使用List来存储不仅仅是视觉(即识别那些暴露的视觉效果的键)。

2 个答案:

答案 0 :(得分:1)

没有背景被认为是空洞的,不能吸收鼠标事件。框架元素默认情况下没有可视化。因此,将根据OnRender方法中绘制的内容完成命中测试。可以通过在渲染上绘制一个空的透明矩形来启用命中测试。

    protected override void OnRender(DrawingContext drawingContext)
    {
        drawingContext.DrawRectangle(Brushes.Transparent, new Pen(Brushes.Transparent, 1), new Rect(0, 0, this.ActualWidth, this.ActualHeight));
        base.OnRender(drawingContext);
    }

答案 1 :(得分:1)

在分析(源代码深入研究)VisualCollection类如何工作之后,我发现缺少的部分是将新的可视对象附加到底层的WPF可视化树。那么,现在我们有......

this.VisualChildren.Add(DrwVis);  // This only shows the visual
this.AddVisualChild(DrwVis);      // This links the visual to its parent
瞧,瞧!点击测试Works和mousemove事件被触发。