PreviewMouseMove стреляет дважды - PullRequest
3 голосов
/ 10 июня 2011

У меня проблема с простым кодом.Я искал решение в течение нескольких часов, но без последствий.У меня есть холст и прямоугольник.Я перемещаю Rectangle, если курсор находится снаружи, делегат pMouseMove запускается только один раз для каждого пикселя.И наоборот, если курсор находится в прямоугольнике, делагат запускается дважды для каждого пикселя.Я хочу запустить его только один раз, как если бы он был вне прямоугольника, как это сделать?

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

Извините за мой плохой английский

1 Ответ

3 голосов
/ 11 июня 2011

События в 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.OriginalSource является Rectangle, событие PreviewMouseMove возникает в два раза чаще по сравнению с тем, когда e.OriginalSource является Canvas.Есть что-то внутреннее в реализации Rectangle, которая делает это (единственный способ выяснить это - использовать инструмент, такой как Reflector, чтобы увидеть внутреннюю логику. Однако есть обходной путь, в котором вы можете сделать частоту события согласованной.

Вы можете установить rect.IsHitTestVisible = false;, и это исключит Прямоугольник из отправки событий и будет 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");
    }
}
...