Как рассчитать логическую ширину визуального элемента WPF?

2

Мне нужно вычислить логическую ширину визуального элемента, прежде чем он будет визуализирован 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. */
        }
    }
}
Теги:
wpf
width
.net-3.5

2 ответа

10
Лучший ответ

Класс 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;
        }
    }
}
  • 0
    Если после вызова меры вы получите 0,0, вы можете поместить элемент контейнера непосредственно над элементом в визуальном дереве и измерить его. Возможно, не лучшее решение, но оно работает, если вы в отчаянии.
0

Увы, мы снова встречаемся. Возможно, это поможет, если вы расскажете нам больше о том, чего вы пытаетесь достичь. WPF фактически использует независимые от устройства единицы для своих размеров и то, что ActualWidth (из MSDN):

Ширина элемента в качестве значения в устройствах, не зависящих от устройства (1/96-й дюйм на единицу). Значение по умолчанию равно 0 (ноль).

Если вы видите странность в доступности значений ActualWidth, вы можете прослушать событие SizeChanged или переопределить OnRenderSizeChanged. Я думаю, что эти два тонко отличаются друг от друга, но я не уверен, каковы эти различия.

  • 0
    Я склонен делать большинство объяснений в комментариях к коду. Может быть, я не должен этого делать ... Во всяком случае, ActualWidth полезен, только если вы хотите визуализировать ширину чего-либо. Я хочу логическую ширину. Значение, которое я хочу, - это значение «200» из объявления полигона в XAML. Фактическая ширина не гарантируется равной объявленной ширине элемента, и в этом случае я даже не устанавливаю свойство обычной ширины. Но на самом деле многоугольник будет иметь ширину 200 провалов, если нет других факторов. Это значение, которое мне нужно, чтобы моя программа могла рассчитывать динамически.
  • 0
    Итак, при каких обстоятельствах ActualWidth не 200? ИМХО, единственный случай, когда этого не случится, - это когда его родитель каким-то образом обрезает его. Вы пытались отладить код для запроса значения ActualWidth?
Показать ещё 3 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню