• WPF 之 ObservableCollection 动态数据集合的使用(二)


    一、 ObservableCollection 动态数据集合

    在许多情况下,我们使用的数据是对象的集合。 例如,数据绑定中的常见方案是使用 ItemsControl ListBoxListView 或等 TreeView 来显示记录集合。

    但是,若要设置动态绑定,以便集合中的插入或删除操作 UI 自动更新,该集合必须实现 INotifyCollectionChanged 接口。 此接口需要公开 CollectionChanged 事件,即每当基础集合发生更改时应引发的事件。

    WPF 提供 ObservableCollection 类,该类是实现接口的数据集合的内置实现 INotifyCollectionChanged 。它表示一个动态数据集合,它可在添加、删除项目或刷新整个列表时提供通知。

    二、ObservableCollection 与 UI 的绑定

    例如,我们实现一个如下需求:

    (1)显示一个数据集,内容包括学生的姓名、年龄、所属班级信息;(2)能够对该数据集进行增加、删除、移动、清空等操作。具体 UI 如下图所示:

    img

    我们先声明一个 Model,用于保存学生信息,再声明一个 ViewModel ,用于 Model 与 UI 之间进行信息同步(具体绑定步骤见 WPF 之 INotifyPropertyChanged 接口的使用 (一)):

     1     /// <summary>
     2     /// Model
     3     /// </summary>
     4     public class Student
     5     {
     6         public string Name { get; set; }
     7         public long Age { get; set; }
     8         public string Grades { get; set; }
     9     }
    10     
    11     /// <summary>
    12     /// ViewModel
    13     /// </summary>
    14     public class Window2VM:NotifyProperty
    15     {
    16         private ObservableCollection<Student> _nameCollection;
    17 
    18         public ObservableCollection<Student> NamesCollection
    19         {
    20             get => _nameCollection;
    21             set => SetProperty(ref _nameCollection, value);
    22         }
    23 
    24         public Window2VM()
    25         {
    26             NamesCollection = new ObservableCollection<Student>()
    27             {
    28                new Student(){Name = "dwayne",Age = 12,Grades = "7年级·3班",},
    29                new Student(){Name = "john",Age = 15,Grades = "8年级·5班",},
    30                new Student(){Name = "linq",Age = 14,Grades = "8年级·1班",},
    31                new Student(){Name = "cool",Age = 11,Grades = "7年级·6班",},
    32                new Student(){Name = "team",Age = 16,Grades = "9年级·3班",},
    33             };
    34         }
    35     }
    

    然后把该 ViewModel 绑定到 XAML 上

     1 <Window x:Class="UI.Window2"
     2         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
     3         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
     4         xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
     5         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
     6         xmlns:local="clr-namespace:UI"
     7         mc:Ignorable="d"
     8         d:DataContext="{d:DesignInstance local:Window2VM}"
     9         Title="Window2" Height="400" Width="500">
    10     <StackPanel>
    11        <UniformGrid Columns="2" Height="120">
    12            <Button Margin="5" Content="Add" Click="ButtonAdd_OnClick"></Button>
    13            <Button Margin="5" Content="Remove" Click="ButtonRemove_OnClick"></Button>
    14            <Button Margin="5" Content="Move" Click="ButtonMove_OnClick"></Button>
    15            <Button Margin="5" Content="Clear" Click="ButtonClear_OnClick"></Button>
    16        </UniformGrid>
    17         <DataGrid Margin="5" Height="200" ColumnWidth="150" ItemsSource="{Binding NamesCollection}"></DataGrid>
    18     </StackPanel>
    19 </Window>
    

    增删操作代码:

     1     /// <summary>
     2     /// Window2.xaml 的交互逻辑
     3     /// </summary>
     4     public partial class Window2 : Window
     5     {
     6         private Window2VM vm;
     7         public Window2()
     8         {
     9             InitializeComponent();
    10 
    11             this.DataContext=vm=new Window2VM();
    12         }
    13 
    14 
    15         private void ButtonAdd_OnClick(object sender, RoutedEventArgs e)
    16         {
    17 
    18             vm.NamesCollection.Add(new Student()
    19             {
    20                 Name=$"Test-{new DateTimeOffset(DateTime.UtcNow).ToUnixTimeMilliseconds()}",
    21                 Age = new DateTimeOffset(DateTime.UtcNow).ToUnixTimeMilliseconds()/1000,
    22                 Grades = $"{new Random().Next(7,10)}年级·{new Random().Next(1, 10)}班",
    23             });
    24         }
    25 
    26         private void ButtonRemove_OnClick(object sender, RoutedEventArgs e)
    27         {
    28             vm.NamesCollection.RemoveAt(0);
    29         }
    30 
    31         private void ButtonMove_OnClick(object sender, RoutedEventArgs e)
    32         {
    33             vm.NamesCollection.Move(vm.NamesCollection.Count-1,0);
    34         }
    35 
    36         private void ButtonClear_OnClick(object sender, RoutedEventArgs e)
    37         {
    38             vm.NamesCollection.Clear();
    39         }
    40     }
    

    三、ObservableCollection 的 CollectionChanged 事件

    如果我们增加一个搜素功能,即输入学生姓名或年龄或班级,自动显示相关的集合,如下图所示:

    img

    我们可以一个集合用来保存学生信息,一个集合用来显示,同时当保存学生信息的集合发生变化时,显示信息的集合要同步变化,这就需要用到ObservableCollection 的 CollectionChanged 事件,具体实现如下:

     1     /// <summary>
     2     /// ViewModel
     3     /// </summary>
     4     public class Window2VM:NotifyProperty
     5     {
     6         private ObservableCollection<Student> _displayName;
     7         private string _searchContent;
     8 
     9         /// <summary>
    10         /// 保存学生信息的集合
    11         /// </summary>
    12         public ObservableCollection<Student> NamesCollection { get; set; }
    13 
    14         /// <summary>
    15         /// 展示学生信息的集合
    16         /// </summary>
    17         public ObservableCollection<Student> DisplayName
    18         {
    19             get => _displayName;
    20             set => SetProperty(ref _displayName, value);
    21         }
    22 
    23         /// <summary>
    24         /// 搜索内容
    25         /// </summary>
    26         public string SearchContent
    27         {
    28             get => _searchContent;
    29             set => SetProperty(ref _searchContent, value);
    30         }
    31 
    32         public Window2VM()
    33         {
    34             _searchContent = "";
    35             _displayName = new ObservableCollection<Student>();
    36             NamesCollection = new ObservableCollection<Student>();
    37 
    38             // 同步集合
    39             NamesCollection.CollectionChanged += (sender, e) =>
    40             {
    41                 {
    42                     switch (e.Action)
    43                     {
    44                         case NotifyCollectionChangedAction.Add:
    45                             var items = (object[])(e.NewItems.SyncRoot);
    46                             foreach (var item in items)
    47                             {
    48                                 _displayName.Add(item as Student);
    49                             }
    50                             break;
    51                         case NotifyCollectionChangedAction.Remove:
    52                             _displayName.RemoveAt(e.OldStartingIndex);
    53                             break;
    54                         case NotifyCollectionChangedAction.Reset:
    55                             _displayName.Clear();
    56                             break;
    57                         case NotifyCollectionChangedAction.Move:
    58                             _displayName.Move(e.OldStartingIndex, e.NewStartingIndex);
    59                             break;
    60                         case NotifyCollectionChangedAction.Replace:
    61                             break;
    62                     }
    63                 };
    64             };
    65             NamesCollection.Add(new Student() { Name = "dwayne", Age = 12, Grades = "7年级·3班", });
    66             NamesCollection.Add(new Student() { Name = "john", Age = 15, Grades = "8年级·5班", });
    67             NamesCollection.Add(new Student() { Name = "linq", Age = 14, Grades = "8年级·1班", });
    68             NamesCollection.Add(new Student() { Name = "cool", Age = 11, Grades = "7年级·6班", });
    69             NamesCollection.Add(new Student() { Name = "team", Age = 16, Grades = "9年级·3班", });
    70         }
    71     }
    

    搜索功能,我们可以优化一下,当搜索文本框内容发生变化时,显示集合自动发生变更,先添加 XAML代码如下:

    1         <StackPanel Orientation="Horizontal" Height="50">
    2             <TextBox Margin="5" Width="360" BorderBrush="Black" VerticalContentAlignment="Center" Text="{Binding Path=SearchContent,UpdateSourceTrigger=PropertyChanged}" TextChanged="TextBoxBase_OnTextChanged"></TextBox>
    3             <Button Margin="5" Width="100" Content="Search" Click="ButtonSearch_OnClick"></Button>
    4         </StackPanel>
    

    后台代码如下:

     1         private void ButtonSearch_OnClick(object sender, RoutedEventArgs e)
     2         {
     3             SearchCommand();
     4         }
     5 
     6         private void TextBoxBase_OnTextChanged(object sender, TextChangedEventArgs e)
     7         {
     8             SearchCommand();
     9         }
    10 
    11         private void SearchCommand()
    12         {
    13             vm.DisplayName = new ObservableCollection<Student>(vm.NamesCollection.Where(student =>
    14                 (student.Name.Contains(vm.SearchContent) || student.Age.ToString().Contains(vm.SearchContent) ||
    15                  student.Grades.Contains(vm.SearchContent))).ToList());
    16         }
    
  • 相关阅读:
    在ASP.Net中两种利用CSS实现多界面的方法
    c# 添加图片水印,可以指定水印位置+生成缩略图[付上帅图1,2,3,4]
    精力有限,本博客暂停维护,转到www.80back.com(个人的小站)
    设计一个silverlight的Button控件silverlight(银光)学习(1)
    asp.net(c#)上传图片生成缩略图
    DataGrid和存储过程结合的分页,只读取当前页数据
    c#实现google样式的分页
    asp.net MD5加密函数(c#)
    执行JS
    LoadRunner常见问题
  • 原文地址:https://www.cnblogs.com/dongweian/p/14361943.html
Copyright © 2020-2023  润新知