Windows 10 UWP 2 of N : New data binding
在XAML上面呈現資料有兩種模式:
- Code Behind
- Data binding
兩種方式都可以達到將資料呈現在UI上的方式!但有個問題就是Code Behind並不會自動的更新資料的變更,於是Data Binding的概念就出現拉,可以選擇更新模式來達到資料同步的需求(要求)
但是再從Mobile的開發上面來看DataBinding很好,但效能就會受到影響!太多的DataBinding就是導致效能變差,而在Build 2015上介紹了新的Data Binding稱之為Compiled binding!
而Compiled binding有以下特性
- Data binding是在runtime的時候產生Code而Compiled就是在Compiled時期完成
- 消除在執行時期的映射(reflection)的流程
- 程式碼可以被預期的和具有除錯性
Data binding在XAML上的寫法 | Compiled binding在XAML上的寫法 |
Text = “{Binding Title}” | Text = “{x : Bind Title}” |
以效能來看就是如下
NO binding > x : Binding > Binding
不論是在CPU使用或是Memory都是用以上的順序!
所以直接來說就是換成使用{ x : Bind }
Complied data binding還有兩的特點
- x : Bind 是強型別!
- Mode = OneTime 是預設值!
Binding的Mode還是一樣有三個Value,分別是
分類 | 說明 |
One time | 初始化binding成功後的值,之後Source的變更並不會更新到該屬性 |
One way | 當Source端資料更新的時候,會同步在Binding的Target上 |
Two way | 不論是Source或是Target都可以變更來同步資料 |
One-way listen to change notification可以使用如下的方式
- INotifyPropertyChanged
- DependencyProperty
- INotifyCollectionChanged / IObservableVector
Two-way
- UI property需要DependencyProperty
- TextBox會是個特殊的case(若是要同步TextBox的Text屬性),要等到LostFocus的時候才會觸發!
接者介紹再ListViewBase中客製化DataTemplate並結合Compiled binding的寫法
x:Class="App1.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:App1"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:triggers="using:App1.Triggers"
xmlns:vm="using:App1.ViewModel"
xmlns:model="using:App1.Model"
mc:Ignorable="d">
<Page.Resources>
<vm:MainPageViewModel x:Key="MainVM"/>
</Page.Resources>
<Grid DataContext="{StaticResource MainVM}" Background="Black" HorizontalAlignment="Center" VerticalAlignment="Center">
<ListView ItemsSource="{Binding EmployeeCollections}">
<ListView.ItemTemplate>
<DataTemplate x:DataType="model:EmployeeModel">
<RelativePanel>
<Image x:Name="UserImage" Width="80" Height="80" RelativePanel.AlignBottomWithPanel="True" RelativePanel.AlignLeftWithPanel="True">
<Image.Source>
<BitmapImage DecodePixelHeight="80" DecodePixelWidth="80" UriSource="ms-appx:///Assets/Logo.png"/>
</Image.Source>
</Image>
<TextBlock RelativePanel.RightOf="UserImage" RelativePanel.AlignTopWithPanel="True" Text="{x:Bind FirstName}" Foreground="Blue"/>
<TextBlock RelativePanel.RightOf="UserImage" RelativePanel.AlignVerticalCenterWithPanel="True" Text="{x:Bind LastName}" Foreground="Blue"/>
<TextBlock RelativePanel.RightOf="UserImage" RelativePanel.AlignBottomWithPanel="True" Text="{x:Bind Age}" Foreground="Blue"/>
</RelativePanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
</Page>
需要注意的事情是!現在使用DataTemplate和Compiled binding需要加上一個Attribute x : DataType (上圖Code的20行) 強型別該DataTemplate!
DataTemplate可以建立成被重複使用的方式跟8.1的時期一樣!但如果要使用Compile binding就得調整如下
- 將DataTemplate建立x : key,加上 x : DataType。
- 放在Resource的Code block內。
但如果想把該DataTemplate寫在ResourceDictionary內的話就得調整如下步驟!
- 建立ResourceDictionary檔案 (比如叫做Dictionary1.xaml)
- 建立該檔案之Class檔(該Class就會命名成Dictionary1.xaml.cs)
- 在Class檔案放入如下的Code
將該ResourceDictionary加上
{
public Dictionary1()
{
InitializeComponent();
}
}
接者在Resource將該Dictionary給Merge到現在的Dictionary
.Resources>
<ResourceDictionary>
<vm:MainPageViewModel x:Key="MainVM"/>
<ResourceDictionary.MergedDictionaries>
<local:Dictionary1/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
<!--<vm:MainPageViewModel x:Key="MainVM"/>-->
<!--<DataTemplate x:DataType="model:EmployeeModel" x:Key="SampleDataTemplate">
<RelativePanel>
<Image x:Name="UserImage" Width="80" Height="80" RelativePanel.AlignBottomWithPanel="True" RelativePanel.AlignLeftWithPanel="True">
<Image.Source>
<BitmapImage DecodePixelHeight="80" DecodePixelWidth="80" UriSource="ms-appx:///Assets/Logo.png"/>
</Image.Source>
</Image>
<TextBlock RelativePanel.RightOf="UserImage" RelativePanel.AlignTopWithPanel="True" Text="{x:Bind FirstName, FallbackValue=ErrorFirstName}" Foreground="Blue"/>
<TextBlock RelativePanel.RightOf="UserImage" RelativePanel.AlignVerticalCenterWithPanel="True" Text="{x:Bind LastName, FallbackValue=ErrorFirstName}" Foreground="Blue"/>
<TextBlock RelativePanel.RightOf="UserImage" RelativePanel.AlignBottomWithPanel="True" Text="{x:Bind Age, FallbackValue=ErrorFirstName}" Foreground="Blue"/>
</RelativePanel>
</DataTemplate>-->
</Page.Resources>
第五行就是將Dictionary的File給Merge到APP的Resource裡面~
接者介紹新的方式階段性載入Binding的資料
使用的語法是 x : Phase = “放入整數,大於0”
<Image x:Name="UserImage" Width="80" Height="80" RelativePanel.AlignBottomWithPanel="True" RelativePanel.AlignLeftWithPanel="True">
<Image.Source>
<BitmapImage DecodePixelHeight="80" DecodePixelWidth="80" UriSource="ms-appx:///Assets/Logo.png"/>
</Image.Source>
</Image>
<TextBlock RelativePanel.RightOf="UserImage" RelativePanel.AlignTopWithPanel="True" Text="{x:Bind FirstName, FallbackValue=ErrorFirstName}" x:Phase="1" Foreground="Blue"/>
<TextBlock RelativePanel.RightOf="UserImage" RelativePanel.AlignVerticalCenterWithPanel="True" Text="{x:Bind LastName, FallbackValue=ErrorFirstName}" Foreground="Blue"/>
<TextBlock RelativePanel.RightOf="UserImage" RelativePanel.AlignBottomWithPanel="True" Text="{x:Bind Age, FallbackValue=ErrorFirstName}" Foreground="Blue"/>
</RelativePanel>
這樣就可以在大量的資料載入時優先顯示FirstName的TextBlock
補述幾點
CCC事件(ContainerContentChanging)依然可以使用!而且會在所有的phase之前
Phase的數字可以非連貫性
當需要載入大量資料在較為低階的裝置時使用可以提升UX
接者是可以將Event給Binding起來!
如下Code所示
<Button Background="White" Content="ShowDialog" Click="{x:Bind Button_Click}"/>
或者可以把Event寫在Model裡面啦!
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Windows.UI.Popups;
using Windows.UI.Xaml;
namespace App1.Model
{
public class EmployeeModel : BaseModel
{
private string _FirstName;
public string FirstName
{
get { return _FirstName; }
set { _FirstName = value; }
}
private string _LastName;
public string LastName
{
get { return _LastName; }
set { _LastName = value; }
}
private int _Age;
public int Age
{
get { return _Age; }
set { _Age = value; }
}
public async void Button_Click(object sender, RoutedEventArgs e)
{
var dialog = new MessageDialog(String.Format("{0} {1} has been poke", this.FirstName, this.LastName), "Dialog");
var UICmd = await dialog.ShowAsync();
}
}
}
然後稍微修改一下DataTemplate如下
<RelativePanel>
<Image x:Name="UserImage" Width="80" Height="80" RelativePanel.AlignBottomWithPanel="True" RelativePanel.AlignLeftWithPanel="True">
<Image.Source>
<BitmapImage DecodePixelHeight="80" DecodePixelWidth="80" UriSource="ms-appx:///Assets/Logo.png"/>
</Image.Source>
</Image>
<TextBlock RelativePanel.RightOf="UserImage" RelativePanel.AlignTopWithPanel="True" Text="{x:Bind FirstName, FallbackValue=ErrorFirstName}" Foreground="Blue"/>
<TextBlock RelativePanel.RightOf="UserImage" RelativePanel.AlignVerticalCenterWithPanel="True" Text="{x:Bind LastName, FallbackValue=ErrorFirstName}" Foreground="Blue"/>
<TextBlock RelativePanel.RightOf="UserImage" RelativePanel.AlignBottomWithPanel="True" Text="{x:Bind Age, FallbackValue=ErrorFirstName}" Foreground="Blue"/>
<Button Background="White" Content="ShowDialog" RelativePanel.RightOf="UserImage" RelativePanel.AlignVerticalCenterWithPanel="True" RelativePanel.AlignRightWithPanel="True" Click="{x:Bind Button_Click}"/>
</RelativePanel>
</DataTemplate>
Event binding幾點說明
可以支援沒有參數的Event如Void DoSomething() {…}
和原本Event相同的參數Void DoSomething(object sender, RoutedEventArgs e) {…}
和原本Event相同的參數的基礎類型Void DoSomething(object sender, object e) {…}
多載並不支援
這樣的寫法並不支援所有的事件!!
有個觀念要記住!在Model的Event binding在不同的Item是不同的Event!
Binding 生命週期以及效能
Binding初始化完成在Loading的事件
使用Bindings.Initialize()將會初始化Bindings
使用Bindings.Update()在非同步的資料更新
使用Bindings.StopTracking()會停止追蹤Property的變更,呼叫Update()會重新Tracking
OneTime 效能較OneWay好
Bindings.Update()可以在OneTime上同步資料
在列表上 考慮使用INCC(INotifyCollectionChanged)來更新資料取代INPC(INotifyPropertyChanged)在屬性上
想使用INCC其實只需要用ObservableCollection就有實作INCC的部分了!
2015/07/23 補述:Compile Binding不可以搭配Converter!因為Compile的Binding已經將資料型別確切寫死在(頁面名稱).g.cs檔案的Update_Data的這段~
2015/08/11 補述:Compile Binding可以搭配Converter!但是須將Converter寫在APP.Resource裡面或者ResourceDictionary並把該reosourcedictionary merge到application.resource下!目前不能再UIControle的Resource下了定義Converter。感謝Bobson告知
***以上Code以及說明都有可能隨者Windows 10 的版本有所調整!***
參考資料 Build 2015 3-635 Data Binding: Boost Your App`s Performance Through New Enhancements to XAML Data Binding
下次再分享Windows 10 的新技術拉~