如何计算WPF视觉元素的逻辑宽度?

时间:2009-08-24 01:07:02

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

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

为了简化说明,我会说这个视觉元素很可能是一个Polygon对象。它可能是其他东西,但Polygon使其易于可视化。

所以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. */
        }
    }
}

2 个答案:

答案 0 :(得分:11)

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;
        }
    }
}

答案 1 :(得分:0)

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

  

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

如果您发现ActualWidth值的可用性很奇怪,您可能希望收听SizeChanged事件或覆盖OnRenderSizeChanged。我认为这两者略有不同,但我不确定这些差异是什么。