Мне нужно вычислить логическую ширину визуального элемента, прежде чем он будет визуализирован 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 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. */
}
}
}
Класс System.Windows.UIElement предоставляет методы для измерения себя вне любых отношений между родительскими и дочерними элементами.
Очень важно, чтобы вы проверяли IsMeasureValid, прежде чем пытаться использовать измеренные значения. Если IsMeasureValid является ложным, вам необходимо вручную вызвать метод UIElement.Measure(), чтобы убедиться, что у вас есть последнее измерение элемента и его содержимого. Если IsMeasureValid истинно, это не повредит для измерения снова. Он просто перезапишет все предыдущие измерения, которые он сохранил.
Если требуется твердое измерение элемента без внешних ограничений, укажите бесконечный размер как параметр доступного параметра к методу UIElement.Measure().
Метод 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;
}
}
}
Увы, мы снова встречаемся. Возможно, это поможет, если вы расскажете нам больше о том, чего вы пытаетесь достичь. WPF фактически использует независимые от устройства единицы для своих размеров и то, что ActualWidth (из MSDN):
Ширина элемента в качестве значения в устройствах, не зависящих от устройства (1/96-й дюйм на единицу). Значение по умолчанию равно 0 (ноль).
Если вы видите странность в доступности значений ActualWidth, вы можете прослушать событие SizeChanged
или переопределить OnRenderSizeChanged
. Я думаю, что эти два тонко отличаются друг от друга, но я не уверен, каковы эти различия.