C# WPF鼠标事件路由问题 以下是我正在尝试做的:
构建一个基本上是滚动树视图的自定义控件。稍后,它将不得不以某种方式监控和交互其项目。(例如,它必须找到对应于名称路径的元素)。由于所有项目都具有相同的大小,因此这也是虚拟化的主要情况;) 毫不奇怪,这些元素应该支持基本的交互,比如(视觉上)响应鼠标悬停在它们上面 下面是我如何尝试的: 实际的树类有一个Items属性(它是一个IList)和两个滚动条作为它的可视子级,并覆盖度量、排列和渲染(希望忽略几个不相关的函数): 什么不起作用: 我的主要问题是子元素似乎没有得到mousedown事件(或其他鼠标事件)。也许我没有得到整个视觉树和路由事件的东西,但我从来没有看到控制台输出时,我点击该项目。在树上,我可以同时获得previewmousdown和MousedDown事件 此外,内部控件不会剪裁到内部显示区域(为什么要剪裁),我可以通过在排列滚动条和覆盖GetLayoutClip之前排列它们来解决这个问题。或者,我可以尝试让孩子们意识到他们的水平偏移,并简单地将他们安排在一个不合适的矩形中。但是,我确实想知道是否有更好的方法:)确保您正在为您的每个孩子打电话。仅仅覆盖VisualChildrenCount和GetVisualChild是不够的;框架还需要了解这种关系。(也许您是在“无关函数”中这样做的。) 虚拟化确实很难实现,与其尝试从头开始构建虚拟化,不如尝试使用的功能。看起来您正在垂直堆叠元素,并在每个深度缩进子元素。您可以使用逻辑将层次结构数据展平到单个列表中,该列表存储原始节点和嵌套级别。然后可以使用VirtualzingStackPanel将该列表绑定到ItemsControl,并根据嵌套级别设置每个容器的左边距C# WPF鼠标事件路由问题 以下是我正在尝试做的:,c#,wpf,mouseevent,C#,Wpf,Mouseevent,构建一个基本上是滚动树视图的自定义控件。稍后,它将不得不以某种方式监控和交互其项目。(例如,它必须找到对应于名称路径的元素)。由于所有项目都具有相同的大小,因此这也是虚拟化的主要情况;) 毫不奇怪,这些元素应该支持基本的交互,比如(视觉上)响应鼠标悬停在它们上面 下面是我如何尝试的: 实际的树类有一个Items属性(它是一个IList)和两个滚动条作为它的可视子级,并覆盖度量、排列和渲染(希望忽略几个不相关的函数): 什么不起作用: 我的主要问题是子元素似乎没有得到mousedown事件(或其他
如果您最终实现了自己的虚拟化控件,那么您可能希望直接从中继承。下面是一系列博客文章,介绍了实现虚拟化面板所需的一切:您当前的解决方案由于没有利用TreeView、ItemsControl、Control、ScrollViewer或任何面板的任何内置功能而损失惨重。您现在基本上是在WPF中进行WinForms编程。是什么让你决定沿着这条路走,而不是从TreeView或其他ItemsControl开始并根据需要修改它?非常感谢!它确实也调用了缺少的AddVisualChild:)现在,我也明白了为什么VisualCollection构造函数需要对父级VisualChild的引用——当添加了一些东西时,它会自动调用AddVisualChild(这就是滚动条神奇工作的原因)
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!");
}
}