在 WPF 中相对于父级尺寸定位装饰器

发布于 2024-08-16 15:55:30 字数 3252 浏览 11 评论 0原文

我试图根据装饰元素的父元素的尺寸来定位装饰器。例如,我有一个文本框。我想装饰这个文本框,使其看起来像这样:

如何放置装饰器http://img707.imageshack.us/img707/9840/fig1.png

将文本框放置在画布对象中,如果有足够的可用空间,则将装饰器(半透明圆角正方形)与画布对象对齐文本框的底部边缘。当用户单击文本框时,装饰器就会启动。

目前,画布及其内容(文本框)托管在 WinForms 表单中 - 因此 WPF 由 ElementHost 控件处理。

但是当我运行代码时,第一次单击文本框时,它会显示与文本框顶部边缘对齐的装饰器(参见下图)。之后它就正确定位了自己(如上图)有谁知道为什么会这样?

装饰器的位置http://img14.imageshack.us/img14/4766/fig2v。 png

我已粘贴以下代码:

TextBoxAdorner.cs - 这是装饰器逻辑

public class TextBoxAdorner : Adorner
{
    private TextBox _adornedElement;
    private VisualCollection _visualChildren;
    private Rectangle _shape;
    private Canvas _container;
    private Canvas _parentCanvas;

    public TextBoxAdorner(UIElement adornedElement, Canvas parentCanvas)
        : base(adornedElement)
    {
        _adornedElement = (TextBox)adornedElement;
        _parentCanvas = parentCanvas;
        _visualChildren = new VisualCollection(this);

        _container = new Canvas();

        _shape = new Rectangle();
        _shape.Width = 100;
        _shape.Height = 80;
        _shape.Fill = Brushes.Blue;
        _shape.Opacity = 0.5;

        _container.Children.Add(_shape);

        _visualChildren.Add(_container);
    }

    protected override Size ArrangeOverride(Size finalSize)
    {
        Point location = GetLocation();
        _container.Arrange(new Rect(location, finalSize));

        return finalSize;
    }

    private Point GetLocation()
    {
        if (_parentCanvas == null)
            return new Point(0, 0);

        Point translate;
        double xloc = 0, yloc = _shape.Height - _adornedElement.ActualHeight;

        if (yloc < 0) // textbox is bigger than the shape
            yloc = 0;
        else
        {
            translate = this.TranslatePoint(new Point(0, -yloc), _parentCanvas);

            // coordinate is beyond the position of the parent canvas
            if (translate.Y < 0)  // this is true the first time it's run
                yloc = 0;
            else
                yloc = -yloc;
        }

        translate = this.TranslatePoint(new Point(_shape.Width, 0), _parentCanvas);

        // textbox is in right edge of the canvas
        if (translate.X > _parentCanvas.ActualWidth) 
        {
            double pos = translate.X - _parentCanvas.ActualWidth;

            translate = this.TranslatePoint(new Point(-pos,0), _parentCanvas);

            if (translate.X < 0)
                xloc = 0;
            else
                xloc = translate.X;
        }

        return new Point(xloc, yloc);
    }

    protected override Size MeasureOverride(Size constraint)
    {
        Size myConstraint = new Size(_shape.Width, _shape.Height);
        _container.Measure(myConstraint);

        return _container.DesiredSize;
    }

    protected override Visual GetVisualChild(int index)
    {
        return _visualChildren[index];
    }

    protected override int VisualChildrenCount
    {
        get
        {
            return _visualChildren.Count;
        }
    }
}

I am trying to position an Adorner depending on the dimensions of the parent of the adorned element. For example, I have a textbox. I want to adorn this textbox so it looks something like this:

how the adorner needs to be placed http://img707.imageshack.us/img707/9840/fig1.png

A textbox is placed in a canvas object and if there is enough space available then place the adorner (semi transparent rounded square) in line with the bottom edge of the textbox. The adorner is initiated when the user clicks on the textbox.

Currently the canvas and its contents (the textbox) is hosted in a WinForms form - so the WPF is handled by the ElementHost control.

But when I run my code, when the textbox is clicked for the first time it displays the adorner aligned to the top edge of the textbox (see figure below). After that it positions itself correctly (like the figure above) Does anyone know why this might be?

how adorner is positions http://img14.imageshack.us/img14/4766/fig2v.png

I have pasted the code for this below:

TextBoxAdorner.cs - this the adorner logic

public class TextBoxAdorner : Adorner
{
    private TextBox _adornedElement;
    private VisualCollection _visualChildren;
    private Rectangle _shape;
    private Canvas _container;
    private Canvas _parentCanvas;

    public TextBoxAdorner(UIElement adornedElement, Canvas parentCanvas)
        : base(adornedElement)
    {
        _adornedElement = (TextBox)adornedElement;
        _parentCanvas = parentCanvas;
        _visualChildren = new VisualCollection(this);

        _container = new Canvas();

        _shape = new Rectangle();
        _shape.Width = 100;
        _shape.Height = 80;
        _shape.Fill = Brushes.Blue;
        _shape.Opacity = 0.5;

        _container.Children.Add(_shape);

        _visualChildren.Add(_container);
    }

    protected override Size ArrangeOverride(Size finalSize)
    {
        Point location = GetLocation();
        _container.Arrange(new Rect(location, finalSize));

        return finalSize;
    }

    private Point GetLocation()
    {
        if (_parentCanvas == null)
            return new Point(0, 0);

        Point translate;
        double xloc = 0, yloc = _shape.Height - _adornedElement.ActualHeight;

        if (yloc < 0) // textbox is bigger than the shape
            yloc = 0;
        else
        {
            translate = this.TranslatePoint(new Point(0, -yloc), _parentCanvas);

            // coordinate is beyond the position of the parent canvas
            if (translate.Y < 0)  // this is true the first time it's run
                yloc = 0;
            else
                yloc = -yloc;
        }

        translate = this.TranslatePoint(new Point(_shape.Width, 0), _parentCanvas);

        // textbox is in right edge of the canvas
        if (translate.X > _parentCanvas.ActualWidth) 
        {
            double pos = translate.X - _parentCanvas.ActualWidth;

            translate = this.TranslatePoint(new Point(-pos,0), _parentCanvas);

            if (translate.X < 0)
                xloc = 0;
            else
                xloc = translate.X;
        }

        return new Point(xloc, yloc);
    }

    protected override Size MeasureOverride(Size constraint)
    {
        Size myConstraint = new Size(_shape.Width, _shape.Height);
        _container.Measure(myConstraint);

        return _container.DesiredSize;
    }

    protected override Visual GetVisualChild(int index)
    {
        return _visualChildren[index];
    }

    protected override int VisualChildrenCount
    {
        get
        {
            return _visualChildren.Count;
        }
    }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

听风吹 2024-08-23 15:55:30

装饰器的位置是相对于被装饰元素的。如果您希望它位于对象的顶部,则 yloc 的值应该为负数。但是,您的代码也考虑了画布的边界。如果上面的矩形没有足够的空间,它会将其放在下面。尝试将文本框放置在画布中稍低的位置。

The position of an Adorner is relative to the adorned element. If you want it to be to the top of your object, the value of yloc should be negative. However, the code you have also regards the boundaries of the Canvas. If there's not enough place for the rectangle above, it would put it below. Trying placing the TextBox a little lower in the Canvas.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文