Вот что Я пытаюсь сделать:
Создайте пользовательский элемент управления, который по сути является представлением дерева прокрутки.Позже ему придется отслеживать и взаимодействовать со своими предметами определенным образом.(например, он должен будет найти элемент, соответствующий некоторому пути имен).Поскольку все элементы будут иметь одинаковый размер, это также лучший случай для виртуализации;)
Неудивительно, что элементы должны поддерживать базовые взаимодействия, такие как реакция (визуально) на наведение мыши на них.
Вот как Я пытался это сделать:
Фактический класс дерева имеет свойство 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.В качестве альтернативы я мог бы попытаться заставить детей знать об их горизонтальном смещении и просто расположить их в прямоугольник, который не подходит.Однако мне интересно, есть ли лучший способ:)