【wpf】实战 ItemsControl + 用户控件 + 绑定

前言

        这次是对之前学习的内容的一次实战内容,背景如下,我写了一个串口控件(用户控件)

界面上需要支持多个串口,每个串口的都有配置项,配置项需要保存到本地。

思路

        首先准备一个ItemsControl,每个子项装一个串口控件。然后,构建数据结构,每个串口对应一个SeriaInfo,然后再构建一个SeriaInfo的数组,作为数据源。由于我不想横向摆放控件,所以需要修改ItemsControl的ItemsPanel。

前台代码如下:


    
        
            
        
    
    
        
            
        
    

数据源结构如下:

public class SeriaInfo
{
    // Com 端口
    public int port { get; set; } = 0;

    //波特率
    public int baudRate { get; set; } = 0;

    //奇偶校验位
    public int parity { get; set; } = 0;

    //数据位
    public int dataBits { get; set; } = 0;

    //停止位
    public int stopBits { get; set; } = 1;

    //字节编码
    public int encoding { get; set; } = 0;


    public bool Enable { get; set; } = true;

}

public class ConfigInfos
{
    /// 
    /// 注意,一定要写成属性的形式,不然无法绑定
    /// 
    public List list_seriaInfo { get; set; } = new List ();

}

        虽然后面会用到绑定,但是这里并属性没有用到属性通知,列表也没有用到ObservableCollection而是List。是因为保存配置文件这个过程都是目标到数据源的过程,不存在程序在运行的过程中数据源变换通知到界面情况,所以普通的属性就能满足要求。(Bingding中目标到数据源的过程是默认的,界面的改变就会改变数据源,反之就需要加属性通知了)。

        由于,我们已经把用户控件放入了ItemsControl的数据模板,所以暂且不管数据源具体是什么,现在只要list_seriaInfo 有几条数据,界面就会显示几个控件。一开始是不存在配置文件的,所以我们这里可以自己先构建一个(最后实现序列化和反序列化)。

public ConfigInfos? config_infos { get; set; } = new ConfigInfos()
{
    list_seriaInfo = new List()
    {
        new SeriaInfo(),
        new SeriaInfo(),
        new SeriaInfo()
    }
};

这里,我们很容易犯的一个错误就是把 { get; set; } 忘记了,这样是绑定不成功的,因为绑定的话必须是属性,不能是字段

有了这句之后,界面上就会显示三个串口。并且是横排列的。

【wpf】实战 ItemsControl + 用户控件 + 绑定_第1张图片

数据绑定

        接下来就是数据绑定,这里需要理解的重点是,每个控件已经是ItemsControl的一个子项了,这里ItemsControl的ItemsSource绑定的是config_infos.list_seriaInfo,那每个控件对应的就是list_seriaInfo的一个元素,即SeriaInfo这个数据结构

ItemsSource="{Binding config_infos.list_seriaInfo}"

理解这一点非常重要,于是我们就可以去串口用户控件做绑定了,直接指定的就是SeriaInfo中的属性。


    
        
            
                
                
                    
                        
                        
                    
                    
                    
                
                
                
                    
                        
                        
                    
                    
                    
                        1200
                        2400
                        4800
                        9600
                        19200
                        38400
                        115200
                    
                
                
                
                    
                        
                        
                    
                    
                    
                        无(None)
                        偶校验(Even)
                        奇校验(Odd)
                        保留为0(Space)
                        保留为1(Mark)
                    
                
                
                
                    
                        
                        
                    
                    
                    
                        8
                        7
                        6
                        5
                    
                
                
                
                    
                        
                        
                    
                    
                    
                        1
                        1.5
                        2
                    
                
                
                
                    
                        
                        
                    
                    
                    
                        Default
                        ASCII
                        Unicode
                        UTF-8
                    
                
                
                    
                
                
                    
                
                
                    
                        
                        
                        
                    
                    
                    
                
            

        
    

这里我们主要关注ComboBox的SelectedIndex的绑定,这个和我们的保存像相关。由于串口的配置项是固定的,我直接写到的前台(就没有写到后台然后做绑定),这样的话我只用保存ComboBox的SelectedIndex即可。

序列化和反序列化

有了这个绑定,序列化和反序列换做起来是真的省心,省去了很多的不必要的代码

比如:

【wpf】实战 ItemsControl + 用户控件 + 绑定_第2张图片

再比如:

【wpf】实战 ItemsControl + 用户控件 + 绑定_第3张图片

还有这种事件:

【wpf】实战 ItemsControl + 用户控件 + 绑定_第4张图片

 这些统统不需要,因为界面的变化的同时,数据源已经随之更新了,我们省去赋值,直接序列化和反序列化就行啦

序列化调用

public ConfigInfoViewMode()
{
    //序列化调用
    config_infos = Read();
    // 当文件不存在时,直接构建数据,以确保界面生成
    if (config_infos == null)
    {
        config_infos = new ConfigInfos()
        {
            list_seriaInfo = new List()
            {
                new SeriaInfo(),
                new SeriaInfo(),
                new SeriaInfo()
            }
        };
    }
}

反序列化调用

// 反序列化调用
Save(config_infos);

序列化实现

/// 
/// 序列化操作  
/// 
/// 
/// 
static public void Save(T? obj)
{
    FileInfo fi = new FileInfo(_filePath);
    if (!Directory.Exists(fi.DirectoryName))
    {
        Directory.CreateDirectory(fi.DirectoryName);
    }

    StreamWriter yamlWriter = File.CreateText(_filePath);
    Serializer yamlSerializer = new Serializer();
    yamlSerializer.Serialize(yamlWriter, obj);
    yamlWriter.Close();
}

反序列化实现

/// 
/// 泛型反序列化操作  
/// 
/// 
/// 
/// 
static public T? Read()
{
    if (!File.Exists(_filePath))
    {
        return default;
    }
    StreamReader yamlReader = File.OpenText(_filePath);
    Deserializer yamlDeserializer = new Deserializer();

    //读取持久化对象  
    try
    {
        T info = yamlDeserializer.Deserialize(yamlReader);
        yamlReader.Close();
        return info;
    }
    catch (Exception)
    {
        return default;
    }
}

 最后

        关于yaml的序列化内容,可以参考我的这篇文章:

C# 配置文件的最终解决方案, yaml的序列化,反序列化_code bean的博客-CSDN博客_yaml序列化与反序列化

小结

通过 ItemsControl + 控件模板的方式,还有一个好处就是,界面的控件可以动态的递增!


内容补充

这里ComboBox 的绑定可以做一个优化,不再绑定SelectedIndex,而是加上SelectedValuePath="Content" 之后直接绑定SelectedValue,这样写道配置里的就直接是ComboBoxItem的内容,而不是一个序号,而且后续要使用这些数据的时候也更加的方便。


    BSHP
    Flame

具体细节可以参考文章:

【WPF绑定1】 ListBox/ComboBox基础绑定_code bean的博客-CSDN博客_listbox绑定下面是ListBox的基础绑定设置:DisplayMemberPath属性:显示的值SelectedValuePath属性:在选中某个Item时我们可以通过ListBox的SelectedValue属性获取的值的类型我们先构建一个listhttps://blog.csdn.net/songhuangong123/article/details/121118824?csdn_share_tail=%7B%22type%22%3A%22blog%22%2C%22rType%22%3A%22article%22%2C%22rId%22%3A%22121118824%22%2C%22source%22%3A%22songhuangong123%22%7D#:~:text=%E5%8F%91%E5%B8%83-,%E3%80%90WPF%E7%BB%91%E5%AE%9A1%E3%80%91%20ListBox/ComboBox%E5%9F%BA%E7%A1%80%E7%BB%91%E5%AE%9A,-code%20bean

你可能感兴趣的:(WPF,wpf,绑定)