• 编程在线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

  • 相关阅读:
    chrome——关于chrome浏览器的奇葩问题
    vscode——配置终端集成bash和cmd
    AndroidStudio——Android SDK
    Navicat——如何导出所有的查询数据
    mpvue——实现点击数组内的某一元素进行置顶(排序第一)操作
    TP5.x——开启跨域访问
    TP5.x——聊天列表查询
    MarkDowm——语法篇
    写一个整数四则运算的解析器——语法分析部分
    写一个整数四则运算的解析器——词法分析部分
  • 原文地址:https://www.cnblogs.com/hubcarl/p/CodeOnlive.html
Copyright © 2020-2023  润新知