PreviewMouseMove 发射两次

发布于 2024-11-14 15:34:29 字数 1502 浏览 2 评论 0原文

我对简单的代码有疑问。我花了几个小时寻找解决方案,但没有效果。 我有一个画布和矩形。我移动矩形,如果光标在外部,则委托 pMouseMove 对每个像素仅触发一次。相反,如果光标位于矩形处,则 delagate 会为每个像素触发两次。我只想运行一次,就好像它在矩形之外,该怎么做?

XAML:

<Window x:Class="WpfApplication1.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="350" Width="525">
  <Canvas x:Name="Can" Height="257" Width="503" Background="Gray">
    <TextBox Name="tb" Width="77" Height="20" Canvas.Left="0" Canvas.Top="-21"/>
  </Canvas>
</Window>

代码隐藏:

public partial class MainWindow : Window
{
    Rectangle rect = new Rectangle();
    private static int i;
    private static string s;

    public MainWindow()
    {
        InitializeComponent();

        rect.Height = 50;
        rect.Width = 50;
        rect.Fill = Brushes.Black;
        Can.Children.Add(rect);
        Can.PreviewMouseMove += pMouseMove;
    }

    private void pMouseMove(object sender, MouseEventArgs e)
    {
        //cursor over Rectangle
        Canvas.SetTop(rect, e.GetPosition(Can).Y + 10);
        Canvas.SetLeft(rect, e.GetPosition(Can).X + 10);

        //cursor outside Rectangle
        //Canvas.SetTop(rect, e.GetPosition(Can).Y - 10);
        //Canvas.SetLeft(rect, e.GetPosition(Can).X - 10);

        //Counter
        i++;
        tb.Text = i.ToString();

        //e.Handled = true;
    }
}

抱歉我的英语不好

I have a problem with a simple code. I was looking for a few hours a solution, but no effects.
I have a Canvas and Rectangle. I move Rectangle, if the cursor is outside, delegate pMouseMove fires only once for each pixel. Conversely, if the cursor is at the Rectangle, delagate fires twice for each pixel. I want to run it only once, as if it were outside the Rectangle, how to do it?

XAML:

<Window x:Class="WpfApplication1.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="350" Width="525">
  <Canvas x:Name="Can" Height="257" Width="503" Background="Gray">
    <TextBox Name="tb" Width="77" Height="20" Canvas.Left="0" Canvas.Top="-21"/>
  </Canvas>
</Window>

Code-behind:

public partial class MainWindow : Window
{
    Rectangle rect = new Rectangle();
    private static int i;
    private static string s;

    public MainWindow()
    {
        InitializeComponent();

        rect.Height = 50;
        rect.Width = 50;
        rect.Fill = Brushes.Black;
        Can.Children.Add(rect);
        Can.PreviewMouseMove += pMouseMove;
    }

    private void pMouseMove(object sender, MouseEventArgs e)
    {
        //cursor over Rectangle
        Canvas.SetTop(rect, e.GetPosition(Can).Y + 10);
        Canvas.SetLeft(rect, e.GetPosition(Can).X + 10);

        //cursor outside Rectangle
        //Canvas.SetTop(rect, e.GetPosition(Can).Y - 10);
        //Canvas.SetLeft(rect, e.GetPosition(Can).X - 10);

        //Counter
        i++;
        tb.Text = i.ToString();

        //e.Handled = true;
    }
}

Sorry for my bad english

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

原来是傀儡 2024-11-21 15:34:29

WPF 中的事件是路由事件,这实际上意味着您的 Canvas 将从画布本身以及画布内的所有内容接收事件。正如您所注意到的,CanvasPreviewMouseMove 事件正在接收来自 CanvasRectangle 的事件。

[更新]
我运行了您的代码并添加了一行来检查 e.OriginalSource 的值,以查看最初引发事件的原因。像这样:

private void pMouseMove(object sender, MouseEventArgs e)
{
    // print out e.OriginalSource just for learning purposes
    Console.WriteLine("OriginalSource:" + e.OriginalSource.ToString());
}

我最初的答案是检查 e.OriginalSource 的类型,因为我认为您两次收到相同的事件。但我现在明白你在说什么:如果 e.OriginalSourceRectangle,则 PreviewMouseMove 事件的引发频率是 e.OriginalSource 时的两倍code>e.OriginalSource 是 CanvasRectangle 的实现内部有一些东西正在执行此操作(找出答案的唯一方法是使用 Reflector 之类的工具来查看内部逻辑。但是,有一个解决方法,您可以使 所有

您可以设置rect.IsHitTestVisible = false;,这将消除矩形发送事件和e.OriginalSource - 这意味着 PreviewMouseMove 事件将来自 Canvas 然后您可以使用 VisualTreeHelper.HitTest 检查鼠标位置是否在 内部。 我刚刚运行了

下面的代码,我认为这是保证事件引发一致的方法,但仍然具有命中测试功能:

rect.Fill = Brushes.Black;
rect.IsHitTestVisible = false;
Can.Children.Add(rect);

PreviewMouseMove 处理程序中

private void pMouseMove(object sender, MouseEventArgs e)
{
    // Debug.WriteLine(e.OriginalSource.ToString());

    HitTestResult result = VisualTreeHelper.HitTest(rect, e.GetPosition(sender as UIElement));

    if (result != null) {
        Debug.WriteLine("Mouse inside rect")
    }
    else {
        Debug.WriteLine("Mouse outside rect");
    }
}

Events in WPF are Routed Events, which effectively means that your Canvas will receive events from the canvas itself and everything inside the canvas. As you noticed, the Canvas's PreviewMouseMove event is receiving events from both the Canvas and the Rectangle.

[Update]
I ran your code and added a line to check the value of the e.OriginalSource to see what originally raised the event. Like this:

private void pMouseMove(object sender, MouseEventArgs e)
{
    // print out e.OriginalSource just for learning purposes
    Console.WriteLine("OriginalSource:" + e.OriginalSource.ToString());
}

My original answer was to check e.OriginalSource's type because I thought you were receiving the same event twice. But I now see what you are saying: if e.OriginalSource is the Rectangle, the PreviewMouseMove event gets raised twice as often compared to when e.OriginalSource is the Canvas. There's something internal to the Rectangle's implementation that is doing this (only way to find out is to use a tool like Reflector to see the internal logic. However, there is a workaround where you can make the frequency of the event consistent.

You can set rect.IsHitTestVisible = false; and that will eliminate the Rectangle from sending events and being e.OriginalSource -- so that means all PreviewMouseMove events will come from the Canvas. Then you can use VisualTreeHelper.HitTest to check to see if the mouse position is inside the Rectangle.

I just ran this code below and I think this is a way to guarantee consistent raising of events, but still have your hit test capability.

In the constructor:

rect.Fill = Brushes.Black;
rect.IsHitTestVisible = false;
Can.Children.Add(rect);

In the PreviewMouseMove handler:

private void pMouseMove(object sender, MouseEventArgs e)
{
    // Debug.WriteLine(e.OriginalSource.ToString());

    HitTestResult result = VisualTreeHelper.HitTest(rect, e.GetPosition(sender as UIElement));

    if (result != null) {
        Debug.WriteLine("Mouse inside rect")
    }
    else {
        Debug.WriteLine("Mouse outside rect");
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文