Namescope pada WPF XAML
Namescope XAML adalah konsep yang mengidentifikasi objek yang ditentukan dalam XAML. Nama dalam namescope XAML dapat digunakan untuk membangun hubungan antara nama objek yang ditentukan XAML dan instansnya yang setara di pohon objek. Biasanya, namescope XAML dalam kode terkelola WPF dibuat saat memuat akar halaman XAML individual untuk aplikasi XAML. Namescope XAML sebagai objek pemrograman didefinisikan oleh antarmuka INameScope dan juga diimplementasikan oleh kelas praktis NameScope.
Namescope dalam Aplikasi XAML yang Dimuat
Dalam konteks pemrograman atau ilmu komputer yang lebih luas, konsep pemrograman sering kali mencakup prinsip pengidentifikasi atau nama unik yang dapat digunakan untuk mengakses objek. Untuk sistem yang menggunakan pengidentifikasi atau nama, namescope menentukan batas di mana proses atau teknik akan mencari jika suatu objek dengan nama tersebut diminta, atau batas di mana keunikan nama pengidentifikasi ditegakkan. Prinsip-prinsip umum ini berlaku untuk namescope XAML. Di WPF, namescope XAML dibuat pada elemen root untuk halaman XAML saat halaman dimuat. Setiap nama yang ditentukan dalam halaman XAML yang dimulai dari akar halaman ditambahkan ke namescope XAML yang bersangkutan.
Dalam WPF XAML, elemen yang merupakan elemen akar umum (seperti Page, dan Window) selalu mengontrol namescope XAML. Jika elemen seperti FrameworkElement atau FrameworkContentElement adalah elemen akar halaman dalam markup, prosesor XAML menambahkan akar Page secara implisit sehingga Page dapat menyediakan namescope XAML yang berfungsi.
Nota
Tindakan build WPF membuat cakupan nama XAML untuk produksi XAML meskipun tidak ada atribut Name
atau x:Name
yang ditentukan pada elemen apa pun dalam markup XAML.
Jika Anda mencoba menggunakan nama yang sama dua kali dalam ruang nama XAML apa pun, akan terjadi pengecualian. Untuk WPF XAML yang memiliki code-behind dan merupakan bagian dari aplikasi yang dikompilasi, pengecualian dilemparkan saat waktu pembuatan oleh proses pembangunan WPF, ketika membuat kelas hasil untuk halaman selama kompilasi markup awal. Untuk XAML yang tidak dikompilasi sebagai markup oleh tindakan build manapun, pengecualian terkait masalah namescope XAML mungkin muncul saat XAML dimuat. Desainer XAML mungkin juga mengantisipasi masalah namescope XAML pada waktu desain.
Menambahkan Objek ke Pohon Objek Runtime
Momen saat XAML diurai mewakili momen pada saat namescope WPF XAML dibuat dan ditentukan. Jika Anda menambahkan objek ke pohon objek pada titik waktu setelah XAML yang menghasilkan pohon tersebut diurai, nilai Name
atau x:Name
pada objek baru tidak secara otomatis memperbarui informasi dalam namescope XAML. Untuk menambahkan nama objek ke dalam namescope WPF XAML setelah XAML dimuat, Anda harus memanggil implementasi RegisterName yang sesuai pada objek yang menentukan namescope XAML, yang biasanya merupakan akar halaman XAML. Jika nama tidak terdaftar, objek yang ditambahkan tidak dapat direferensikan berdasarkan nama melalui metode seperti FindName, dan Anda tidak dapat menggunakan nama tersebut untuk penargetan animasi.
Skenario paling umum untuk pengembang aplikasi adalah Anda akan menggunakan RegisterName untuk mendaftarkan nama ke dalam namescope XAML pada akar halaman saat ini. RegisterName adalah bagian dari skenario penting untuk storyboard yang menargetkan objek untuk animasi. Untuk informasi selengkapnya, lihat Gambaran Umum Storyboards.
Jika Anda memanggil RegisterName pada objek selain objek yang menentukan namescope XAML, nama masih terdaftar ke namescope XAML tempat objek panggilan disimpan, seolah-olah Anda telah memanggil RegisterName pada objek pendefinisian namescope XAML.
Namescope XAML dalam Kode
Anda dapat membuat lalu menggunakan namescope XAML dalam kode. API dan konsep yang terlibat dalam pembuatan namescope XAML sama bahkan untuk penggunaan kode murni, karena prosesor XAML untuk WPF menggunakan API dan konsep ini ketika memproses XAML itu sendiri. Konsep dan API ada terutama untuk tujuan dapat menemukan objek berdasarkan nama dalam pohon objek yang biasanya didefinisikan sebagian atau seluruhnya dalam XAML.
Untuk aplikasi yang dibuat secara terprogram, dan bukan dari XAML yang dimuat, objek yang menentukan namescope XAML harus menerapkan INameScope, atau menjadi kelas turunan FrameworkElement atau FrameworkContentElement, untuk mendukung pembuatan namescope XAML pada instansnya.
Selain itu, untuk elemen apa pun yang tidak dimuat dan diproses oleh prosesor XAML, namescope XAML untuk objek tidak dibuat atau diinisialisasi secara default. Anda harus secara eksplisit membuat namescope XAML baru untuk objek apa pun yang ingin Anda daftarkan namanya kemudian. Untuk membuat namescope XAML, Anda memanggil metode SetNameScope statis. Tentukan objek yang akan memilikinya sebagai parameter dependencyObject
, dan panggilan konstruktor NameScope baru sebagai parameter value
.
Jika objek yang disediakan sebagai dependencyObject
untuk SetNameScope bukan implementasi INameScope, FrameworkElement atau FrameworkContentElement, memanggil RegisterName pada elemen turunan apa pun tidak akan berpengaruh. Jika Anda gagal membuat namescope XAML baru secara eksplisit, panggilan ke RegisterName akan menimbulkan pengecualian.
Untuk contoh penggunaan API namescope XAML dalam kode, lihat Menentukan Cakupan Nama.
Namescope XAML dalam Gaya dan Templat
Gaya dan templat di WPF menyediakan kemampuan untuk menggunakan kembali dan menerapkan kembali konten dengan cara yang mudah. Namun, gaya dan templat mungkin juga menyertakan elemen dengan nama XAML yang ditentukan pada tingkat templat. Templat yang sama mungkin digunakan beberapa kali dalam halaman. Untuk alasan ini, gaya dan templat menentukan namescope XAML mereka sendiri, terlepas dari lokasi apa pun di pohon objek tempat gaya atau templat diterapkan.
Pertimbangkan contoh berikut:
<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
>
<Page.Resources>
<ControlTemplate x:Key="MyButtonTemplate" TargetType="{x:Type Button}">
<Border BorderBrush="Red" Name="TheBorder" BorderThickness="2">
<ContentPresenter/>
</Border>
</ControlTemplate>
</Page.Resources>
<StackPanel>
<Button Template="{StaticResource MyButtonTemplate}">My first button</Button>
<Button Template="{StaticResource MyButtonTemplate}">My second button</Button>
</StackPanel>
</Page>
Di sini, templat yang sama diterapkan ke dua tombol yang berbeda. Jika templat tidak memiliki namescope XAML diskrit, nama TheBorder
yang digunakan dalam templat akan menyebabkan tabrakan nama di namescope XAML. Setiap instans templat memiliki namescope XAML sendiri, jadi dalam contoh ini setiap namescope XAML templat yang diinstansiasi akan berisi tepat satu nama.
Gaya juga mendefinisikan ruang lingkup nama XAML mereka sendiri, terutama agar bagian dari storyboard dapat diberi nama tertentu. Nama-nama ini memungkinkan kontrol perilaku tertentu yang akan menargetkan elemen nama tersebut, bahkan jika templat didefinisikan kembali sebagai bagian dari kustomisasi kontrol.
Karena adanya pemisahan namescope XAML, mencari elemen bernama dalam sebuah templat lebih sulit dibandingkan dengan mencari elemen bernama yang tidak terdapat dalam templat di halaman. Pertama-tama Anda perlu menentukan templat yang diterapkan, dengan mendapatkan nilai properti Template kontrol tempat templat diterapkan. Kemudian, Anda memanggil versi templat FindName, dengan meneruskan kontrol di mana templat diterapkan sebagai parameter kedua.
Jika Anda adalah penulis kontrol dan Anda membuat konvensi di mana elemen bernama tertentu dalam templat yang diterapkan adalah target untuk perilaku yang ditentukan oleh kontrol itu sendiri, Anda dapat menggunakan metode GetTemplateChild dari kode implementasi kontrol Anda. Metode GetTemplateChild dilindungi, jadi hanya pembuat kontrol yang memiliki akses ke metode tersebut.
Jika Anda bekerja dari dalam templat, dan perlu masuk ke namescope XAML tempat templat diterapkan, dapatkan nilai TemplatedParent, lalu panggil FindName di sana. Contoh bekerja dalam templat adalah jika Anda menulis implementasi penanganan aktivitas di mana peristiwa akan dinaikkan dari elemen dalam templat yang diterapkan.
Namescope XAML dan API terkait Nama
FrameworkElement memiliki metode FindName, RegisterName, dan UnregisterName. Jika objek tempat Anda memanggil metode ini memiliki namescope XAML, metode tersebut akan memanggil metode namescope XAML yang relevan. Jika tidak, elemen induk diperiksa untuk melihat apakah ia memiliki namescope XAML, dan proses ini berlanjut secara rekursif sampai namescope XAML ditemukan (karena perilaku prosesor XAML, dijamin ada namescope XAML di akar). FrameworkContentElement memiliki perilaku analog, dengan pengecualian bahwa tidak ada FrameworkContentElement yang akan memiliki namescope XAML. Metode ada di FrameworkContentElement sehingga panggilan dapat diteruskan pada akhirnya ke elemen induk FrameworkElement.
SetNameScope digunakan untuk memetakan namescope XAML baru ke objek yang sudah ada. Anda dapat memanggil SetNameScope lebih dari sekali untuk mengatur ulang atau menghapus namescope XAML, tetapi itu bukan penggunaan umum. Selain itu, GetNameScope biasanya tidak digunakan dari kode.
Implementasi Namescope XAML
Kelas-kelas berikut mengimplementasikan INameScope secara langsung:
ResourceDictionary tidak menggunakan nama atau namescope XAML; sebaliknya menggunakan kunci, karena merupakan implementasi kamus. Satu-satunya alasan ResourceDictionary menerapkan INameScope adalah sehingga dapat menimbulkan pengecualian pada kode pengguna yang membantu mengklarifikasi perbedaan antara namescope XAML sejati dan bagaimana ResourceDictionary menangani kunci, dan juga untuk memastikan bahwa namescope XAML tidak diterapkan ke ResourceDictionary oleh elemen induk.
FrameworkTemplate dan Style menerapkan INameScope melalui definisi antarmuka eksplisit. Implementasi eksplisit memungkinkan namescope XAML ini bersifat konvensional ketika diakses melalui antarmuka INameScope, yaitu bagaimana namescope XAML dikomunikasikan oleh proses internal WPF. Tetapi definisi antarmuka eksplisit bukan bagian dari permukaan API konvensional FrameworkTemplate dan Style, karena Anda jarang perlu memanggil metode INameScope pada FrameworkTemplate dan Style secara langsung, dan sebaliknya akan menggunakan API lain seperti GetTemplateChild.
Kelas berikut menentukan namescope XAML mereka sendiri, dengan menggunakan kelas pembantu System.Windows.NameScope dan menyambungkan ke implementasi namescope XAML-nya melalui properti terlampir NameScope.NameScope:
Lihat juga
.NET Desktop feedback