【问题标题】:How can I calculate the logical width of WPF visual element?如何计算 WPF 视觉元素的逻辑宽度?
【发布时间】:2010-11-22 03:31:49
【问题描述】:

在 WPF 渲染视觉元素之前,我需要计算它的逻辑宽度。

为了解释的简单,我会说这个视觉元素很可能是一个多边形对象。它可能是别的东西,但多边形可以很容易地可视化。

所以 XAML 可能看起来像这样:

<Window x:Class="MyCLRNamespace.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
</Window>

代码隐藏可能看起来像这样:

namespace MyCLRNamespace
{
    public partial class Window1 : Window
    {
        public Window1()
        {
            InitializeComponent();

            //This is the visual element in question. It's a simple triangle.
            Polygon MyPolygon = new Polygon();
            MyPolygon.Points = new PointCollection {    new Point(100, 0),
                                                        new Point(200, 200),
                                                        new Point(0, 200)   };
            double PolyWidth = MyPolygon.Width;
            /* In this case, PolyWidth will be set to double.NaN, since
               MyPolygon.Width is never set.

               I need to be able to calculate the logical width of an element,
               unrelated to the WPF rendering system. This means that I can't
               rely on FrameworkElement.ActualWidth to calculate the width for
               me. I need to be able to look at the MyPolygon object (or its
               content) and figure out that it is set to a visual element that
               should be 200dips wide before any parent element applies any
               operations to it - regardless of what MyPolygon.Width may or may
               not be set to.

               It should also be noted that I don't have to rely on
               FrameorkElement. If there are more generic alternatives, such as
               the UIElement or Visual classes, I'd prefer to use those instead
               of the more specific FrameworkElement. The more robust I can make
               this, the better. */
        }
    }
}

【问题讨论】:

    标签: c# .net wpf .net-3.5 width


    【解决方案1】:

    唉,我们又见面了。如果你能告诉我们更多关于你想要达到的目标,也许会有所帮助。 WPF 实际上使用与设备无关的单位来表示其大小,这就是 ActualWidth (来自 MSDN):

    元素的宽度,以与设备无关的单位(每单位 1/96 英寸)表示的值。默认值为 0(零)。

    如果您发现 ActualWidth 值的可用性异常,您可能需要监听 SizeChanged 事件或覆盖 OnRenderSizeChanged。我认为两者有细微的不同,但我不确定这些差异是什么。

    【讨论】:

    • 我倾向于在代码 cmets 中进行大部分解释。也许我不应该那样做......无论如何,ActualWidth 只有在你想要某些东西的渲染宽度时才有用。我想要逻辑宽度。我想要的值是 XAML 中多边形声明的“200”值。 ActualWidth 不能保证等于元素的声明宽度,在这种情况下,我什至没有设置 regualar width 属性。但如果不存在其他因素,该多边形实际上将是 200 度宽。这就是我需要我的程序能够动态计算的值。
    • 对了,那么什么情况下ActualWidth不是200呢?恕我直言,唯一不是这种情况的情况是它的父级以某种方式剪辑它。您是否尝试过调试代码以询问 ActualWidth 的值?
    • 在多边形尚未渲染的情况下。我想为这个场景做一个代码示例,但是如果不发布我的整个项目,我想不出任何好的方法来展示它。这太令人困惑了。
    • 对,在这种情况下,您需要修改应用程序的其余部分,以等待他们找出控件的大小。这很痛苦,但没有其他方法可以找出渲染的大小。这是有道理的,因为框架在必须渲染控件之前根本不对控件做任何事情。
    • 我编辑了我的问题以反映这种情况。最后并没有那么混乱,我想……而且我相信我想出了如何实现我的目标。如果您想跟进我的发现,请参阅我的回答。
    【解决方案2】:

    System.Windows.UIElement 类提供了在任何父子元素关系之外测量自身的方法。

    在尝试使用测量值之前检查 IsMeasureValid 至关重要。如果 IsMeasureValid 为 false,则需要手动调用 UIElement.Measure() 方法以确保对元素及其内容进行最新测量。如果 IsMeasureValid 为真,那么再次测量不会有什么坏处。它只会覆盖它存储的任何以前的测量值。

    如果您想要元素的实体测量没有外部限制,请提供无限大小作为 UIElement.Measure() 方法的 availableSize 参数。

    UIElement.Measure() 方法会将元素的测量大小存储在 UIElement.DesiredSize 属性中。我不认为这对 WPF 渲染系统有任何负面影响,因为任何父元素都保证在渲染之前使用自己的可用大小限制重新测量元素。这可能会影响屏幕上元素的最终大小,但不会影响应用父子约束之前 元素的原始所需大小。

    namespace MyCLRNamespace
    {
        public partial class Window1 : Window
        {
            public Window1()
            {
                InitializeComponent();
    
                Polygon MyPolygon = new Polygon();
                MyPolygon.Points = new PointCollection {    new Point(100, 0),
                                                            new Point(200, 200),
                                                            new Point(0, 200)   };
                //if (MyPolygon.IsMeasureValid == false)
                    MyPolygon.Measure(new Size( double.PositiveInfinity,
                                                double.PositiveInfinity));
    
                double PolyWidth = MyPolygon.DesiredSize.Width;
            }
        }
    }
    

    【讨论】:

    • 如果调用 measure 后得到 0,0,您可以在可视树中的元素正上方放置一个容器元素并测量该元素。也许不是最好的解决方案,但如果你绝望,它会起作用。
    猜你喜欢
    • 2016-08-16
    • 2015-12-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-11-14
    • 1970-01-01
    • 2011-03-03
    • 1970-01-01
    相关资源
    最近更新 更多