内置控件的WPF装饰器

我正在努力实现对Adorner的不寻常使用。 当您将鼠标hover在RichTextBox上时,Adorner(请参见下图)将显示在其上方,允许您将字符串列表添加到Adorner中包含的ListBox中。 这用于将“标签”(àlaFlickr)添加到装饰元素中包含的通道。

装饰图

首先 :这甚至可能吗?

大多数Adorners示例都展示了如何覆盖Adorner的OnRender方法来执行绘制形状之类的微不足道的事情。 我能够使用它来渲染一组矩形,这些矩形创建了Adorner的灰色边框,如果RichTextBox的高度由于在显示Adorner时添加了额外的行文本而增加,它也会自动resize。

protected override void OnRender(DrawingContext drawingContext) { SolidColorBrush grayBrush = new SolidColorBrush(); grayBrush.Color = Color.FromRgb(153, 153, 153); // left drawingContext.DrawRectangle(grayBrush, null, new System.Windows.Rect(1, 1, 5, ActualHeight)); // right drawingContext.DrawRectangle(grayBrush, null, new System.Windows.Rect(ActualWidth - 6, 1, 5, ActualHeight)); //bottom drawingContext.DrawRectangle(grayBrush, null, new System.Windows.Rect(1, ActualHeight, ActualWidth - 2, 5)); // for reasons unimportant to this example the top gray bar is rendered as part of the RichTextBox } 

但是,添加控件稍微有些问题。 一般来说,WPF的装饰需要在代码而不是XAML中添加子控件。 使用DrawingContext adorner中描述的技术- 可以绘制stackpanel? ,我已经学会了如何在Adorner的初始化程序中将子控件(如TextBox)添加到Adorner而没有任何问题。

然而,问题是将这些控件放置在Adorner中。

如果我可以创建一个灰色背景的网格并将其放置在Adorner的底部,我应该很高兴。 我会假设(希望)自动调整基于随着标签的大小变化而自动调整Adorner大小的事情。

简而言之,假设这是可能的 ,有人可以推荐一种在Adorner中创建这个较低标记控制区域的方法,并将其相对于Adorner的底部进行定位(可能需要在RichTextBox内容resize时resize)?

Huzah! 在Ghenadie Tanasiev的帮助下,我得到了答案。

与WPF中的大多数控件不同,装饰器没有任何开箱即用的方式来分配子元素(例如我想添加的控件)。 在不向装饰者添加任何内容的情况下,您只能覆盖其OnRender方法并在DrawingContext中绘制传递给它的内容。 说实话,这可能适合99%的装饰用例(比如在对象周围创建拖动手柄),但我需要为我的Adorner添加一些适当的控件。

这样做的诀窍是创建一个VisualCollection并将您的装饰器设置为其所有者,方法是将其传递给集合的构造函数。

在本博客文章中对此进行了全面的描述。 不幸的是,由于Ghenadie的指导,我知道搜索VisualCollection ,我的重复谷歌搜索都没有翻过这篇文章。

这篇文章中没有提到,但请注意,可以将VisualCollection技术与绘图在assembly器的OnRender方法中结合使用。 我正在使用OnRender来实现上图中描述的侧边和顶边框,并使用VisualCollection来放置和创建控件。

编辑:这是来自上述博客文章的源代码,因为它不再可用:

 public class AdornerContentPresenter : Adorner { private VisualCollection _Visuals; private ContentPresenter _ContentPresenter; public AdornerContentPresenter(UIElement adornedElement) : base(adornedElement) { _Visuals = new VisualCollection(this); _ContentPresenter = new ContentPresenter(); _Visuals.Add(_ContentPresenter); } public AdornerContentPresenter(UIElement adornedElement, Visual content) : this(adornedElement) { Content = content; } protected override Size MeasureOverride(Size constraint) { _ContentPresenter.Measure(constraint); return _ContentPresenter.DesiredSize; } protected override Size ArrangeOverride(Size finalSize) { _ContentPresenter.Arrange(new Rect(0, 0, finalSize.Width, finalSize.Height)); return _ContentPresenter.RenderSize; } protected override Visual GetVisualChild(int index) { return _Visuals[index]; } protected override int VisualChildrenCount { get { return _Visuals.Count; } } public object Content { get { return _ContentPresenter.Content; } set { _ContentPresenter.Content = value; } } } 

你不必弄脏你的手,看一下我过去使用过的CodeProject文章 。

它允许您在XAML中定义装饰器,进行绑定等。