Инициализация для элементов типа Object вне дерева объектов

Некоторые аспекты инициализации Windows Presentation Foundation (WPF) откладываются для процессов, которые обычно полагаются на то, что элемент подключен либо к логическому дереву или визуальному дерево. В этом разделе описываются действия, необходимые для инициализации элемента, который не подключен ни к одному из деревьев.

В этом разделе содержатся следующие подразделы.

  • Элементы и логическое дерево
  • Связанные разделы

Элементы и логическое дерево

При создании экземпляра класса Windows Presentation Foundation (WPF) в коде следует иметь в виду, что несколько аспектов инициализации объекта для класса Windows Presentation Foundation (WPF) преднамеренно не являются частью кода, выполняющегося при вызове конструктора класса. Большая часть визуального представления элемента управления, особенно для класса элемента управления, не определяется конструктором. Вместо этого визуальное представление определяется шаблоном элемента управления. Шаблон может быть получен из различных источников, но наиболее часто он берется из тематических стилей. Шаблоны фактически выполняют позднее связывание. Необходимый шаблон не присоединяется к элементу управления до тех пор, пока элемент управления не будет подготовлен для макета. А элемент управления не готов для макета до тех пор, пока он не будет присоединен к логическому дереву, которое подключается к отрисовываемой поверхности в корневом элементе. Это элемент корневого уровня, который инициирует отрисовку всех дочерних элементов, как определено в логическом дереве.

Визуальное дерево также участвует в этом процессе. Элементы, которые с помощью шаблонов являются частью визуального дерева, также полностью не создаются до тех пор, пока не произойдет подключение.

Последствием этого является то, что для определенных операций, зависящих от завершенных визуальных характеристик элемента, требуется выполнение дополнительных действий. Примером является попытка получить визуальные характеристики класса, который был создан, но еще не присоединен к дереву. Например, если необходимо вызвать Render на RenderTargetBitmap и передаваемый визуальный элемент не подключен к дереву, то визуально этот элемент остается незавершенным, пока не будут выполнены дополнительные шаги инициализации.

Использование BeginInit и EndInit для инициализации элемента

В WPF интерфейс ISupportInitialize реализуют различные классы. Для обозначения области кода, содержащей действия для инициализации (такие как установка значений свойств, влияющих на отрисовку), можно использовать методы BeginInit и EndInit интерфейса. После вызова EndInit в последовательности система разметки может обработать элемент и начать поиск неявного стиля.

Если элемент, для которого устанавливаются свойства, является производным классом FrameworkElement или FrameworkContentElement, то можно вызвать версии класса BeginInit и EndInit вместо приведения к ISupportInitialize.

Пример кода

В следующем примере представлен образец кода консольного приложения, использующего отрисовку APIs и XamlReader.Load(Stream) свободного файла XAML для иллюстрации правильного размещения BeginInit и EndInit относительно других вызовов API, влияющих на отображение.

В данном примере иллюстрируется только основная функция. Функции Rasterize и Save (не отображены) являются служебными функциями, которые отвечают за обработку изображения и ввод-вывод.

        <STAThread>
        Shared Sub Main(ByVal args() As String)
            Dim e As UIElement
            Dim _file As String = Directory.GetCurrentDirectory() & "\starting.xaml"
            Using stream As Stream = File.Open(_file, FileMode.Open)
                ' loading files from current directory, project settings take care of copying the file
                Dim pc As New ParserContext()
                pc.BaseUri = New Uri(_file, UriKind.Absolute)
                e = CType(XamlReader.Load(stream, pc), UIElement)
            End Using

            Dim paperSize As New Size(8.5 * 96, 11 * 96)
            e.Measure(paperSize)
            e.Arrange(New Rect(paperSize))
            e.UpdateLayout()

'            
'             *   Render effect at normal dpi, indicator is the original RED rectangle
'             
            Dim image1 As RenderTargetBitmap = Rasterize(e, paperSize.Width, paperSize.Height, 96, 96)
            Save(image1, "render1.png")

            Dim b As New Button()
            b.BeginInit()
            b.Background = Brushes.Blue
            b.Height = 200
            b.Width = b.Height
            b.EndInit()
            b.Measure(paperSize)
            b.Arrange(New Rect(paperSize))
            b.UpdateLayout()

            ' now render the altered version, with the element built up and initialized

            Dim image2 As RenderTargetBitmap = Rasterize(b, paperSize.Width, paperSize.Height, 96, 96)
            Save(image2, "render2.png")
        End Sub
[STAThread]
static void Main(string[] args)
{
    UIElement e;
    string file = Directory.GetCurrentDirectory() + "\\starting.xaml";
    using (Stream stream = File.Open(file, FileMode.Open))
    {
        // loading files from current directory, project settings take care of copying the file
        ParserContext pc = new ParserContext();
        pc.BaseUri = new Uri(file, UriKind.Absolute);
        e = (UIElement)XamlReader.Load(stream, pc);
    }

    Size paperSize = new Size(8.5 * 96, 11 * 96);
    e.Measure(paperSize);
    e.Arrange(new Rect(paperSize));
    e.UpdateLayout();

    /*
     *   Render effect at normal dpi, indicator is the original RED rectangle
     */
    RenderTargetBitmap image1 = Rasterize(e, paperSize.Width, paperSize.Height, 96, 96);
    Save(image1, "render1.png");

    Button b = new Button();
    b.BeginInit();
    b.Background = Brushes.Blue;
    b.Width = b.Height = 200;
    b.EndInit();
    b.Measure(paperSize);
    b.Arrange(new Rect(paperSize));
    b.UpdateLayout();

    // now render the altered version, with the element built up and initialized

    RenderTargetBitmap image2 = Rasterize(b, paperSize.Width, paperSize.Height, 96, 96);
    Save(image2, "render2.png");
}

См. также

Основные понятия

Деревья в WPF

Общие сведения об отрисовке графики в WPF

Общие сведения о языке XAML (WPF)