最近上网,看到Window8的新闻满天飞,看到Metro效果还不错,折腾了一个晚上把Windows8给装好了,比较PC屏幕大,个人感觉比WindowsPhone上面的效果更好,软件也都能装,用了用感觉还不错!这不闲着无事, 花了2个星期做了个编程在线Windows8 客户端!
Title编程在线网站:http://facejob.sinaapp.com/
编程在线Windows8 客户端:http://www.cnblogs.com/hubcarl/archive/2012/11/18/2776608.html
文章概要:
1、熟悉INotifyPropertyChanged的使用
2、Style样式模板定义
3、ListView数据绑定
4、MessageDialog弹出窗口的使用
1、熟悉INotifyPropertyChanged的使用
在WPF开发中,数据绑定最经典的就是MVVM.数据绑定使用了ObservableCollection<T> 类来实现,ViewModel通过继承GalaSoft.MvvmLight.ViewModelBase类来实现,Command使用GalaSoft.MvvmLight.Command.RelayCommand<T>来实现。ObservableCollection<T>表示一个动态数据集合,在添加项、移除项或刷新整个列表时,此集合将提供通知。在Window8 Metro开发中, 数据载体实体类通过实现INotifyPropertyChanged, 属性值变化时,自动更新UI(观察者模式)。
INotifyPropertyChanged 接口用于向客户端(通常是执行绑定的客户端)发出某一属性值已更改的通知。
若要在将客户端与数据源进行绑定时发出更改通知,则绑定类型应具有下列任一功能:
-
实现 INotifyPropertyChanged 接口(首选)。
-
为绑定类型的每个属性提供更改事件。
INotifyPropertyChanged 原型实现:event PropertyChangedEventHandler PropertyChanged
6 接口如下:
7
8 namespace System.ComponentModel
9 {
10 public delegate void PropertyChangedEventHandler( object sender, PropertyChangedEventArgs e);
11
12 public interface INotifyPropertyChanged
13 {
14 event PropertyChangedEventHandler PropertyChanged;
15 }
16
17 public class PropertyChangedEventArgs : EventArgs
18 {
19 public PropertyChangedEventArgs( string propertyName);
20 public virtual string PropertyName { get; }
21 }
22 }
23 从数据对象到UI界面:当实现了INotifyPropertyChanged接口的对象有所改变时,会激发OnPropertyChanged这个接口方法,该方法保证了UI界面的数据同步。
下面就定义Article数据载体实体类,实现INotifyPropertyChanged 接口,同时为绑定类型的每个属性提供更改事件。
2 {
3 /// <summary>
4 /// 说明: 文章实体类,实现INotifyPropertyChanged接口
5 /// 作者: Blue Sky
6 /// 时间:2012-11-05
7 /// </summary>
8 public class Article : INotifyPropertyChanged
9 {
10 private static Uri _baseUri = new Uri( " ms-appx:/// ");
11
12 private int id;
13
14 public int Id
15 {
16 get { return this.id; }
17 set
18 {
19 this.id = value;
20 NotifyPropertyChanged( " Id ");
21 }
22
23 }
24
25 // 标题
26 private string title;
27 public string Title
28 {
29 get { return this.title; }
30 set
31 {
32 this.title = value;
33 NotifyPropertyChanged( " Title ");
34 }
35
36 }
37
38 private string imagePath = null;
39 public string ImagePath
40 {
41 get { return this.imagePath; }
42 set
43 {
44 this.imagePath = value;
45 NotifyPropertyChanged( " ImagePath ");
46 }
47
48 }
49
50 private ImageSource image = null;
51 public ImageSource Image
52 {
53 get
54 {
55 if ( this.image == null && this.imagePath != null)
56 {
57 this.image = new Windows.UI.Xaml.Media.Imaging.BitmapImage( new Uri(_baseUri, this.imagePath));
58 }
59 return this.image;
60 }
61
62 set
63 {
64 this.image = value;
65 this.NotifyPropertyChanged( " ImagePath ");
66 }
67 }
68
69 private string description;
70
71 public string Description
72 {
73 get { return this.description; }
74 set
75 {
76 this.description = value;
77 NotifyPropertyChanged( " Description ");
78 }
79
80 }
81
82 // 文章内容
83 private string content;
84
85 public string Content
86 {
87 get { return this.content; }
88 set
89 {
90 this.content = value;
91 NotifyPropertyChanged( " Content ");
92 }
93
94 }
95
96 private DateTime createDate;
97 public DateTime CreateDate
98 {
99 get { return this.createDate; }
100 set
101 {
102 this.createDate = value;
103 NotifyPropertyChanged( " CreateDate ");
104 }
105
106 }
107
108 // 接口方法属性变更通知实现
109 public event PropertyChangedEventHandler PropertyChanged;
110
111 private void NotifyPropertyChanged( string propertyName)
112 {
113 if (PropertyChanged != null)
114 {
115 PropertyChanged( this, new PropertyChangedEventArgs(propertyName));
116 }
117 }
118
119 }
120 }
Article实体类实现INotifyPropertyChanged 接口,同时为绑定类型的每个属性提供更改事件。下面就是要实现视图实体类ArticleViewModel,直接与界面进行交互对象。主要包含两个属性文章列表ArticleList和当前选中的文章SelectedArticle属性,因这两个属性值会变化,同时要更新UI,所以也要实现INotifyPropertyChanged 接口。
2 /// 页面数据视图对象,实现属性变更事件接口,自动更新UI
3 /// </summary>
4 public class ArticleViewModel : INotifyPropertyChanged
5 {
6 private ObservableCollection<Article> articleList;
7 public ObservableCollection<Article> ArticleList
8 {
9 get { return articleList; }
10 }
11
12 private int selectedItemIndex;
13 public int SelectedItemIndex
14 {
15 get { return selectedItemIndex; }
16 set { selectedItemIndex = value; NotifyPropertyChanged( " SelectedItemIndex "); }
17 }
18
19 private Article selectedArticle;
20
21 public Article SelectedArticle
22 {
23 get{ return this.selectedArticle;}
24 set
25 {
26 this.selectedArticle = value;
27 NotifyPropertyChanged( " SelectedArticle ");
28 }
29 }
30
31
32 public ArticleViewModel()
33 {
34 this.InitArticleData();
35 }
36
37 public event PropertyChangedEventHandler PropertyChanged;
38 private void NotifyPropertyChanged( string propertyName)
39 {
40 if (PropertyChanged != null)
41 {
42 PropertyChanged( this, new PropertyChangedEventArgs(propertyName));
43 }
44 }
45 }
2、Style样式模板定义
页面空间样式定义可以用两种方式:一种直接在对应XAML页面直接对控件属性定义,这个与HTML CSS 样式一样,一种是把样式定义成模板形式,把一些公共样式定义到一个文件中去,这个与CSS 样式表一样。在通过Visual Studio Express for Widows8 新建项目时,项目会自动生成一个公共的样式文件StandardStyles.xaml,这种方式也是推荐使用的一种方式,可以做到样式表统一,维护简单方便!
< Setter Property ="FontWeight" Value ="SemiLight" />
</ Style >
<!-- TextBlock 样式 -->
< Style x:Key ="BasicTextStyle" TargetType ="TextBlock" >
< Setter Property ="Foreground" Value ="{StaticResource ApplicationForegroundThemeBrush}" />
< Setter Property ="FontSize" Value ="{StaticResource ControlContentThemeFontSize}" />
< Setter Property ="FontFamily" Value ="{StaticResource ContentControlThemeFontFamily}" />
< Setter Property ="TextTrimming" Value ="WordEllipsis" />
< Setter Property ="TextWrapping" Value ="Wrap" />
< Setter Property ="Typography.StylisticSet20" Value ="True" />
< Setter Property ="Typography.DiscretionaryLigatures" Value ="True" />
< Setter Property ="Typography.CaseSensitiveForms" Value ="True" />
</ Style >
一看就一目了然,Style里面key就是给页面引用的,每一个Style都有唯一的一个key,同时指定是哪种控件类型,样式可以通过BasedOn关键字继承,property关键字是对空间每个属性值进行设置!这个公共样式引入是在App.xaml文件中引入的,每个Metro项目都有一个App.xaml文件。
使用方式: <TextBlock Text="{Binding Description}" Style="{StaticResource BodyTextStyle}" MaxHeight="60"/>
〉〉再就是直接在页面定义样式,这种适合使用比较特殊的样式或者使用频率比较少场景.
例如直接定义图片的宽度和高度,:<Image Margin="0,0,20,0" Width="150" Height="150" Source="{Binding SelectedArticle.Image}" Stretch="UniformToFill"/>
3、ListView数据绑定
ListView控件定义可以方式可以通过两种方式进行
1、数据目标直接定义页面当中,如下:
2 ItemsSource ="{Binding ArticleList}" SelectionChanged ="Item_click" >
3 < ListView.ItemTemplate >
4 < DataTemplate >
5 < Grid Height ="110" Margin ="6" >
6 < Grid.ColumnDefinitions >
7 < ColumnDefinition Width ="Auto" />
8 < ColumnDefinition Width ="*" />
9 </ Grid.ColumnDefinitions >
10 < Border Background ="{StaticResource ListViewItemPlaceholderBackgroundThemeBrush}" Width ="110" Height ="110" >
11 < Image Source ="{Binding Image}" Stretch ="UniformToFill" />
12 </ Border >
13 < StackPanel Grid.Column ="1" VerticalAlignment ="Top" Margin ="10,0,0,0" >
14 < TextBlock Text ="{Binding Title}" Style ="{StaticResource TitleTextStyle}" TextWrapping ="NoWrap" />
15 < TextBlock Text ="{Binding Description}" Style ="{StaticResource BodyTextStyle}" MaxHeight ="60" />
16 </ StackPanel >
17 </ Grid >
18 </ DataTemplate >
19 </ ListView.ItemTemplate >
20 </ ListView >
2、数据模板抽取到文件StandardStyles.xaml当中去,ListView中直接想引用样式一样使用。通过Listview的ItemTemplate属性执行数据模板。如下:
x:Name ="itemListView"
AutomationProperties.AutomationId ="ItemsListView"
AutomationProperties.Name ="Items"
TabIndex ="1"
Grid.Row ="1"
Margin ="-10,-10,0,0"
Padding ="60,0,0,60"
ItemsSource =" {Binding Source={StaticResource itemsViewSource}} "
IsSwipeEnabled ="False"
SelectionChanged ="ItemListView_SelectionChanged"
ItemTemplate =" {StaticResource Standard130ItemTemplate} " />
Standard130ItemTemplate在文件中定义如下:
2 < Grid Height ="130" Margin ="6" >
3 < Grid.ColumnDefinitions >
4 < ColumnDefinition Width ="Auto" />
5 < ColumnDefinition Width ="*" />
6 </ Grid.ColumnDefinitions >
7 < Border Background =" {StaticResource ListViewItemPlaceholderBackgroundThemeBrush} " Width ="110" Height ="110" >
8 < Image Source =" {Binding Image} " Stretch ="UniformToFill" />
9 </ Border >
10 < StackPanel Grid.Column ="1" VerticalAlignment ="Top" Margin ="10,0,0,0" >
11 < TextBlock Text =" {Binding Title} " Style =" {StaticResource TitleTextStyle} " TextWrapping ="NoWrap" />
12 < TextBlock Text =" {Binding Subtitle} " Style =" {StaticResource CaptionTextStyle} " TextWrapping ="NoWrap" />
13 < TextBlock Text =" {Binding Description} " Style =" {StaticResource BodyTextStyle} " MaxHeight ="60" />
14 </ StackPanel >
15 </ Grid >
16 </ DataTemplate >
你看,模板方式定义简单,而且又简洁明了,而且动态加载样式时非常方便。
4、MessageDialog 弹出对话框实现
//弹出带有确定按钮的对话框
2 msgDialog.Commands.Add( new UICommand( " 确定 ", new UICommandInvokedHandler(OnUICommand)));
3 await msgDialog.ShowAsync();
在实例化UICommand时,我们使用了以下构造函数。
public UICommand(string label, UICommandInvokedHandler action);
指定一个与UICommandInvokedHandler委托绑定的方法,这样,当某个UICommand被用户单击后,会调用UICommandInvokedHandler绑定的对应方法,在本例中,所有UICommand都绑定到同一个方法。
此外,MessageDialog有两个属性应当注意一下:
1、CancelCommandIndex:默认“取消”按钮的索引,这个索引是对应于Commands中添加的UICommand的索引,从0开始,按添加顺序,第一个UICommand的索引为0,第二个UICommand的索引为1,第三个为2,依此类推(当然,最多就只有三个,索引2)。假如CancelCommandIndex属性设置了1,那么,消息框中的第二个按钮就是默认的“取消”命令,只要按下ESC键就能触发。
2、DefaultCommandIndex:默认“确定”指令的索引,例如设置为0,即Commands中第一个按钮为默认命令,只要按下回车键就能触发。
要显示MessageDialog,调用ShowAsync方法,注意这个方法是异步方法,要用await关键字,同时,凡是调用了异步方法并加有await关键字的方法,在定义时还要加上async关键字
2 msg.Commands.Add( new UICommand( " 重试 ", new UICommandInvokedHandler(OnUICommand)));
3 msg.Commands.Add( new UICommand( " 忽略 ", new UICommandInvokedHandler(OnUICommand)));
4 msg.Commands.Add( new UICommand( " 取消 ", new UICommandInvokedHandler(OnUICommand)));
5 // 默认按钮索引
6 msg.DefaultCommandIndex = 0;
7 msg.CancelCommandIndex = 2;
好了,讲了这么多,现在把这四点运用上,直接上代码了,比较简单。
2 {
3 /// <summary>
4 /// 可用于自身或导航至 Frame 内部的空白页。
5 /// </summary>
6 public sealed partial class MainPage : Page
7 {
8 private ArticleViewModel viewModel;
9
10 public MainPage()
11 {
12 this.InitializeComponent();
13
14 viewModel = new ArticleViewModel();
15 // Page默认上下文绑定数据源
16 this.DataContext = viewModel;
17 // 或者直接绑定ListView
18 // this.lvArticles.ItemsSource = viewModel;
19 // 委托绑定集合列表变化时触发动作
20 viewModel.ArticleList.CollectionChanged += ArticleList_CollectionChanged;
21 }
22
23 /// <summary>
24 /// 文章列表发生变化事件,用到了MessageDialog 弹出框
25 /// </summary>
26 /// <param name="sender"></param>
27 /// <param name="e"></param>
28 async void ArticleList_CollectionChanged( object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
29 {
30 // 弹出带有确定按钮的对话框
31 MessageDialog msgDialog = new MessageDialog( " 文章列表发生变化 ");
32 msgDialog.Commands.Add( new UICommand( " 确定 ", new UICommandInvokedHandler(OnUICommand)));
33 await msgDialog.ShowAsync();
34 }
35
36 /// <summary>
37 /// 单击确定时回调事件
38 /// </summary>
39 /// <param name="cmd"></param>
40 async void OnUICommand(IUICommand cmd)
41 {
42 await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
43 {
44
45 });
46 }
47
48 /// <summary>
49 /// ListView 选中触发事件
50 /// </summary>
51 /// <param name="sender"></param>
52 /// <param name="e"></param>
53 private void Item_click( object sender, SelectionChangedEventArgs e)
54 {
55 if (e.AddedItems.Count > 0)
56 {
57 Article selectedItem = e.AddedItems[ 0] as Article;
58 if (selectedItem != null)
59 {
60 // 获取选中文章,展示文章详细信息,因SelectedArticle 属性实现了NotifyPropertyChanged事件,当SelectedArticle值发生变化时,自动更新UI
61 viewModel.SelectedArticle = selectedItem;
62 // Webview显示HTML脚本,暂时没发现Webview直接绑定显示HMTL的,只能直接赋值
63 ContentView.NavigateToString(selectedItem.Content);
64 }
65 }
66 }
67 }
68 }
好了,晚了,今天就写到这了,下一篇准备写一下Window8 Metro开发之数据存储!
Title
编程在线网站:http://www.cnblogs.com/hubcarl/archive/2012/11/18/2776608.html
编程在线Windows8 客户端:http://www.cnblogs.com/hubcarl/archive/2012/11/18/2776608.html
转载于:https://www.cnblogs.com/hubcarl/archive/2012/11/22/CodeOnlive.html