Sdílet prostřednictvím


Inicializace prvků objektů, které nejsou ve stromu objektů

Některé aspekty inicializace WPF (Windows Presentation Foundation) jsou odloženy na procesy, které obvykle spoléhají na to, že daný prvek je připojený k logickému stromu nebo vizuálnímu stromu. Toto téma popisuje kroky, které mohou být nezbytné k inicializaci prvku, který není připojen k některému stromu.

Prvky a logický strom

Při vytváření instance třídy Windows Presentation Foundation (WPF) v kódu byste měli vědět, že několik aspektů inicializace objektu pro třídu Windows Presentation Foundation (WPF) nejsou záměrně součástí kódu, který se spouští při volání konstruktoru třídy. Zejména pro třídu ovládacího prvku, většina vizuální reprezentace tohoto ovládacího prvku není definována konstruktorem. Místo toho je vizuální reprezentace definována šablonou ovládacího prvku. Šablona může pocházet z různých zdrojů, ale nejčastěji se šablona získává ze stylů motivu. Šablony jsou efektivně pozdě vázané; potřebná šablona není připojena k ovládacímu prvku, dokud není ovládací prvek připravený k uspořádání. A ovládací prvek není připravený k rozložení, dokud není připojen k logickému stromu, který se připojí k vykreslovací ploše v kořeni. Kořenový prvek je tím, který iniciuje vykreslování všech svých podřízených elementů, jak jsou definovány v logickém stromu.

Vizuální strom se také účastní tohoto procesu. Prvky, které jsou součástí vizuálního stromu prostřednictvím šablon, také nejsou plně instancovány, dokud nejsou připojeny.

Důsledky tohoto chování jsou, že určité operace, které spoléhají na dokončené vizuální charakteristiky prvku, vyžadují další kroky. Příkladem je, že se pokoušíte získat vizuální charakteristiky třídy, která byla vytvořena, ale ještě není připojena ke stromu. Pokud například chcete volat Render na RenderTargetBitmap a prvek vizuálu, který předáváte, není připojený ke stromu, není tento prvek vizuálně dokončen, dokud nejsou dokončeny další kroky inicializace.

Inicializace elementu pomocí BeginInit a EndInit

Různé třídy v WPF implementují ISupportInitialize rozhraní. Pomocí BeginInit a EndInit metod rozhraní označíte oblast v kódu, která obsahuje kroky inicializace (například nastavení hodnot vlastností, které ovlivňují vykreslování). Po zavolání EndInit v sekvenci může systém rozložení zpracovat prvek a začít hledat implicitní styl.

Pokud je prvek, na který nastavujete vlastnosti, odvozenou třídou FrameworkElement nebo FrameworkContentElement, můžete volat verze tříd BeginInit a EndInit namísto přetypování na ISupportInitialize.

Ukázkový kód

Následující příklad je ukázkový kód pro konzolovou aplikaci, která používá vykreslovací rozhraní API a XamlReader.Load(Stream) volného souboru XAML k ilustraci správného umístění BeginInit a EndInit kolem jiných volání rozhraní API, která upravují vlastnosti, které ovlivňují vykreslování.

Příklad znázorňuje pouze hlavní funkci. Funkce Rasterize a Save (nezobrazují se) jsou utility funkce, které se starají o zpracování obrázků a vstupně-výstupní operace.

[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

Viz také

  • stromy v WPF
  • přehled vykreslování grafiky WPF
  • XAML v WPF