Oxyplot在模型失效时无法捕获鼠标事件。

3
简短版: 当我调用myModel.InvalidatePlot(true/false)更新模型后,不会立刻捕获OxyPlot鼠标事件处理程序(例如mySeries.MouseDown)。 详细版: 我正在以一种非传统的方式使用OxyPlot库。我通过快速更新占据整个图形的图像注释来模拟背景视频的播放。这使我能够使用鼠标事件来在图像上绘制。我的问题是,视频/图像注释播放和鼠标事件是分开进行的,但当鼠标事件发生在“帧更新”期间时,有些事件会被忽略。我的想法是,在绘图无效化myModel.InvalidatePlot(true/false)时,鼠标事件直到模型更新后才被捕获。

注意:我的目标是看看是否有任何OxyPlot用户已经克服了这个问题。如果必要的话,我可能可以将我的模型包装在另一个元素中,该元素可以捕获鼠标事件,然后在准备好处理它们时将它们排队。 - CodyF
2个回答

0

我发现InvalidatePlot导致了一个问题,即鼠标按钮事件(例如OnMouseDown(MouseButtonEventArgs e))从未被PlotView捕获。为了解决这个问题,我使用了另一个WPF对象来捕获鼠标事件并强制调用我的PlotView的鼠标处理方法:

1)我在另一个ZIndex级别上添加了一个WPF网格,并附加了函数到鼠标事件(MouseDown,MouseWheel等):

<Grid x:Name="Grid_MouseCatcher"
        HorizontalAlignment="Stretch"
        VerticalAlignment="Stretch"
        Panel.ZIndex="2"
        MouseDown="Grid_MouseCatcher_MouseDown"
        MouseEnter="Grid_MouseCatcher_MouseEnter"
        MouseLeave="Grid_MouseCatcher_MouseLeave"
        MouseMove="Grid_MouseCatcher_MouseMove"
        MouseUp="Grid_MouseCatcher_MouseUp"
        MouseWheel="Grid_MouseCatcher_MouseWheel"
        Opacity="0.0"
        PreviewMouseMove="SetFocusToOxyPlot" />
<oxy:PlotView x:Name="PlotView"
        HorizontalContentAlignment="Stretch"
        VerticalContentAlignment="Stretch"
        Panel.ZIndex="1"
        Model="{Binding PlotModel}" />

2) 网格处理的每个事件都会调用我在 OxyPlot 源代码中创建的公共方法:

 /// <summary>
 /// Sends mouse events from the overlaying grid to the PlotView. Forcing an Action.
 /// This was included due to an OxyPlot bug where the OnMouse... methods were not being called 
 /// when the plot was invalidated via InvalidatePlot(...)
 /// </summary>
 /// <param name="sender"></param>
 /// <param name="e"></param>
 private void Grid_MouseCatcher_MouseDown(object sender, MouseButtonEventArgs e)
 {
     Debug.WriteLine("MouseCatcher - Down: " + e.GetPosition(Grid_MouseCatcher).X + " " + e.GetPosition(Grid_MouseCatcher).Y);
     PlotView.ForceMouseDown(e);
 }

3)在源代码文件OxyPlot.Wpf\PlotBase.Events.cs中,我创建了函数(例如ForceMouseDown(MouseButtonEventArgs e)),它显式调用受保护的鼠标事件(OnMouseDown(MouseButtonEventArgs e))

/// <summary>
/// Forces a call to Mouse handler. 
/// This was needed because the events were getting lost when the model was updating
/// </summary>
/// <param name="e"></param>
/// <returns></returns>
public void ForceMouseDown(MouseButtonEventArgs e){
    this.OnMouseDown(e);
}


/// <summary>
/// Invoked when an unhandled MouseDown attached event reaches an element in its route that is derived from this class. 
/// Implement this method to add class handling for this event.
/// </summary>
/// <param name="e">The <see cref="T:System.Windows.Input.MouseButtonEventArgs" /> that contains the event data. 
/// This event data reports details about the mouse button that was pressed and the handled state.</param>
protected override void OnMouseDown(MouseButtonEventArgs e)
{
    base.OnMouseDown(e);
    if (e.Handled)
    {
        return;
    }

    this.Focus();
    this.CaptureMouse();

    // store the mouse down point, check it when mouse button is released to determine if the context menu should be shown
    this.mouseDownPoint = e.GetPosition(this).ToScreenPoint();

    e.Handled = this.ActualController.HandleMouseDown(this, e.ToMouseDownEventArgs(this));
}

通过这种方式修复问题,我仍然可以按照OxyPlot的建议为我的Plotview添加鼠标事件处理程序,因为它们的OnMouse####事件仍然被调用,只是现在由覆盖网格显式调用。

请看我的答案,它使用了与你的解决方案相同的原理,但只需要三行代码。 - Herman
@CodyF 请问 PreviewMouseMove 事件的 SetFocusToOxyPlot 处理程序的源代码在哪里?谢谢。 - silviubogan

0

我找到了一种更简单的解决方法,基于CodyF的解决方案。在OxyPlot.Wpf.PlotBase的OnApplyTemplate()末尾添加以下行:

var mouseGrid = new Grid();
mouseGrid.Background = Brushes.Transparent; // background must be set for hit test to work
this.grid.Children.Add(mouseGrid);

然而,这个更改将会破坏当前的工具提示。请参见 OxyPlot 的 Github 页面上的 pull request


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接