WPF FrameworkElement не получает ввод с мыши

Попытка получить события OnMouse, появляющиеся в дочернем элементе FrameworkElement. Родительский элемент — это Panel (и свойство Background не равно Null).

class MyFrameworkElement : FrameworkElement
{
    protected override void OnMouseDown(MouseButtonEventArgs e)
    {
        // Trying to get here!
        base.OnMouseDown(e);
    }
}

public class MyPanel : Panel
{
    protected override void OnMouseDown(MouseButtonEventArgs e)
    {
        // This is OK
        base.OnMouseDown(e);
    }
}

OnMouse никогда не вызывается, событие всегда необрабатывается, и Snoop говорит мне, что перенаправленное событие, похоже, доходит только до элемента Panel.

<Window 
  x:Class="WpfApplication5.Window1"
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:l="clr-namespace:WpfApplication5"
  Title="Window1" Height="300" Width="300">
  <Border x:Name="myBorder" Background="Red">
    <l:MyPanel x:Name="myPanel" Background="Transparent">
      <l:MyFrameworkElement x:Name="myFE"/>
    </l:MyPanel>
  </Border>
</Window>

Документы говорят, что FrameworkElement обрабатывает ввод, но почему бы и нет в этом сценарии?


person lava    schedule 16.07.2010    source источник


Ответы (2)


OnMouseDown будет вызываться только в том случае, если ваш элемент отвечает на проверку попадания. См. раздел Проверка попаданий на визуальном уровне. Реализация по умолчанию будет выполнять тестирование на совпадение с графикой, нарисованной в OnRender . Создание Panel с фоном Transparent работает, потому что Panel рисует прямоугольник по всей своей области, и этот прямоугольник выдержит тест на попадание. Вы можете получить тот же эффект, переопределив OnRender для рисования прозрачного прямоугольника:

protected override void OnRender(DrawingContext drawingContext)
{
    drawingContext.DrawRectangle(Brushes.Transparent, null, 
        new Rect(0, 0, RenderSize.Width, RenderSize.Height));
}

Вы также можете переопределить HitTestCore, чтобы все клики засчитываются как попадания:

protected override HitTestResult HitTestCore(PointHitTestParameters hitTestParameters)
{
    return new PointHitTestResult(this, hitTestParameters.HitPoint);
}
person Quartermeister    schedule 17.07.2010

Я смог воспроизвести сценарий, который вы описали. Я немного поиграл, и только когда я изменил базовый класс MyFrameworkElement с FrameworkElement на что-то более конкретное, например UserControl, события начали запускаться так, как должны. Я не уверен на 100%, почему это так, но я бы рекомендовал использовать один из классов, производных от FrameworkElement, который соответствует вашим потребностям (например, Panel, как вы сделали в приведенном выше примере, или Button).

Мне было бы любопытно узнать точную причину, по которой приведенный выше пример дает такие результаты...

person Mark Carpenter    schedule 16.07.2010
comment
Спасибо за ваш ответ. Я немного поиграл и сумел добиться нужного поведения, добавив в FrameWorkElement следующее: protected override void OnRender(DrawingContext DrawingContext) { Size renderSize = this.RenderSize; Rect Rect = новый Rect(renderSize); Pen Pen = новое Pen (Brushes.Transparent, 0.0); DrawingContext.DrawRectangle(Brushes.Transparent, pen, rect); } Возможно, FrameworkElement имеет нулевой размер, если к нему что-то не добавить? - person lava; 17.07.2010