zoukankan      html  css  js  c++  java
  • 编程在线Windows8客户端实现之数据绑定

          最近上网,看到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

    数据绑定,就是要保持数据对象和UI界面的同步。NET事件绑定是基于Observer模式的。在.NET2.0中,对Observer进行了一次包装,可以引用System.Component命名空间,实现INotifyPropertyChanged接口,可以获得事件PropertyChanged,以及PropertyChangedEventArgs。于是在这套体系下,事件机制事先搭建好了。
         
     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 接口,同时为绑定类型的每个属性提供更改事件。

     

    View Code
      1 namespace Windows8Study.Model
      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(thisnew PropertyChangedEventArgs(propertyName));
    116             }
    117         }
    118 
    119     }
    120 }

    Article实体类实现INotifyPropertyChanged 接口,同时为绑定类型的每个属性提供更改事件。下面就是要实现视图实体类ArticleViewModel,直接与界面进行交互对象。主要包含两个属性文章列表ArticleList和当前选中的文章SelectedArticle属性,因这两个属性值会变化,同时要更新UI,所以也要实现INotifyPropertyChanged 接口。

     

     1 /// <summary>
     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(thisnew PropertyChangedEventArgs(propertyName));
    43             }
    44         }
    45 }

     2、Style样式模板定义

            页面空间样式定义可以用两种方式:一种直接在对应XAML页面直接对控件属性定义,这个与HTML CSS 样式一样,一种是把样式定义成模板形式,把一些公共样式定义到一个文件中去,这个与CSS 样式表一样。在通过Visual Studio Express for Widows8 新建项目时,项目会自动生成一个公共的样式文件StandardStyles.xaml,这种方式也是推荐使用的一种方式,可以做到样式表统一,维护简单方便!

     <Style x:Key="BodyRichTextStyle" TargetType="RichTextBlock" BasedOn="{StaticResource BaselineRichTextStyle}">
            <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、数据目标直接定义页面当中,如下:

    View Code
     1  <ListView Grid.Row="0" Grid.Column="0" x:Name="lvArticles" Height="800" Margin="60,60,0,60"
     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属性执行数据模板。如下:

    <ListView
                
    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在文件中定义如下:

     

     1 <DataTemplate x:Key="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 弹出对话框实现

       //弹出带有确定按钮的对话框
       

    1    MessageDialog msgDialog = new 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关键字

               

    1 MessageDialog msg = new MessageDialog("按钮测试");
    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;

     好了,讲了这么多,现在把这四点运用上,直接上代码了,比较简单。

     1 namespace Windows8Study
     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[0as 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

  • 相关阅读:
    51nod 1087 1 10 100 1000(找规律+递推+stl)
    51nod 1082 与7无关的数 (打表预处理)
    51 nod 1080 两个数的平方和
    1015 水仙花数(水题)
    51 nod 1003 阶乘后面0的数量
    51nod 1002 数塔取数问题
    51 nod 1001 数组中和等于K的数对
    51 nod 1081 子段求和
    51nod 1134 最长递增子序列 (O(nlogn)算法)
    51nod 1174 区间中最大的数(RMQ)
  • 原文地址:https://www.cnblogs.com/hubcarl/p/CodeOnlive.html
Copyright © 2011-2022 走看看