代码之家  ›  专栏  ›  技术社区  ›  danielschemmel

WPF鼠标事件路由问题

  •  1
  • danielschemmel  · 技术社区  · 16 年前

    这里是

    构建一个基本上是滚动树视图的自定义控件。稍后,它将不得不以某种方式监视和交互其项(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之前排列它们来解决这个问题。或者,我可以尝试让孩子们意识到他们的水平偏移,并简单地将他们安排在一个不合适的矩形中。不过,我确实想知道是否有更好的办法:)

    1 回复  |  直到 16 年前
        1
  •  2
  •   Quartermeister    16 年前

    一定要打电话 AddVisualChild 为你的每个孩子的视觉效果。仅仅重写VisualChildrenCount和GetVisualChild是不够的;框架还需要了解这种关系(也许你是在“不相关的函数”中这样做的

    虚拟化确实很难实现,与其尝试从头开始构建,不如尝试使用 VirtualizingPanel . 看起来您正在垂直堆叠元素,并在每个深度缩进子元素。您可以使用逻辑将层次结构数据展平到单个列表中,该列表存储原始节点和嵌套级别。然后可以使用virtualzingstackpanel将该列表绑定到ItemsControl,并基于嵌套级别设置每个容器的左边距。

    如果您最终实现了自己的虚拟化控件,那么您可能希望继承 虚拟化面板 直接。以下是一系列博客文章,介绍了实现虚拟化面板所需的一切: http://blogs.msdn.com/b/dancre/archive/tags/virtualizingtilepanel/