Windows RT menyediakan suatu cara yang sederhana dan konsisten untuk menampilkan dan berinteraksi dengan data. Setiap kontrol yang memiliki properti dapat diasosiasikan dengan sumber data. Fitur ini disebut Data Binding, yaitu sebuah proses memberikan asosiasi antara antarmuka dengan lojik aplikasi. Jika data yang di-binding berubah maka tampilan antarmuka juga secara otomatis berubah dan juga sebaliknya jika suatu properti yang ditampilkan di antarmuka berubah, perubahan tersebut dapat kita propagasi kan ke data yang sudah terasosiasi.
Data binding dapat kita pandang sebagai jembatan yang menghubungkan sebuah binding target dengan binding source. Sebuah binding memiliki empat komponen, sebuah target binding ,properti target, sumber data dan path dari data yang ingin ditampilkan. Sebagai contoh, kita ingin melakukan binding terhadap TextBox terhadap properti Name dari suatu kelas model Employee. Pada contoh ini target obyek adalah TextBox, target properti adalah properti Text dari TextBox, nilai yang di binding adalah Name dan sumber datanya adalah obyek Employee.
Properti target haruslah sebuah dependency property. Hampir properti UIElement dari kontrol Windows RT merupakan dependency property dan setiap properti ini, kecuali yang sifatnya hanya read-only mendukung data binding. Untuk sumber data yang memiliki koleksi benda maka biasanya kontrol antarmuka yang digunakan untuk obyek data binding juga merupakan kontrol yang tipe nya koleksi, seperti ListView,GridView dan FlipView.
Untuk melihat bagaimana tampilan implementasi data binding dalam aplikasi, buatlah sebuah proyek baru, aplikasi Windows Store dengan template Grid App.
Pada jendela Solution Explorer buka berkas BindableBase.cs di dalam direktori Common. Kelas ini memiliki satu event yaitu PropertyChanged.
[Windows.Foundation.Metadata.WebHostHidden] public abstract class BindableBase : INotifyPropertyChanged { /// <summary> /// Multicast event for property change notifications. /// </summary> public event PropertyChangedEventHandler PropertyChanged; protected bool SetProperty<T>(ref T storage, T value, [CallerMemberName] String propertyName = null) { if (object.Equals(storage, value)) return false; storage = value; this.OnPropertyChanged(propertyName); return true; } protected void OnPropertyChanged([CallerMemberName] string propertyName = null) { var eventHandler = this.PropertyChanged; if (eventHandler != null) { eventHandler(this, new PropertyChangedEventArgs(propertyName)); } } } |
Kelas ini merupakan kelas helper yang dihasilkan oleh template dan sangat berguna untuk membangun aplikasi yang menggunakan fitur data binding. Untuk membuat obyek-obyek model yang dijadikan sumber data, kita dapat membuat kelas turunan dari BindableBase sehingga mewarisi fitur PropertyChanged. Dengan adanya fitur ini maka setiap ada perubahan nilai dari properti tersebut, akan dipropagasikan kepada kontrol yang direkatkan ke data tersebut. Dengan demikian mekanisme perubahan data antara model dan antarmuka dapat dilakukan dengan mudah.
Selanjutnya, bukalah berkas SampleDataSource.cs di dalam direktori DataModel. Di dalam kelas ini terdapat berbagai deklarasi kelas SampleDataCommon dan SampleDataItem. Kelas SampleDataCommon merupakan kelas abstrak yang diturunkan dari kelas BindableBase. Kelas ini berfungsi menjadi kelas bapak SampleDataItem. SampleDataItem merupakan kelas model yang digunakan template Grid App untuk menampilkan data di dalam aplikasi tersebut.
Contoh implementasi kelas model tersebut adalah seperti dibawah ini. Setiap fungsi setter dilakukan pemanggilan fungsi SetProperty yang merupakan fungsi yang didapatkan dari kelas BindableBase. Fungsi ini berguna untuk mempropagasikan perubahan nilai ke kontrol yang mengikat nilai dari model ini.
/// <summary>
/// Generic item data model. /// </summary> public class SampleDataItem : SampleDataCommon { public SampleDataItem(String uniqueId, String title, String subtitle, String imagePath, String description, String content, SampleDataGroup group) : base(uniqueId, title, subtitle, imagePath, description) { this._content = content; this._group = group; } private string _content = string.Empty; public string Content { get { return this._content; } set { this.SetProperty(ref this._content, value); } } …. |
Untuk implementasi binding target secara sederhana kita bisa memanfaatkan properti DataContext yang dimiliki kontrol bertipe Page. Setiap obyek yang kita berikan ke dalam DataContext maka setiap elemen yang terdapat pada pohon antarmuka XAML dapat mengakses nilai tersebut. Sebagai contoh, jika kita menginstansiasi kelas SampeDataItem dan kita berikan nilai tersebut ke DataContext, setiap kontrol pada pohon XAML, misalnya TextBlock, akan dapat menampilkan nilai dari anggota kelas tersebut dengan deklarasi binding yang sesuai.
Bukalah berkas GroupedItemsPage.xaml.cs dan tambahkan kode berikut ini di dalam fungsi LoadState. Kita akan membuat instans dari kelas SampleDataItem, memberikan nilai tertentu dan menjadikan nilai tersebut menjadi nilai DataContext. Pada saat ini, suatu kelas bernama data bertipe SampleDataItem telah menjadi sumber data bagi halaman tersebut. Selanjutnya pada antarmuka, kita dapat membuat sebuah kontrol dan menampilkan data dari anggota-anggota kelas SampleDataItem.
protected override void LoadState(Object navigationParameter, Dictionary<String, Object> pageState)
{ // TODO: Create an appropriate data model for your problem domain to replace the sample data //var sampleDataGroups = SampleDataSource.GetGroups((String)navigationParameter); //this.DefaultViewModel[“Groups”] = sampleDataGroups; SampleDataItem data = new SampleDataItem(“1”, “title test”, “subtitle”, null, null, null, null); this.DataContext = data; } |
Buka GroupedItemsPage.xaml , tepat diatas kontrol GridView tampatkan sebuah TextBlock. Perhatikan untuk sementara GridView diatur agar tidak tampil terlebih dahulu (Visibility=Collapsed) . Atribut Text dari TextBlock kita berikan nilai Title melalui deklarasi binding. Dengan demikian, pada saat runtime, TextBlock akan mencari nilai Title dari apapun obyek yang direkatkan ke dalam DataContext. Karena DataContext kita rekatkan ke kelas SampleDataItem, maka TextBlock akan menampilkan nilai “title test” , nilai dari anggota kelas yang namanya bersesuaian dengan deklarasi binding.
<TextBlock Grid.Row=”2″ Text=”{Binding Title}” Style=”{StaticResource HeaderTextStyle}”/>
<!– Horizontal scrolling grid used in most view states –> <GridView Visibility=”Collapsed” |
Tekanlah F5 untuk melihat hasilnya.
Untuk melihat bagaimana implementasi binding target pada template Grid App ini, bukalah berkas GroupedItemsPage.xaml . Perhatikan kontrol GridView pada XAML editor dan Anda seharusnya akan dapat melihat blok kode berikut ini :
<GridView
x:Name=”itemGridView” AutomationProperties.AutomationId=”ItemGridView” AutomationProperties.Name=”Grouped Items” Grid.RowSpan=”2″ Padding=”116,137,40,46″ ItemsSource=”{Binding Source={StaticResource groupedItemsViewSource}}” ItemTemplate=”{StaticResource Standard250x250ItemTemplate}” SelectionMode=”None” IsSwipeEnabled=”false” IsItemClickEnabled=”True” ItemClick=”ItemView_ItemClick”> |
Untuk kontrol yang bertipe koleksi seperti GridView maka untuk menghasilkan antarmuka berdasarkan jumlah dari koleksi yang di-binding dilakukan dengan memberikan nilai pada atribut ItemsSource. Pada contoh diatas, ItemsSource diberikan nilai {Binding Source = {Static Resource groupedItemsViewsSource}} . Dengan demikian GridView akan berusaha memperoleh nilai dari sebuah resource bernama groupedItemsViewSource.
<CollectionViewSource
x:Name=”groupedItemsViewSource” Source=”{Binding Groups}” IsSourceGrouped=”true” ItemsPath=”TopItems” d:Source=”{Binding AllGroups, Source={d:DesignInstance Type=data:SampleDataSource, IsDesignTimeCreatable=True}}”/> |
Perhatikan pada bagian atas berkas, setelah <Page.Resources> , terdapat deklarasi CollectionViewSource yang diberi nama groupedItemsViewsSource. CollectionViewSource mengambil nilainya dari variabel. Groups dan mengakses anggota variabel tersebut, yaitu TopItems. Untuk mengetahui nilai Groups mengacu ke variabel yang mana, cobalah scroll ke paling atas hingga tampak deklarasi DataContext seperti dibawah ini :
<common:LayoutAwarePage
x:Name=”pageRoot” x:Class=”DataBinding.GroupedItemsPage” DataContext=”{Binding DefaultViewModel, RelativeSource={RelativeSource Self}}” |
Dari sini kita sudah mengetahui bahwa Groups mengacu pada suatu nilai dari sebuah variabel DefaultViewModel, yang merupakan nilai dari DataContext pada halaman tersebut. Untuk mengetahui variabel apa yang terdapat pada kata kunci Groups, bukalah berkas GroupedItemsPage.xaml.cs dan perhatikan fungsi LoadState.
protected override void LoadState(Object navigationParameter, Dictionary<String, Object> pageState)
{ // TODO: Create an appropriate data model for your problem domain to replace the sample data var sampleDataGroups = SampleDataSource.GetGroups((String)navigationParameter); this.DefaultViewModel[“Groups”] = sampleDataGroups; } |
Ternyata Groups adalah sebuah nilai yang bertipe IEnumerable<SampleDataGroup> sehingga dapat kita simpulkan bahwa sumber data GridView adalah sebuah IEnumerable<SampleDataGroup> , dimana untuk masing-masing SampleDataGroup, memiliki variabel lagi, yaitu sebuah koleksi yang berisi SampleDataItem. Koleksi SampleDataItem ini akan menjadi sumber data masing-masing grup dari GridView tersebut.
Bagian akhir dari proses data binding ini adalah tampilan antarmuka yang menampilkan koleksi dari SampleDataItem. Untuk mengetahui struktur tampilan bagaimana GridView akan menampilkan masing-masing SampleDataItem tersebut, perhatikan blok kode GridView,dimana nilai atribut ItemsTemplate adalah ItemTemplate=”{StaticResource Standard250x250ItemTemplate}”. Dengan demikian kita mengetahui bahwa masing-masing SampleDataItem tersebut ditampilkan dengan menggunakan suatu template bernama Standard250x250ItemTemplate. Bukalah berkas StandardStyles.xaml di dalam direktori Common dan temukan blok kode yang diberi kata kunci Standar250x250ItemTemplate.
<DataTemplate x:Key=”Standard250x250ItemTemplate”>
<Grid HorizontalAlignment=”Left” Width=”250″ Height=”250″> <Border Background=”{StaticResource ListViewItemPlaceholderBackgroundThemeBrush}”> <Image Source=”{Binding Image}” Stretch=”UniformToFill” AutomationProperties.Name=”{Binding Title}”/> </Border> <StackPanel VerticalAlignment=”Bottom” Background=”{StaticResource ListViewItemOverlayBackgroundThemeBrush}”> <TextBlock Text=”{Binding Title}” Foreground=”{StaticResource ListViewItemOverlayForegroundThemeBrush}” Style=”{StaticResource TitleTextStyle}” Height=”60″ Margin=”15,0,15,0″/> <TextBlock Text=”{Binding Subtitle}” Foreground=”{StaticResource ListViewItemOverlaySecondaryForegroundThemeBrush}” Style=”{StaticResource CaptionTextStyle}” TextWrapping=”NoWrap” Margin=”15,0,15,10″/> </StackPanel> </Grid> </DataTemplate> |
Dari deklarasi DataTemplate sekarang kita mengetahui bahwa untuk masing-masing SampleDataItem ditampilkan menggunakan suatu kontrol yang terdiri dari beberapa Text dengan layout StackPanel. Dan anggota dari SampleDataItem yang diakses adalah Title,Subtitle dan Image.
Tekanlah F5 untuk melihat bagaimana hasil data binding tersebut.
Memahami dengan baik bagaimana proses data binding bekerja dapat menghemat dan mempermudah kita dalam pengembangan aplikas di Windows 8-style UI. Dengan data binding pemisahan antarmuka dan lojik dapat dilakukan dengan lebih intuitif dan mudah.