C# 内部带有控件的WPF装饰器
我试图实现一个装饰物的不同寻常的用途。当您将鼠标悬停在RichTextBox上时,它上方会出现一个装饰器(参见下图),允许您将字符串列表添加到装饰器中包含的列表框中。这用于将“标签”(即Flickr)添加到装饰元素中包含的段落中C# 内部带有控件的WPF装饰器,c#,.net,wpf,C#,.net,Wpf,我试图实现一个装饰物的不同寻常的用途。当您将鼠标悬停在RichTextBox上时,它上方会出现一个装饰器(参见下图),允许您将字符串列表添加到装饰器中包含的列表框中。这用于将“标签”(即Flickr)添加到装饰元素中包含的段落中 首先:这可能吗 大多数装饰器示例都显示了如何覆盖装饰器的OnRender方法来完成诸如绘制形状之类的琐事。我能够使用它来渲染一组矩形,这些矩形创建装饰器的灰色边框,如果在显示装饰器时由于添加了额外的行文本而导致RichTextBox的高度增加,该边框也会自动调整大小
首先:这可能吗 大多数装饰器示例都显示了如何覆盖装饰器的OnRender方法来完成诸如绘制形状之类的琐事。我能够使用它来渲染一组矩形,这些矩形创建装饰器的灰色边框,如果在显示装饰器时由于添加了额外的行文本而导致RichTextBox的高度增加,该边框也会自动调整大小
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。使用中描述的技术,我已经学会了如何将子控件(如文本框)添加到装饰器中,而在装饰器的初始值设定项中没有任何问题
然而,问题是这些控件在装饰器中的位置
如果我能创建一个灰色背景的网格,并将其放置在装饰器的底部,我就可以开始了。我假设(希望)添加标记时,根据网格大小的变化自动调整装饰器大小之类的事情会自动发生
简言之,假设这是可能的,有人能推荐一种方法,在装饰器内创建这个较低的标记控制区域,并将其相对于装饰器底部定位(可能需要随着RichTextBox内容的大小调整而调整大小)Huzah!在…的帮助下,我得到了一个答案
与WPF中的大多数控件不同,装饰器没有任何现成的方式来指定子元素(例如我想要添加的控件)。在不向装饰器添加任何内容的情况下,您只能重写它们的OnRender
方法,并在传递给它的DrawingContext
中绘制内容。老实说,这可能适合装饰器99%的使用情况(比如围绕对象创建拖动手柄),但我需要向装饰器添加一些适当的控件
实现这一点的诀窍是创建一个装饰器,并通过将其传递到集合的构造函数中,将装饰器设置为其所有者
这一切在本文中描述得相当全面。不幸的是,在Ghenadie的指导下,在我知道如何搜索VisualCollection
之前,我反复的谷歌搜索并没有找到这篇文章
本文中没有提到这一点,但请注意,可以将VisualCollection技术与adorner的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; }
}
}
另见不明显。Well discoveredblog已经死了,但wayback有一个快照。你不必把你的手弄得那么脏,看看我过去用过的。它允许您在XAML中定义装饰器,进行绑定,等等。实际上,我已经花了几个小时来研究这种方法,试图找到一种实现上述定位的方法,但我认为CodeProject示例中的代码不够健壮,无法适应我要做的事情。例如,它将我创建的任何装饰条剪切到装饰元素的边界(非常奇怪,因为装饰条的z索引总是应该在顶部)。我尝试了一些测试,比如将AdornedControl.AdornerContent下元素的高度绑定到装饰元素的实际高度,但失败了(无提示)。是的,它进行了剪裁,我发现它剪裁到布局,而不是装饰元素。至于你的问题,我再看看你的记忆,狒狒。:)今天下午我将自己继续做下去,并将报告我学到的任何东西。它实际上会剪辑到装饰层的边界。您可以在VisualTree中的任意位置放置AdornerDecorator,当您请求adorner层时,这是树中获取层的部分。如果您的AdorneDecorator的ClipToBounds设置为true,则它将被剪裁到该矩形。如果你不想剪贴,把你的装饰器放在窗口的水平,你的装饰器将有自由支配的位置。(我需要完全相反的方式…在面板周围显式放置一个AdorneDecorator,我希望将子控件的装饰夹到该面板上。