Bagikan melalui


Inisialisasi untuk Elemen Objek Tidak dalam Pohon Objek

Beberapa aspek inisialisasi Windows Presentation Foundation (WPF) ditangguhkan ke proses yang biasanya mengandalkan apakah elemen tersebut terhubung dengan pohon logis atau pohon visual. Topik ini menjelaskan langkah-langkah yang mungkin diperlukan untuk menginisialisasi elemen yang tidak terhubung ke salah satu pohon.

Elemen dan Pohon Logis

Ketika Anda membuat instans kelas Windows Presentation Foundation (WPF) dalam kode, Anda harus menyadari bahwa beberapa aspek inisialisasi objek untuk kelas Windows Presentation Foundation (WPF) sengaja bukan bagian dari kode yang dijalankan saat memanggil konstruktor kelas. Terutama untuk kelas kontrol, sebagian besar representasi visual kontrol tersebut tidak ditentukan oleh konstruktor. Sebaliknya, representasi visual ditentukan oleh templat kontrol. Templat berpotensi berasal dari berbagai sumber, tetapi paling sering templat diperoleh dari gaya tema. Templat secara efektif berfungsi sebagai pengikatan yang terlambat; templat yang diperlukan tidak ditempelkan pada kontrol terkait sampai kontrol siap untuk diatur layoutnya. Dan kontrol tidak siap untuk tata letak sampai dilampirkan ke pohon logis yang terhubung ke permukaan penyajian di akar. Elemen tingkat akar itulah yang memulai penyajian semua elemen turunannya seperti yang didefinisikan dalam pohon logis.

Pohon visual juga berpartisipasi dalam proses ini. Elemen yang merupakan bagian dari pohon visual melalui templat juga tidak sepenuhnya dibuat sampai tersambung.

Konsekuensi dari perilaku ini adalah bahwa operasi tertentu yang mengandalkan karakteristik visual elemen yang telah selesai memerlukan langkah tambahan. Contohnya adalah jika Anda mencoba untuk mendapatkan karakteristik visual kelas yang dibangun tetapi belum melekat pada pohon. Misalnya, jika Anda ingin memanggil Render pada RenderTargetBitmap dan visual yang Anda berikan adalah elemen yang tidak tersambung ke pohon, elemen tersebut belum lengkap secara visual sampai langkah-langkah inisialisasi tambahan selesai.

Menggunakan BeginInit dan EndInit untuk Menginisialisasi Elemen

Berbagai kelas dalam WPF mengimplementasikan antarmuka ISupportInitialize. Anda menggunakan metode BeginInit dan EndInit antarmuka untuk menunjukkan wilayah dalam kode Anda yang berisi langkah-langkah inisialisasi (seperti mengatur nilai properti yang memengaruhi penyajian). Setelah EndInit dipanggil secara berurutan, sistem tata letak dapat memproses elemen dan mulai mencari gaya implisit.

Jika elemen yang sedang Anda atur propertinya merupakan kelas turunan dari FrameworkElement atau FrameworkContentElement, maka Anda dapat memanggil versi kelas BeginInit dan EndInit daripada melakukan casting ke ISupportInitialize.

Contoh Kode

Contoh berikut adalah kode sampel untuk aplikasi konsol yang menggunakan API perenderan dan bagian XamlReader.Load(Stream) dari file XAML yang tidak terikat untuk mengilustrasikan penempatan BeginInit dan EndInit yang benar di sekitar panggilan API lain yang mengatur properti yang mempengaruhi perenderan.

Contoh ini hanya mengilustrasikan fungsi utama. Fungsi Rasterize dan Save (tidak ditampilkan) adalah fungsi utilitas yang mengurus pemrosesan gambar dan 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

Lihat juga