3

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

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;
    }
}

对不起,我的英语不好

4

1 回答 1

3

WPF 中的事件是Routed Events,这实际上意味着您Canvas将从画布本身和画布内的所有内容接收事件。正如您所注意到的,Canvas'PreviewMouseMove事件正在接收来自Canvas和 的事件Rectangle

[更新] 我运行了您的代码并添加了一行来检查 的值,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两倍。的实现内部有一些东西正在这样做(找出的唯一方法是使用像 Reflector 这样的工具来查看内部逻辑。但是,有一种解决方法可以使事件的频率保持一致。e.OriginalSourceCanvasRectangle

您可以设置rect.IsHitTestVisible = false;,这将消除 Rectangle 发送事件和存在e.OriginalSource- 这意味着所有PreviewMouseMove事件都将来自Canvas. 然后您可以使用VisualTreeHelper.HitTest来检查鼠标位置是否在Rectangle.

我刚刚在下面运行了这段代码,我认为这是一种保证事件持续引发的方法,但仍然具有您的命中测试能力。

在构造函数中:

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");
    }
}
于 2011-06-11T04:52:27.777 回答