還是以上篇導航為基礎,完善導航的頁面并為導航的頁面綁定資料和顯示資料。
這篇學習筆記主要記錄兩個點,分别為如下:
- 基于Silverlight 的Windows Phone 資料綁定
- 為應用程式添加程式欄,額外記錄顯示和隐藏系統托盤(System.Tray)的代碼
1.資料綁定
資料綁定為基于Silverlight 的應用程式提供了一個簡單的方式來實作顯示和資料之間互動。資料顯示從資料管理中分離出來。使用者界面與資料模型之間的連接配接或者綁定,允許資料在兩者之間流動。不一個綁定被建立,資料發生改變,被綁定到資料的UI(使用者界面 )元素能自動發生改變。這本篇 學習筆記将針對Silverlight 提供的控件DataList 為原型講述如何綁定資料和删除資料。下面的圖顯示了綁定的概念:
上圖可以分為綁定目标和綁定源。
- 綁定目标代表綁定的對象是UI控件,是以必須控件是FrameworkElement的任何一個DependencyProperty(提供快速的方法計算值,可與其他動态資料互動)。
- 綁定來源包含了來源和目标之間的資料流的資料。來源可以是任何運作于CLR的對象,包括目标元素本身或者其他UI元素。
- 資料流的方向。Binding 對象的Mode屬性設定了資料流的方向。分為三種方向:OneTime---目标控件屬性隻是更新一次,以後的更新會被忽略。oneWay--資料對象的值會同步到目标控件的屬性,但是目标控件的屬性的改變不會同步到資料對象中。TwoWay--目标控件的屬性和資料對象的值互相同步。
- 可選的值轉換器,它被應用于經過值轉換器傳遞的資料。值轉器是一個類,它實作了IValueConverter。
原理大緻如上,下面看一下要實作的效果圖:
如圖,點選圖中畫紅圈的連接配接,将會導航到一個放置DataList的資料清單,DataList放置了一列帶圖檔和文字的資料,選中某項則讓删除按鈕可用,可以指定删除某項資料,并實時更新到清單中,界面效果如下:
綁定資料原理:
為了保證引用的集合發生改變時資料綁定機制也能使集合接收通知,Silverlight 使用了事件機制。資料綁定引擎期望當一個集合的值改變時,所發生的事件是CollectionChanged ,該事件被定義為如下:
event NotifyCollectionChangedEventHandler CollectionChanged;
這個集合的實作應該是集合的每一個改變(添加/編輯/移除集合的成員,程式順序,等)都會被觸發到事件。引用事件響應變化。這個事件被定義到INotifyCollectionChanged 接口中。 為使資料綁定能自動更新到集合,應該建立自己的集合并實作這個接口。在Silverlight 類庫中提供了兩個集合,這兩個集合實作了這個接口,我們可以很放心的拿來使用,分别為:ObservableCollection<T>和ReadOnlyObservableCollection<T> 。
- ObservableCollection -代表了一個動态資料集。它會為集合中的項發生添加,移除或者整個清單被重新整理等情況實時提供通知。
- ReadOnlyObservableCollection -代表了一個可讀的ObservableCollection。
Tip:兩個類的資料綁定機制會對更新己經綁定到集合的對象時觸發的事件做出響應。
實作這個集合之前,我們有必要先完成一個Phots 的屬性集,代碼如下:
public class Photo : INotifyPropertyChanged
{
private string _Filename;
public string Filename
{
get { return _Filename; }
set
{
_Filename = value;
NotifyPropertyChanged( " FileName " );
}
}
private BitmapImage _Image;
public BitmapImage Image
{
get { return _Image; }
set
{
_Image = value;
NotifyPropertyChanged( " Image " );
}
}
private void NotifyPropertyChanged( string propertyName)
{
if ( null != PropertyChanged)
PropertyChanged( this , new PropertyChangedEventArgs(propertyName));
}
public event PropertyChangedEventHandler PropertyChanged;
}
TIP: INotifyPropertyChanged ,是一個接口實作它是為了在資料改變的時候能夠廣播出去,通過屬性名稱通知哪個屬性名稱發生了變化。
另外我們還需要一個工具來,用來通過資源的URI将檔案轉為可讓圖檔接收的BitmapImage類型,代碼如下:
public static class Utils
{
public static BitmapImage GetImage( string filename)
{
string imgLocation = Application.Current.Resources[ " ImagesLocation " ].ToString();
StreamResourceInfo imageResource = Application.GetResourceStream( new Uri(imgLocation + filename, UriKind.Relative));
BitmapImage image = new BitmapImage();
image.SetSource(imageResource.Stream);
return image;
}
完成了上述兩個類,打開圖檔對應的Xaml,我這裡的名稱路徑在:/Views/PicturesView/Default.xaml。在該頁面的ContentPanel中加入一個DataList 控件,并為其資料模闆添加内容顯示窗器,比如本例以橫向顯示的StackPanel中放置了一個圖檔控件和一個文本控件用來顯示圖檔和圖檔名稱,XML代碼如下:
< Grid x:Name ="ContentPanel" Grid.Row ="1" Margin ="12,0,12,0" >
< StackPanel Orientation ="Vertical" >
< StackPanel Orientation ="Horizontal" >
< Button x:Name ="btnRemoveSelection" Content ="Remove Image" Click ="btnRemoveSelection_Click" IsEnabled ="False" />
</ StackPanel >
< ListBox x:Name ="lstPictures" Width ="450" Height ="520" Margin ="10" SelectionChanged ="lstPictures_SelectionChanged" >
< ListBox.ItemTemplate >
< DataTemplate >
< StackPanel Orientation ="Horizontal" >
< Image Source =" {Binding Image} " Width ="100" Stretch ="Uniform" HorizontalAlignment ="Center" />
< TextBlock Text =" {Binding Filename} " TextWrapping ="Wrap" />
</ StackPanel >
</ DataTemplate >
</ ListBox.ItemTemplate >
</ ListBox >
</ StackPanel >
</ Grid >
做Asp.net 的朋友趕快過來圍觀,這個DataList 資料綁定的方法不是就是ASP.NET常用的寫法嗎?隻是來源做了處理使用Silverlight 的寫法,不過看樣子和格式都與Asp.Net 的DataList 資料綁定很相似。好了,之後進入CS檔案,引用這一命名空間:
using System.Collections.Specialized;
聲明上述提到的ObservableCollection對象,将Photo對象放進去,我在做Android 的時候喜歡寫資料源的時候這樣寫:List<HashMap<String,Object>> list=new ArrayList<HashMap<String,Object>>(); 然後去自定義一個資料源,感覺靈活性比較強,WP7還沒試過,就先暫時使用這種資料對象來實作資料的更新顯示吧。
定義好後,為集合中的PHOTO對象存值和設定DataList的事件并與删除按鈕互動,所有代碼如下:
/// <summary>
/// 此事件定義了當資料改變時通知集合觸發事件
/// </summary>
// public event NotifyCollectionChangedEventHandler CollectionChanged;
ObservableCollection < Photo > photos = new ObservableCollection < Photo > ();
private void initializePhotos()
{
photos.Add( new Photo() {
Filename = " Butterfly.jpg " ,
Image = Utils.GetImage( " Butterfly.jpg " )
});
photos.Add( new Photo()
{
Filename = " Chrysanthemum.jpg " ,
Image = Utils.GetImage( " Chrysanthemum.jpg " )
});
photos.Add( new Photo()
{
Filename = " Desert.jpg " ,
Image = Utils.GetImage( " Desert.jpg " )
});
photos.Add( new Photo()
{
Filename = " Field.jpg " ,
Image = Utils.GetImage( " Field.jpg " )
});
photos.Add( new Photo()
{
Filename = " Tulips.jpg " ,
Image = Utils.GetImage( " Tulips.jpg " )
});
photos.Add( new Photo()
{
Filename = " Flower.jpg " ,
Image = Utils.GetImage( " Flower.jpg " )
});
photos.Add( new Photo()
{
Filename = " Hydrangeas.jpg " ,
Image = Utils.GetImage( " Hydrangeas.jpg " )
});
photos.Add( new Photo()
{
Filename = " Butterfly.jpg " ,
Image = Utils.GetImage( " Butterfly.jpg " )
});
photos.Add( new Photo()
{
Filename = " Jellyfish.jpg " ,
Image = Utils.GetImage( " Jellyfish.jpg " )
});
photos.Add( new Photo()
{
Filename = " Koala.jpg " ,
Image = Utils.GetImage( " Koala.jpg " )
});
photos.Add( new Photo()
{
Filename = " Leaves.jpg " ,
Image = Utils.GetImage( " Leaves.jpg " )
});
photos.Add( new Photo()
{
Filename = " Lighthouse.jpg " ,
Image = Utils.GetImage( " Lighthouse.jpg " )
});
photos.Add( new Photo()
{
Filename = " Penguins.jpg " ,
Image = Utils.GetImage( " Penguins.jpg " )
});
photos.Add( new Photo()
{
Filename = " Rocks.jpg " ,
Image = Utils.GetImage( " Rocks.jpg " )
});
photos.Add( new Photo()
{
Filename = " Tulip.jpg " ,
Image = Utils.GetImage( " Tulip.jpg " )
});
photos.Add( new Photo()
{
Filename = " Window.jpg " ,
Image = Utils.GetImage( " Window.jpg " )
});
}
public Default()
{
InitializeComponent();
initializePhotos();
lstPictures.ItemsSource = photos;
}
private void btnRemoveSelection_Click( object sender, RoutedEventArgs e)
{
if ( null != lstPictures.SelectedItem)
{
photos.Remove(lstPictures.SelectedItem as Photo);
}
}
private void lstPictures_SelectionChanged( object sender, SelectionChangedEventArgs e)
{
if ( null != lstPictures.SelectedItem)
{
btnRemoveSelection.IsEnabled = true ;
}
if (photos.Count == 0 )
{
btnRemoveSelection.IsEnabled = false ;
}
}
2.應用程式欄
在很多情況下我們會需要提供跨應用程式的通用功能。一些情況下,我們可能想要為頁面提供一些符合某些條件時才出現的特殊功能。另外一些情況下,您隻希望獲得更多的螢幕空間,這些情況下,Windows Phone 提供了應用程式欄。
要為應用程式添加應用程式欄,需要在App.xaml 注冊。本篇學習的内容注冊一個菜單和兩個 按鈕,一個菜單導航到About 頁面,另外一個按鈕跳轉到Image清單。打開App.xaml,在Application.Resouces節點内,輸如下代碼并為其添加事件響應:
<!-- 注冊 應用程式欄 -->
< shell:ApplicationBar x:Key ="MainAppBar" IsVisible ="True" >
<!-- 菜單項 Abou -->
< shell:ApplicationBar.MenuItems >
< shell:ApplicationBarMenuItem Text ="About" Click ="ApplicationBarMenuItem_Click" />
</ shell:ApplicationBar.MenuItems >
<!-- 應用程式條 按鈕 -->
< shell:ApplicationBar.Buttons >
< shell:ApplicationBarIconButton Text ="Web" IconUri ="ie_icon.png" Click ="ApplicationBarIconButton_Click" />
< shell:ApplicationBarIconButton Text ="Images" IconUri ="pictures_Icon.png" Click ="ImageEvent_Click" />
</ shell:ApplicationBar.Buttons >
</ shell:ApplicationBar >
進入APP.xaml.cs在自動生成的事件句柄内,鍵入如下代碼實作跳轉:
private void ApplicationBarMenuItem_Click( object sender, EventArgs e)
{
PhoneApplicationFrame root = Application.Current.RootVisual as PhoneApplicationFrame;
root.Navigate( new Uri( " /About " , UriKind.Relative));
}
private void ApplicationBarIconButton_Click( object sender, EventArgs e)
{
}
private void ImageEvent_Click( object sender, EventArgs e)
{
PhoneApplicationFrame root = Application.Current.RootVisual as PhoneApplicationFrame;
root.Navigate( new Uri( " /Pictures " ,UriKind.Relative));
}
在你需要顯示應用程式欄的頁面的phone:PhoneApplicationPage節點指定ApplicationBar來源,比如本文的指定方式:
< phone:PhoneApplicationPage
x:Class ="DataBind.MainPage"
xmlns ="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x ="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:phone ="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
xmlns:shell ="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
xmlns:d ="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc ="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable ="d" d:DesignWidth ="480" d:DesignHeight ="768"
FontFamily =" {StaticResource PhoneFontFamilyNormal} "
FontSize =" {StaticResource PhoneFontSizeNormal} "
Foreground =" {StaticResource PhoneForegroundBrush} "
SupportedOrientations ="Portrait" Orientation ="Portrait"
shell:SystemTray.IsVisible ="True"
ApplicationBar =" {StaticResource MainAppBar} "
>
看看截圖效果吧:
源碼比較大,有需要的EMAIL我:[email protected]