Compartir a través de


Inicialización de elementos de objeto no incluidos en un árbol de objetos

Algunos aspectos de la inicialización de Windows Presentation Foundation (WPF) se difieren a los procesos que suelen basarse en que ese elemento esté conectado al árbol lógico o al árbol visual. En este tema se describen las operaciones que pueden ser necesarias para inicializar un elemento que no está conectado a ninguno de estos árboles.

Este tema contiene las secciones siguientes.

  • Elementos y el árbol lógico
  • Temas relacionados

Elementos y el árbol lógico

Al crear una instancia de una clase Windows Presentation Foundation (WPF) en código, debe tener en cuenta que hay varios aspectos de la inicialización de objetos para una clase de Windows Presentation Foundation (WPF) que deliberadamente no forman parte del código que se ejecuta al llamar al constructor de la clase. Concretamente para una clase de control, el constructor no define la mayoría de la representación visual de ese control. En cambio, la representación visual la define la plantilla del control. La plantilla puede proceder de varios orígenes, pero lo más habitual es que se obtenga de los estilos de tema. En la práctica, el enlace de las plantillas se efectúa en tiempo de ejecución; la plantilla necesaria no se asocia al control correspondiente hasta que éste está para el diseño. Y el control no está listo para el diseño hasta que se asocia a un árbol lógico conectado a una superficie de la representación en la raíz. Este elemento del nivel de la raíz es el que inicia la representación de todos sus elementos secundarios definidos en el árbol lógico.

El árbol visual también participa en este proceso. Las instancias de los elementos que forman parte del árbol visual a través de las plantillas tampoco se crean totalmente hasta que se conectan.

Como consecuencia de este comportamiento, algunas operaciones que se basan en las características visuales completadas de un elemento requieren operaciones adicionales. Un ejemplo de ello es el caso en que se intenta obtener las características visuales de una clase que se construyó pero todavía no está asociada a un árbol. Por ejemplo, si desea llamar a Render para RenderTargetBitmap y el objeto visual que se pasa es un elemento no conectado a un árbol, ese elemento no estará completo visualmente hasta que se completen las operaciones de inicialización adicionales.

Utilizar BeginInit y EndInit para inicializar el elemento

Varias clases de WPF implementan la interfaz ISupportInitialize. Los métodos BeginInit y EndInit de la interfaz se utilizan para indicar una zona del código que contiene las operaciones de inicialización (tales como establecer los valores de propiedad que afectan a la representación). Una vez se llama a EndInit en la secuencia, el sistema del diseño puede procesar el elemento y comenzar a buscar un estilo implícito.

Si el elemento cuyas propiedades se establecen es una clase derivada de FrameworkElement o de FrameworkContentElement, entonces puede llamar a las versiones de las clases BeginInit y EndInit, en lugar de efectuar una conversión a ISupportInitialize.

Código de ejemplo

A continuación se muestra un ejemplo de código para una aplicación de consola que utiliza APIs de representación y el método XamlReader.Load(Stream) de un archivo XAML dinámico para mostrar la posición correcta de BeginInit y EndInit en torno a otras llamadas de API que ajustan las propiedades que afectan a la representación.

En el ejemplo sólo se muestra la función principal. Las funciones Rasterize y Save (no mostradas) son funciones de utilidad que se encargan del procesamiento de imágenes y de E/S.

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

Vea también

Conceptos

Árboles en WPF

Información general sobre la representación de gráficos en WPF

Información general sobre XAML (WPF)