这里是
构建一个基本上是滚动树视图的自定义控件。稍后,它将不得不以某种方式监视和交互其项(e、 g.它必须找到与某种路径(名称)对应的元素。因为所有项目的大小都相同,所以这也是虚拟化的一个基本情况;)
毫不奇怪,这些元素应该支持基本的交互,比如(视觉上)响应鼠标悬停在它们上面。
这里是
怎样
我试着这么做:
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事件(或其他鼠标事件)。也许我没有得到整个可视化树和路由事件的东西-但我从来没有看到控制台输出时,我点击该项目。在树上,我可以得到预览和鼠标下降事件。。。
而且,内部控件没有剪辑到内部显示区域(为什么要剪辑),我可以通过在排列滚动条和覆盖GetLayoutClip之前排列它们来解决这个问题。或者,我可以尝试让孩子们意识到他们的水平偏移,并简单地将他们安排在一个不合适的矩形中。不过,我确实想知道是否有更好的办法:)