Проблема с маршрутизацией событий мыши WPF - PullRequest
1 голос
/ 10 июля 2010

Вот что Я пытаюсь сделать:

Создайте пользовательский элемент управления, который по сути является представлением дерева прокрутки.Позже ему придется отслеживать и взаимодействовать со своими предметами определенным образом.(например, он должен будет найти элемент, соответствующий некоторому пути имен).Поскольку все элементы будут иметь одинаковый размер, это также лучший случай для виртуализации;)

Неудивительно, что элементы должны поддерживать базовые взаимодействия, такие как реакция (визуально) на наведение мыши на них.

Вот как Я пытался это сделать:

Фактический класс дерева имеет свойство Items (которое является IList) и две полосы прокрутки в качестве визуальных дочерних и переопределяющих показателей., упорядочить и визуализировать (пара - надеюсь - не относящихся к делу функций не учтено):

public sealed partial class SyncTree : Control
{
    ScrollBar verticalScrollbar = new ScrollBar();
    ScrollBar horizontalScrollbar = new ScrollBar();

    private VisualCollection visualchildren;

    protected override int VisualChildrenCount
    {
        get
        {
            return visualchildren.Count + Items.Count;
        }
    }

    protected override Visual GetVisualChild(int index)
    {
        if (index < visualchildren.Count)
            return visualchildren[index];
        else
            return Items[index - visualchildren.Count];
    }

    private Size MeasuredSize = new Size(0, 0);

    protected override Size MeasureOverride(Size availableSize)
    {
        UpdateMeasuredSize();
        return availableSize;
    }

    protected override Size ArrangeOverride(Size arrangeBounds)
    {
        ArrangeItems(ArrangeScrollbars(arrangeBounds));
        return arrangeBounds;
    }

    private void ArrangeItems(Size arrangeBounds)
    {
        var y = Padding.Top - verticalScrollbar.Value;
        foreach (var item in Items)
        {
            item.Arrange(new Rect(Padding.Left - horizontalScrollbar.Value, y, item.Width, item.Height));

            y += item.Height;
            y += RootNodeSpacing;
        }
    }

    protected override void OnRender(DrawingContext context)
    {
        //kill the ugly background-colored patch between the scrollbars
        if (verticalScrollbar.IsVisible && horizontalScrollbar.IsVisible) context.DrawRectangle(verticalScrollbar.Background, null, new Rect(RenderSize.Width - verticalScrollbar.Width, RenderSize.Height - horizontalScrollbar.Height, verticalScrollbar.Width, horizontalScrollbar.Height));

        context.DrawRectangle(Background, null, new Rect(RenderSize));
    }
}

Элементы имеют собственный тип:

public class SyncTreeItem : Control
{
    protected override Size MeasureOverride(Size constraint)
    {
        var size = new Size(FormattedText.Width + FormattedText.Height + 5, FormattedText.Height);
        if (IsExpanded)
        {
            foreach (var item in Items)
            {
                item.Measure(new Size(constraint.Width - Indent, constraint.Height - size.Height));
                size.Height += item.DesiredSize.Height;
                size.Width = Math.Max(size.Width, item.DesiredSize.Width + Indent);
            }
        }
        Height = size.Height;
        Width = size.Width;
        return size;
    }

    protected override Size ArrangeOverride(Size arrangeBounds)
    {
        if (IsExpanded)
        {
            var y = FormattedText.Height;
            foreach (var item in Items)
            {
                item.Arrange(new Rect(Indent, y, item.Width, item.Height));
                y += item.Height;
            }
            return new Size(arrangeBounds.Width, y);
        }
        else return new Size(arrangeBounds.Width, FormattedText.Height);
    }

    protected override void OnRender(DrawingContext context)
    {
        context.DrawRectangle(Brushes.Transparent, null, new Rect(new Point(0, 0), RenderSize));
        context.PushClip(new RectangleGeometry(new Rect(RenderSize)));

        var ft = FormattedText;

        context.DrawImage(Icon, new Rect(0, 0, ft.Height, ft.Height));
        context.DrawText(ft, new Point(ft.Height + 5, 0));
    }

    protected override void OnMouseDown(MouseButtonEventArgs e)
    {
        Console.WriteLine("got mousedown!");
    }
}

Что не работает:

Моя основная проблема заключается в том, что дочерние элементы просто не получают событие mousedown (или других событий мыши).Возможно, я не получаю весь материал Visual Tree и Routed Event - но я никогда не вижу вывод консоли, когда я щелкаю элемент.На дереве я могу получить события предпросмотра вниз и mousedown ...

Кроме того, внутренние элементы управления не привязываются к внутренней области отображения (ну, почему они должны), что я мог бы исправить, упорядочивих, прежде чем упорядочить полосы прокрутки и перезаписать GetLayoutClip.В качестве альтернативы я мог бы попытаться заставить детей знать об их горизонтальном смещении и просто расположить их в прямоугольник, который не подходит.Однако мне интересно, есть ли лучший способ:)

1 Ответ

2 голосов
/ 10 июля 2010

Убедитесь, что вы звоните AddVisualChild для каждого вашего ребенка. Недостаточно просто переопределить VisualChildrenCount и GetVisualChild; рамки также должны быть проинформированы об отношениях. (Возможно, вы делаете это в «несоответствующих функциях».)

Виртуализация действительно трудна для реализации, и вместо того, чтобы создавать ее с нуля, лучше использовать функциональность VirtualizingPanel . Похоже, вы складываете элементы вертикально и делаете отступы для детей на каждой глубине. Вы можете иметь логику, чтобы сгладить иерархические данные в единый список, в котором хранится исходный узел плюс уровень вложенности. Затем вы можете связать этот список с ItemsControl с помощью VirtualizingStackPanel и установить левое поле каждого контейнера на основе уровня вложенности.

Если вы в конечном итоге реализуете свой собственный элемент управления виртуализацией, вы можете напрямую наследовать от VirtualizingPanel . Вот серия сообщений в блоге, в которых описывается все, что вам нужно сделать для реализации панели виртуализации: http://blogs.msdn.com/b/dancre/archive/tags/virtualizingtilepanel/

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...