3

単純なコードに問題があります。解決策を数時間探していましたが、効果はありませんでした。Canvas と Rectangle があります。カーソルが外側にある場合、デリゲート pMouseMove はピクセルごとに 1 回だけ起動します。逆に、カーソルが Rectangle にある場合、delagate はピクセルごとに 2 回起動します。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 EventsCanvasです。これは事実上、キャンバス自体とキャンバス内のすべてからイベントを受け取ることを意味します。お気付きのように、Canvasのイベントはと のPreviewMouseMove両方からイベントを受信して​​います。CanvasRectangle

[更新] コードを実行し、e.OriginalSource最初にイベントを発生させた原因を確認するために の値を確認する行を追加しました。このような:

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

私の最初の答えは、同じイベントを2回受け取っていると思ったので、e.OriginalSourceのタイプを確認することでした。しかし、私は今あなたが言っていることを理解しe.OriginalSourceています. これを行っている の実装の内部に何かがあります (見つける唯一の方法は、Reflector などのツールを使用して内部ロジックを確認することです。ただし、イベントの頻度を一定にする回避策があります。RectanglePreviewMouseMovee.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 に答える