The use of collection ObservableCollection<T> in WPF

C# collection class ObservableCollection<T>

Similar to the generic list class List<T>, represents a dynamic data collection that provides notifications when items are added or removed, or when the entire list is refreshed.

Namespace: System.Collections.ObjectModel

Inheritance relationship:

public class ObservableCollection<T> : Collection<T>, INotifyCollectionChanged, INotifyPropertyChanged

Refer to Microsoft's official website

ObservableCollection

There are two important events

public event NotifyCollectionChangedEventHandler CollectionChanged;
protected event PropertyChangedEventHandler PropertyChanged;

accomplish

INotifyCollectionChanged  INotifyPropertyChanged

annotation

In many cases, the data you work with is a collection of objects. For example, a common scenario in data binding is to use  an ItemsControl  (eg,  ListView or  TreeView  ) and a ListBox to display a collection of records.

You can enumerate   any collection that implements the IEnumerable interface. However, to set up dynamic binding so that insertions or deletions in the collection can automatically update the UI, the collection must implement the  INotifyCollectionChanged  interface. This interface exposes  the CollectionChanged  event, which is raised whenever the underlying collection changes.

WPF provides  the ObservableCollection<T>  class, which is a built-in implementation of data collection that implements  the INotifyCollectionChanged  interface.

Before implementing your own collection, consider using  ObservableCollection<T>  or one of the existing collection classes such as  List<T> , Collection <T>  ,  BindingList<T>  , etc. If you have an advanced scenario and want to implement your own collection, consider using  IList , which provides a non-generic collection of objects individually accessible by index. Implementing  IList  provides the best performance of the data binding engine.

Notice

To fully support the transfer of data values ​​from a binding source object to a binding target, each object in the collection that supports bindable properties must implement an appropriate property change notification mechanism, such as the INotifyPropertyChanged  interface  .

Test using ObservableCollection

Create a new WPF application DataGridDemo, add DataGrid and Button in the default MainWindow.xaml designer

 The relevant code of the designer of MainWindow.xaml is as follows:

The form is bound to the Loaded event, and the button is bound to the Click event

<Window x:Class="DataGridDemo.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:DataGridDemo"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800" Loaded="Window_Loaded">
    <Grid Margin="0,0,-49,0">
        <DataGrid Name="dgTest" ItemsSource="{Binding}" AutoGenerateColumns="False" HorizontalAlignment="Left" Height="387" Margin="6,6,0,0" VerticalAlignment="Top" Width="699">
            <DataGrid.Columns>
                <DataGridTextColumn Binding="{Binding EnglishName}" Width="120" Header="Mes名称"/>
                <DataGridTextColumn Binding="{Binding FieldName}" Width="120" Header="字段名称"/>
                <DataGridTextColumn Binding="{Binding MappingName}" Width="120" Header="映射名称"/>
                <DataGridTextColumn Binding="{Binding ChineseName}" Width="120" Header="中文名称"/>
                <DataGridTextColumn Binding="{Binding DataType}" Width="120" Header="数据类型"/>
                <DataGridTextColumn Binding="{Binding Value}" Width="120" Header="当前值"/>
            </DataGrid.Columns>
        </DataGrid>
        <Button x:Name="btnSaveEdit" Content="保存编辑后的数据" HorizontalAlignment="Left" Margin="712,16,0,0" VerticalAlignment="Top" Width="101" Height="58" Click="btnSaveEdit_Click"/>

    </Grid>
</Window>

New test binding class ParametricData

ParametricData.cs is as follows:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace DataGridDemo
{
    /// <summary>
    /// 需要上传的某条生产数据,由name,value,dataType等组成
    /// </summary>
    public class ParametricData
    {
        /// <summary>
        /// 中文名称,该上传数据项的描述
        /// </summary>
        public string ChineseName { get; set; }
        /// <summary>
        /// 英文名称,上传数据的键名。例如:SCGL1【输出功率1】
        /// </summary>
        public string EnglishName { get; set; }
        /// <summary>
        /// 数据表的列名或字段名,与EnglishName组成对应关系。用于手动上传出站数据时,从数据表查找数据绑定到指定的键上
        /// </summary>
        public string FieldName { get; set; }
        /// <summary>
        /// PLC地址表配置的英文名称,与EnglishName组成映射关系,用于获取实际的生产数据值
        /// </summary>
        public string MappingName { get; set; }
        /// <summary>
        /// 数据类型
        /// </summary>
        public string DataType { get; set; }
        /// <summary>
        /// 当前值
        /// </summary>
        public string Value { get; set; }
    }
}

MainWindow.xaml.cs related processing code is as follows

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace DataGridDemo
{
    /// <summary>
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
    public partial class MainWindow : Window
    {
        //List<ParametricData> ParametricDataList = new List<ParametricData>();
        System.Collections.ObjectModel.ObservableCollection<ParametricData> ParametricDataList = new System.Collections.ObjectModel.ObservableCollection<ParametricData>();
        public MainWindow()
        {
            InitializeComponent();
        }

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            for (int i = 0; i < 10; i++)
            {
                ParametricDataList.Add(new ParametricData()
                {
                    EnglishName = $"TestData{i + 1}",
                    ChineseName = $"测试数据{i + 1}",
                    FieldName = $"TestData{i + 1}",
                    MappingName = $"TestData{i + 1}",
                    DataType = "数字",
                    Value = new Random(Guid.NewGuid().GetHashCode()).Next(1, 1000).ToString("D3"),
                });
            }
            dgTest.DataContext = ParametricDataList;
        }

        private void btnSaveEdit_Click(object sender, RoutedEventArgs e)
        {
            int affectCount = 0;
            for (int i = 0; i < dgTest.Items.Count; i++)
            {
                ParametricData parametricData = dgTest.Items.GetItemAt(i) as ParametricData;
                if (parametricData == null || string.IsNullOrWhiteSpace(parametricData.EnglishName)) 
                {
                    continue;
                }
                WriteLogCsv(AppDomain.CurrentDomain.BaseDirectory + "test.csv", parametricData);
                affectCount++;
            }
            MessageBox.Show($"保存编辑后的数据成功,保存数据条数:【{affectCount}】");
        }

        /// <summary>
        /// 写CSV日志 按列显示
        /// </summary>
        /// <param name="fileName">写入的csv文件名,全路径</param>
        /// <param name="barcode">条码</param>
        /// <param name="responseResult">MES请求与返回信息对象</param>
        /// <returns></returns>
        public static bool WriteLogCsv(string fileName, ParametricData parametricData)
        {
            try
            {
                string directoryPath = System.IO.Path.GetDirectoryName(fileName);
                if (!Directory.Exists(directoryPath))
                {
                    Directory.CreateDirectory(directoryPath);
                }
                string columnContents = "Mes名称,字段名称,映射名称,中文名称,数据类型,当前值\r\n";
                if (!File.Exists(fileName))
                {
                    File.AppendAllText(fileName, columnContents, Encoding.Default);
                }

                StringBuilder sb = new StringBuilder();
                using (StreamWriter write = new StreamWriter(fileName, true, Encoding.Default))
                {
                    sb.Append($"{parametricData.EnglishName},");
                    sb.Append($"{parametricData.FieldName},");
                    sb.Append($"{parametricData.MappingName},");
                    sb.Append($"{parametricData.ChineseName},");
                    sb.Append($"{parametricData.DataType},");
                    sb.Append($"{ProcessPunctuationForCsv(parametricData.Value)}");
                    write.WriteLine(sb.ToString());
                }
                return true;
            }
            catch (Exception ex)
            {
                MessageBox.Show("CSV文件写入失败:" + ex.Message);
                return false;
            }
        }

        /// <summary>
        /// 处理csv文件中的双引号和逗号,使其在Excel中完美显示为一个单元格
        /// </summary>
        /// <param name="srcStr"></param>
        /// <returns></returns>
        private static string ProcessPunctuationForCsv(string srcStr)
        {
            if (srcStr == null)
            {
                return string.Empty;
            }
            bool quoteFlag = false;//是否添加过双引号
            //如果存在双引号,需要将字符串的一个双引号 替换为 两个双引号。并且需要在字符串的前后加上双引号
            if (srcStr.Contains("\""))
            {
                srcStr = srcStr.Replace("\"", "\"\"");
                srcStr = "\"" + srcStr + "\"";
                quoteFlag = true;
            }
            //如果只存在逗号(不存在引号),将前后加引号即可
            if (srcStr.Contains(",") && !quoteFlag)
            {
                srcStr = "\"" + srcStr + "\"";
            }
            return srcStr;
        }
    }
}

The running effect is as shown in the figure:

Guess you like

Origin blog.csdn.net/ylq1045/article/details/130846337