Initialisierung für Objektelemente außerhalb einer Objektstruktur

Einige Aspekte der WPF-Initialisierung (Windows Presentation Foundation) werden für Prozesse zurückgestellt, die sich in der Regel darauf verlassen, dass das Element entweder mit einer logischen Struktur oder einer visuellen Struktur verbunden wird. Dieses Thema beschreibt die Schritte, die möglicherweise erforderlich sind, um ein Element zu initialisieren, das nicht mit einer dieser Strukturen verbunden ist.

Elemente und die logische Struktur

Beim Erstellen einer Instanz einer WPF-Klasse (Windows Presentation Foundation) im Code sollten Sie bedenken, dass verschiedene Aspekte der Objektinitialisierung für eine WPF-Klasse absichtlich kein Teil des Codes sind, der beim Aufrufen des Klassenkonstruktors ausgeführt wird. Insbesondere für eine Steuerelementklasse ist der Großteil der visuellen Darstellung dieses Steuerelements nicht vom Konstruktor definiert. Stattdessen wird die visuelle Darstellung durch die Vorlage des Steuerelements definiert. Die Vorlage stammt möglicherweise aus einer Vielzahl von Quellen, ganz oft wird die Vorlage jedoch aus Designstilen. Vorlagen sind eine effektive späte Bindung; die erforderliche Vorlage wird dem fraglichen Steuerelement nicht angefügt, solange das Steuerelement nicht für Layout bereit ist. Das Steuerelement ist so lange nicht für Layout bereit, bis es einer logischen Struktur angefügt wird, die eine Verbindung mit einer Renderingoberfläche auf der Stammebene eingeht. Es ist das Rootebenenelement, dass das Rendering aller untergeordneten Elemente initiiert, so wie in der logischen Struktur definiert.

Die visuelle Struktur beteiligt sich auch an diesem Prozess. Elemente, die Teil der visuellen Struktur durch die Vorlagen sind, werden ebenfalls nicht vollständig instanziiert, bis sie verbunden sind.

Die Folgen dieses Verhaltens sind, dass bestimmte Vorgänge, die auf den fertigen visuellen Merkmalen eines Elements basieren, zusätzliche Schritte erfordern. Ein Beispiel ist, wenn Sie versuchen, visuelle Merkmale einer Klasse abzurufen, die erstellt aber noch nicht einer Struktur angefügt wurde. Wenn Sie z. B. Render für RenderTargetBitmap aufrufen möchten und das übergebene visuelle Element nicht mit einer Struktur verbunden ist, ist dieses Element nicht visuell vollständig, bis zusätzliche Initialisierungsschritte abgeschlossen wurden.

Verwenden von BeginInit und EndInit zum Initialisieren des Elements

Verschiedene Klassen in WPF implementieren die ISupportInitialize-Schnittstelle. Sie verwenden die BeginInit- und EndInit-Methoden der Schnittstelle, um einen Bereich in Ihrem Code zu kennzeichnen, der Initialisierungsschritte enthält (z. B. das Festlegen von Eigenschaftswerten, die das Rendering beeinflussen). Nachdem EndInit in der Sequenz aufgerufen wurde, kann das Layoutsystem das Element verarbeiten und beginnen, nach einer impliziten Formatvorlage zu suchen.

Wenn das Element, für das Sie Eigenschaften festlegen, eine von FrameworkElement oder FrameworkContentElement abgeleitete Klasse ist, können Sie die Klassenversionen von BeginInit und EndInit aufrufen, anstatt in ISupportInitialize umzuwandeln.

Beispielcode

Das folgende Beispiel ist Beispielcode für eine Konsolenanwendung, die Rendering-APIs und XamlReader.Load(Stream) einer XAML-Loose-Datei verwendet, um die richtige Platzierung von BeginInit und EndInit um andere API-Aufrufe herum zu veranschaulichen, die Eigenschaften anpassen, die das Rendering beeinflussen.

Das Beispiel veranschaulicht nur die Hauptfunktion. Die Funktionen Rasterize und Save (nicht dargestellt) sind Hilfsfunktionen, die die Verarbeitung und E/A erledigen.

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

Weitere Informationen