Delen via


Initialisatie voor objectelementen die niet in een objectstructuur zijn

Sommige aspecten van WPF-initialisatie (Windows Presentation Foundation) worden uitgesteld naar processen die doorgaans afhankelijk zijn van dat element dat is verbonden met de logische structuur of visuele structuur. In dit onderwerp worden de stappen beschreven die mogelijk nodig zijn om een element te initialiseren dat niet is verbonden met een van beide boomstructuuren.

Elementen en de logische structuur

Wanneer u een exemplaar van een WPF-klasse (Windows Presentation Foundation) in code maakt, moet u er rekening mee houden dat verschillende aspecten van objectinitialisatie voor een WPF-klasse (Windows Presentation Foundation) bewust geen deel uitmaken van de code die wordt uitgevoerd bij het aanroepen van de klasseconstructor. Met name voor een besturingsklasse wordt de meeste visuele weergave van dat besturingselement niet gedefinieerd door de constructor. In plaats daarvan wordt de visuele weergave gedefinieerd door de sjabloon van het besturingselement. De sjabloon is mogelijk afkomstig van verschillende bronnen, maar meestal wordt de sjabloon verkregen uit themastijlen. Sjablonen worden effectief laat gebonden; de benodigde sjabloon is niet gekoppeld aan het desbetreffende besturingselement totdat het besturingselement gereed is voor opmaak. Het besturingselement is pas gereed voor opmaak wanneer het is gekoppeld aan een logische boomstructuur die verbinding maakt met een renderoppervlak bij de wortel. Het is dat element op hoofdniveau dat het weergeven van al zijn onderliggende elementen initieert zoals gedefinieerd is in de logische boom.

De visuele boom neemt ook deel aan dit proces. Elementen die deel uitmaken van de visuele structuur via de sjablonen, worden ook niet volledig geïnstantieerd totdat verbinding is gemaakt.

De gevolgen van dit gedrag zijn dat bepaalde bewerkingen die afhankelijk zijn van de voltooide visuele kenmerken van een element extra stappen vereisen. Een voorbeeld is wanneer u de visuele kenmerken wilt ophalen van een klasse die is gemaakt maar nog niet is gekoppeld aan een boom. Als u bijvoorbeeld Render wilt aanroepen op een RenderTargetBitmap en de visual die u doorgeeft een element is dat niet is verbonden met een boomstructuur, is dat element pas visueel voltooid als er aanvullende initialisatiestappen zijn voltooid.

BeginInit en EndInit gebruiken om het element te initialiseren

Verschillende klassen in WPF implementeren de ISupportInitialize interface. U gebruikt de BeginInit en EndInit methoden van de interface om een regio in uw code aan te geven die initialisatiestappen bevat (zoals het instellen van eigenschapswaarden die van invloed zijn op rendering). Nadat EndInit in de reeks is aangeroepen, kan het indelingssysteem het element verwerken en op zoek gaan naar een impliciete stijl.

Als het element waarop u eigenschappen instelt een FrameworkElement of FrameworkContentElement afgeleide klasse is, kunt u de klasseversies van BeginInit en EndInit aanroepen in plaats van naar ISupportInitializete gieten.

Voorbeeldcode

Het volgende voorbeeld is voorbeeldcode voor een consoletoepassing die gebruikmaakt van rendering-API's en XamlReader.Load(Stream) van een los XAML-bestand om de juiste plaatsing van BeginInit en EndInit rond andere API-aanroepen te illustreren waarmee eigenschappen worden aangepast die van invloed zijn op rendering.

In het voorbeeld ziet u alleen de hoofdfunctie. De functies Rasterize en Save (niet weergegeven) zijn hulpprogrammafuncties die zorgen voor beeldverwerking en IO.

[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

Zie ook