我正在尝试实现对Adorner的不寻常使用。将鼠标悬停在RichTextBox上时,将在其上方显示一个Adorner(请参见下图),使您可以将字符串列表添加到Adorner中包含的ListBox中。这用于在装饰元素中包含的段落中添加“标签”(即Flickr)。
首先:这甚至可能吗?
大多数装饰器示例都显示了如何重写Adorner的OnRender方法来完成诸如绘制形状之类的琐碎事情。我能够使用它来呈现一组矩形,该矩形创建了Adorner的灰色边框,如果RichTextBox的高度由于在显示Adorner时添加了额外的行文本而增加,它也会自动调整大小。
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 - possible to draw stackpanel?中描述的技术,我学习了如何在Adorner的初始化程序中毫无问题地将子控件(如TextBox)添加到Adorner。
但是,问题是这些控件在Adorner中的放置。
如果我可以创建一个灰色背景的网格并将其放置在Adorner的底部,那应该很好。我会假设(希望)这样的事情会自动发生,例如随着标签的添加,根据该Grid的大小变化自动调整Adorner的大小。
简而言之,假设这是可行的,谁能推荐一种在Adorner内创建此较低标记控制区域并将其相对于Adorner底部定位的方法(随着RichTextBox内容的调整大小,可能需要调整大小)?
最佳答案
哈扎!在Ghenadie Tanasiev的帮助下,我得到了答案。
与WPF中的大多数控件不同,装饰器没有任何现成的分配子元素的方式(例如我要添加的控件)。在不向装饰器添加任何内容的情况下,您只能覆盖其OnRender
方法,并在传递给它的DrawingContext
中绘制内容。老实说,这可能适合装饰者使用的99%的用例(诸如在对象周围创建拖动手柄之类的东西),但是我需要向我的Adorner添加一些适当的控件。
这样做的技巧是创建一个 VisualCollection
并将您的装饰器传递给集合的构造函数,以将其装饰器设置为其所有者。
所有这些都在this blog article中进行了非常全面的描述。不幸的是,在Ghenadie的指导下,直到我知道要搜索VisualCollection
为止,我对Google的反复搜索才使这篇文章不被发表。
本文中没有提到这一点,但请注意,可以将VisualCollection技术与装饰器的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; }
}
}
关于c# - 内置控件的WPF装饰器,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/9998691/