【问题标题】:OnMouseMove does not fire on canvas in WPFOnMouseMove 不会在 WPF 中的画布上触发
【发布时间】:2011-12-07 13:02:35
【问题描述】:

我已经完成了我的自定义图表控件,我想在光标之后画一个简单的十字。该图表被实现为画布上的折线,我在画布的 OnMouseMove 事件中绘制两条线来改变它们的坐标。

令人惊讶的是,当 MainGUI 线程空闲时(UI 完全响应,如果我暂停应用程序,主线程在 App mainForm.ShowDialog()) 处,则每 10 秒左右事件才会调用一次。

关于如何找出为什么会发生这种情况的任何想法?我使用 OnMouseMove 或 PreviewOnMouseMove 获得了相同的性能。

编辑:这就是我绘制十字架的方式(无论如何,如果我在 OnMouseMove 处设置断点,它只会不时停止)。

XAML:

<Border BorderThickness="1" BorderBrush="White" Grid.Column="1" Grid.Row="0" Grid.RowSpan="2" Grid.ColumnSpan="2" >
    <Canvas x:Name="DrawArea" PreviewMouseMove="DrawArea_PreviewMouseMove" />
</Border>

CS:

 public Chart()
 {
    _line = new Polyline();
    _line.Stroke = Brushes.Orange;
    _crossX = new Line();
    _crossY = new Line();
    _crossX.Stroke = Brushes.Orange;
    _crossY.Stroke = Brushes.Orange;
    _crossX.StrokeThickness = 1;
    _crossY.StrokeThickness = 1;

    InitializeComponent();

    this.DrawArea.Children.Add(_line);
    this.DrawArea.Children.Add(_crossX);
    this.DrawArea.Children.Add(_crossY);
}     

private void DrawArea_MouseMove(object sender, MouseEventArgs e)
{
    Point mousePosition = System.Windows.Input.Mouse.GetPosition(this.DrawArea);

    _crossX.X1 = 0;
    _crossX.X2 = this.DrawArea.ActualWidth;
    _crossX.Y1 = _crossX.Y2 = mousePosition.Y;

    _crossY.Y1 = 0;
    _crossY.Y2 = this.DrawArea.ActualHeight;
    _crossY.X1 = _crossY.X2 = mousePosition.X;
}

【问题讨论】:

  • 你不能定义一个自定义光标,而不是尝试做额外的绘图来“假”一个吗?
  • 所以,您没有性能问题,但问题是事件根本没有被调用 - 我理解对吗?
  • |Daniel:之所以这么叫,是因为画了十字架,但它可能每 10 秒左右更新 1 次。
  • @Damien:它不是游标,而是跨越图表的十字形,让您可以看到所代表数据的不同级别。
  • 你能展示一下你是怎么画十字架的吗?在 OnRender 中?小时候在画布上更新位置?请显示一些代码。

标签: c# wpf performance events


【解决方案1】:

这很奇怪,我不知道为什么......

FrameworkElement.MouseMove 仅在该区域具有一些明确的背景画笔\填充集时才有效。

在你的情况下设置Canvas.Background="Transparent",它应该可以工作。

还有另一个解决方法...WPF Not sending MouseMove events after CaptureMouse();

这可能是因为HitTest 取决于彩色像素及其反馈。

不管它是什么,它都没有在 MSDN 上记录,这让许多 UI 设计师感到困惑。

【讨论】:

  • 我只有两个字:THANKS 和 WTF????真奇怪。应该有人来填补微软的缺陷吧?
  • 如果画布上有一个子对象,例如形状、文本块或其他任何东西,则会为该对象和画布触发鼠标事件(它们是直接事件,因此它们不会到达画布从孩子们那里冒出来)。这很奇怪。
  • 这也适用于Grid
  • Background="Transparent" 可以解决问题 - 显然,如果没有任何背景,框架元素不会“看到”鼠标光标在其自身上方。
  • 虽然描述的行为看起来很奇怪,但它是有道理的。如果事件与控制相关但不与空的地方相关,则触发事件。例如,如果控件的形状不是矩形,这可能会有所帮助。
【解决方案2】:

我最终写了一个这样的鼠标全局鼠标处理程序:

using System.Windows.Interop;

private const int WM_MOUSEMOVE = 0x0200;
public delegate void Del_MouseMovedEvent(Point mousePosition);

// Relative to this control, the mouse position will calculated
public IInputElement Elmt_MouseMovedRelativeElement = null;

// !! This is static; needs special treatment in a multithreaded application !!
public static event Del_MouseMovedEvent Evt_TheMouseMoved = null;

// your main function call
public MyMainWindows()
{
    // install the windows message filter first
    ComponentDispatcher.ThreadFilterMessage += ComponentDispatcher_ThreadFilterMessage;

    InitializeComponent();

    ...
}   

// filtering the windows messages
private void ComponentDispatcher_ThreadFilterMessage(ref MSG msg, ref bool handled)
{
    if(msg.message == WM_MOUSEMOVE)
    {
        this.Evt_TheMouseMoved?.Invoke(Mouse.GetPosition(this.Elmt_MouseMovedRelativeElement));
    }
}

// individual event for mouse movement
private void MyMouseMove(Point mousePoint)
{
    // called on every mouse move when event is assigned
    Console.WriteLine(mousePoint.X + " " + mousePoint.Y);
}

private void AnyFunctionDeeperInTheCode()
{
    // assign the handler to the static var of the main window
    MyMainWindows.Evt_TheMouseMoved += MyMouseMove;

    // set the element / control to which the mouse position should be calculated; 
    MyMainWindows.Elmt_MouseMovedRelativeElement = this;

    ...

    // undassign the handler from the static var of the main window
    MyMainWindows.Evt_TheMouseMoved -= MyMouseMove;
}

【讨论】:

    猜你喜欢
    • 2012-02-12
    • 1970-01-01
    • 2016-12-16
    • 2017-12-27
    • 2022-08-15
    • 1970-01-01
    • 2022-12-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多