相比于理論,我更傾向于從實(shí)踐中開始,尤其是對(duì)于數(shù)據(jù)綁定。那么,我們先來(lái)看看幾個(gè)簡(jiǎn)單的例子。
我們依舊使用前面的鬧鐘類來(lái)開始。在下面的代碼中,我們有屬性、構(gòu)造函數(shù),還有一個(gè) ToString() 方法的重載。之所以重載這個(gè)方法是因?yàn)槲覀兿朐谧詈蠼壎ǖ臅r(shí)候,這三個(gè)屬性能夠在 TextBox 上顯示得更加工整。
public class Alarm
{
public string Title { get; set; }
public string Description { get; set; }
public DateTime AlarmTime { get; set; }
public Alarm() { }
public Alarm(string title, string description,DateTime alarmTime)
{
Title = title;
Description = description;
AlarmTime = alarmTime;
}
public override string ToString()
{
return "Title: " + Title +"\n"+ "Time: "+ AlarmTime.ToString("d") + "\n"+ "Description: " + Description;
}
}
接下來(lái)再在 XAML 中添加 TextBox 控件如下,因?yàn)?TextBox 此時(shí)是用作顯示而非輸入,所以建議設(shè)置其的只讀屬性。數(shù)據(jù)綁定的核心就是 Text 屬性中的那么一個(gè) Binding 關(guān)鍵字。
<TextBox x:Name="textBox1" FontSize="28" Height="150" Width="400"
TextWrapping="Wrap" Text="{Binding}" IsReadOnly="True"/>
但是光這樣還不夠,我們還需要在后臺(tái)代碼中將數(shù)據(jù)綁定到 textBox1 的 DataContext(數(shù)據(jù)上下文)中。
textBox1.DataContext = new Alarm(
"First Alarm", "I need to study!", new DateTime(2015, 4, 11));
相信大家并不為覺得這個(gè)很難,相反我在學(xué)數(shù)據(jù)綁定的時(shí)候一上來(lái)就是一大堆理論,以至于我對(duì)數(shù)據(jù)一詞有了陰影——所以我學(xué)數(shù)據(jù)結(jié)構(gòu)非常痛苦。
才保存一個(gè)鬧鐘沒太大意思,我們多來(lái)幾個(gè)。
public ObservableCollection<Alarm> UsefulAlarm = new ObservableCollection<Alarm>();
public MainPage()
{
this.InitializeComponent();
UsefulAlarm.Add(new Alarm("First Alarm", "I need to study!", new DateTime(2015, 4, 11)));
UsefulAlarm.Add(new Alarm("First Alarm", "Read a magzine!", new DateTime(2015, 4, 12)));
UsefulAlarm.Add(new Alarm("First Alarm", "Write a blog!", new DateTime(2015, 4, 15)));
UsefulAlarm.Add(new Alarm("First Alarm", "Travel", new DateTime(2015, 5, 15)));
textBox1.DataContext = UsefulAlarm;
}
但是……
很顯然我們用了 ObservableCollection< T >
類,它為數(shù)據(jù)綁定提供了一個(gè)集合,這是因?yàn)樗鼘?shí)現(xiàn)了 INotifyPropertyChanged 和 INotifyCollectionChanged 接口。顧名思義,當(dāng)屬性改變時(shí),它可以通知它所綁定的控件,并且如果你希望該空間能夠同步更新,則將用于綁定的對(duì)象也實(shí)現(xiàn) INotifyPropertyChanged 接口。這個(gè)類好歸好,但相對(duì)于 TextBox 而言算有些高端了,以至于它無(wú)法顯示出來(lái)。但是我們可以用 ComboBox 來(lái)代替它,我們的類并不需要修改,前面的 UsefulAlarm 實(shí)例化也都不用改,只需要將 textBox1 改成 comboBox1 即可。以下是新的 ComboBox 代碼。
<ComboBox Name="comboBox1" ItemsSource="{Binding}" FontSize="28" Height="150" Width="400">
<ComboBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical" Margin="8">
<TextBox Width="350" TextWrapping="Wrap" Text="{Binding Title}" IsReadOnly="True"/>
<TextBox Width="350" TextWrapping="Wrap" Text="{Binding Description}" IsReadOnly="True"/>
<TextBox Width="350" TextWrapping="Wrap" Text="{Binding AlarmTime}" IsReadOnly="True"/>
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
在圖示中我們也容易發(fā)現(xiàn) TextBox 和 ComboBox 兩個(gè)控件的 Width 屬性的應(yīng)用區(qū)別。在 TextBox 中,我們將數(shù)據(jù)綁定到 Text 中;而在 ComboBox 中,我們則是將數(shù)據(jù)綁定到 ItemsSource 中,簡(jiǎn)單的說就是 ComboBox 拿來(lái)所有的數(shù)據(jù),再將它們分成小的細(xì)節(jié)發(fā)給它的子對(duì)象,這些子對(duì)象都在 ComboBox 的 DataTemplate(數(shù)據(jù)容器)中。
在這里我們并沒有用到前面所重載的 ToString() 函數(shù),因?yàn)槲覀円呀?jīng)分別將 Title、Description、AlarmTime 綁定到相應(yīng)的 TextBox 控件了。那圖示中又為什么這些數(shù)據(jù)都是一行一行的表示呢,這都是布局控件 StackPanel 的功勞,全靠它的Orientation屬性。如果將這個(gè)屬性設(shè)置成 Horizontal 呢,那標(biāo)題、描述已經(jīng)時(shí)間就是全排在一行了。
聽說 ListBox 和 ComboBox 很類似哦,它們都是 Box……XBox 呀。博主我有點(diǎn)懶,那可不可以直接將 ComboBox 的名字改成 ListBox 就直接運(yùn)行呢,答案是可以哦!那么區(qū)別到底在哪里呢?看看這張圖就知道啦。
咦?怎么只有一條鬧鐘了?別驚慌……拖動(dòng)右邊的滾動(dòng)條就可以查看到全部的鬧鐘咯。我真的只把 ComboBox 改成 ListBox 還有相應(yīng)的 Name 屬性(包括后臺(tái)代碼中的名字哦),以下就是完整的代碼啦,我會(huì)騙你?
<ListBox Name="listBox1" ItemsSource="{Binding}" FontSize="28" Height="150" Width="400">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical" Margin="8">
<TextBox Width="350" TextWrapping="Wrap" Text="{Binding Title}" IsReadOnly="True"/>
<TextBox Width="350" TextWrapping="Wrap" Text="{Binding Description}" IsReadOnly="True"/>
<TextBox Width="350" TextWrapping="Wrap" Text="{Binding AlarmTime}" IsReadOnly="True"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
看了前面的代碼相信我沒有騙你吧,童鞋們看到 ListBox 有沒有想到 ListView 呢?我要是想說還是和前面一樣只用改名字等就可以用 ListView,你還是不信么?
<ListView Name="listView1" ItemsSource="{Binding}" FontSize="28" Height="150" Width="400">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical" Margin="8">
<TextBox Width="350" TextWrapping="Wrap" Text="{Binding Title}" IsReadOnly="True"/>
<TextBox Width="350" TextWrapping="Wrap" Text="{Binding Description}" IsReadOnly="True"/>
<TextBox Width="350" TextWrapping="Wrap" Text="{Binding AlarmTime}" IsReadOnly="True"/>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
當(dāng)然了,還是用右邊的滾動(dòng)條來(lái)下拉以查看所有的數(shù)據(jù)。不過 ListView 君的最佳姿勢(shì)不是這樣哦,將 Height 改為 600 才是呢??聪聢D——這才是高大上的 ListView 君嘛!
好了不玩了,GridView 也是可以這樣弄得,不信你試試。
1.我們?yōu)槭裁匆脭?shù)據(jù)綁定
很顯然,我們不可能把所有的數(shù)據(jù)全部固定在特定的控件上。比如,游戲的積分、設(shè)定的鬧鐘、天氣預(yù)報(bào)甚至的通訊類的消息,它們都并非是一成不變的。但是也并非所有的控件都需要綁定,比如你的 App 的名字、發(fā)送消息時(shí)所用的發(fā)送按鈕上面的文本等。
2.那數(shù)據(jù)和 UI 之間又有哪些關(guān)系呢
首先我們得明確,數(shù)據(jù)的顯示和其后臺(tái)的管理是不一樣的。數(shù)據(jù)與UI綁定之后,我們的數(shù)據(jù)就可以在這兩者之間進(jìn)行溝通,如果數(shù)據(jù)發(fā)生變化時(shí),綁定到數(shù)據(jù)的 UI 則會(huì)自動(dòng)將相應(yīng)的屬性進(jìn)行調(diào)整,不僅僅是前面用到的 Text 屬性,還有 FontSize、Width、Foreground、Image 屬性都可以。
3.數(shù)據(jù)綁定到底是綁定什么
首先,我們得有綁定源,這些就是我們需要綁定的數(shù)據(jù),沒有數(shù)據(jù),即使你綁定了,它也顯示不出來(lái)。 其次,我們還需要綁定目標(biāo),也就是 Framework 類的 DependencyProperty 屬性,說得白話文點(diǎn)就是將數(shù)據(jù)綁定到 UI 的相應(yīng)屬性上。
最后,我們還需要一個(gè) Binding 對(duì)象,它就像是搬運(yùn)工,沒有它,數(shù)據(jù)也是無(wú)法動(dòng)彈的。它能夠幫助我們將數(shù)據(jù)從數(shù)據(jù)源移動(dòng)到綁定目標(biāo),并且將綁定目標(biāo)的相應(yīng)消息通知給綁定源。它還有一些巧妙的工具,能夠?qū)⒔壎ㄔ吹臄?shù)據(jù)加工成特定的格式。
4.綁定源有哪些
所有的公共語(yǔ)言運(yùn)行時(shí)對(duì)象,我們前面用的Alarm類就是這種對(duì)象,另外UI元素也是哦。
5.聽說有的搬運(yùn)工只能將數(shù)據(jù)源的數(shù)據(jù)一次性搬到綁定目標(biāo)后就不再搬了,而有的搬運(yùn)工則會(huì)在數(shù)據(jù)修改后再搬一次,甚至還有的能夠在綁定目標(biāo)更改后再將數(shù)據(jù)搬回到數(shù)據(jù)源
以下分別是 OneWay 和 TwoWay 的例子:
<StackPanel Width="240" Orientation="Vertical" HorizontalAlignment="Center" VerticalAlignment="Center">
<Slider Name="slider1" Minimum="0" Maximum="100"/>
<TextBox FontSize="30"
Text="{Binding ElementName=slider1,Path=Value,Mode=OneWay}" />
</StackPanel>
拖動(dòng)滑動(dòng)條,就可以看到在 TextBox 中顯示它的值的變化了。如果希望它只變化一次,那就將代碼中的 OneWay 改成 OneTime 即可。
<StackPanel Width="240" Orientation="Vertical" HorizontalAlignment="Center" VerticalAlignment="Center">
<TextBox FontSize="30" Name="textBox" Height="60"
Text ="{Binding ElementName=listBox1, Path=SelectedItem.Content, Mode=TwoWay}">
</TextBox>
<ListBox FontSize="30" Name="listBox1">
<ListBoxItem Content="Item 1"/>
<ListBoxItem Content="Item 2"/>
<ListBoxItem Content="Item 3"/>
<ListBoxItem Content="Item 4"/>
</ListBox>
</StackPanel>
如下圖所示,點(diǎn)擊 Item 1 后 TextBox 則會(huì)顯示相應(yīng)的 Item 1,將 TextBox 中的 Item 1 修改為 Item 5 后再 ListBox 中也自動(dòng)修改成了 Item5。
簡(jiǎn)單示例:Foreground 的數(shù)據(jù)綁定
前面已經(jīng)說到了 Foreground 也可以綁定,想不想試試呢。我們現(xiàn)在 TextBox 中寫一個(gè) TextBox,然后在后臺(tái)代碼中添加一個(gè)綁定就可以了。這個(gè)和前面的比較簡(jiǎn)單,這里只是用來(lái)引出后面的東東哦
<TextBox Name="textBox" Width="200" Height="100" IsReadOnly="True"
FontSize="32" Text="Text" Foreground="{Binding ForeBrush}"/>
textBox.Foreground = new SolidColorBrush(Colors.BlueViolet);
更多建議: