一个简单的类实现C#配置窗体中所有配置值变化的监听(附源代码)

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/weixin_43145361/article/details/100051937

问题描述

在配置窗体中,为了更好地提高用户体验,当某个值发生变化时,需要向用户提供是否保存。如果没有变化则不需要。举例说明。如下图所示,在这个界面有四配置内容:通用参数配置、压力源配置、温度配置和传感器配置。在每类配置中,又有很多具体的配置项。左上角的保存默认是灰色的,如果修改了任何一个值,那么就需要将保存按键亮起,同时如果此后用户退出或关闭窗体,要有相应的提醒,告之用户数据已经修改,询问是否需要保存。
在这里插入图片描述
需求不难理解,但是问题是,在配置项很多时,一个个检测不仅代码量大,而且当控件发生变更时,又需要做相应的处理。所以,为了解决此问题,本文提出了一种简易的方法,能够以极少的代码解决这个问题。

解决方案

第1步:获得所有控件

解决问题的关键是对那些值可能变化的控件进行监听。如果要监听,那么第一步是获得所有控件。C#的窗体控件结构是一种树形的结构,所以可以写一个遍历函数以获得所有控件。由于带有编辑功能的控件都派生于 Control 类(包括Form),所以我们只需要对此进行遍历即可。主要代码如下所示。

/// <summary>
/// 返回指定控件中的所有控件。
/// </summary>
/// <param name="control">待遍历控件。</param>
/// <param name="controls">控件列表。</param>
/// <returns></returns>
public List<Control> GetAllControls(Control control)
{
    List<Control> controls = new List<Control>();
    if (control != null)
    {
        foreach (Control subControl in control.Controls)
        {
            controls.Add(subControl);
            controls.AddRange(GetAllControls(subControl));
        }
    }
    return controls;
}

第2步:对需要监控的控件进行处理

我们使用一个全局变量 bool Modified 进行记录数据是否发生变化,然后对所需要监听的控件进行处理,主要代码如下所示:

/// 对指定窗体进行绑定,用于监听编辑控件中的值的变化。
/// </summary>
/// <param name="control"></param>
public ControlValueChangedListener(Control control)
{
    Modified = false;
    foreach (var item in GetAllControls(control))
    {
        if (item is TextBox tb)
            tb.TextChanged += (sender, e) => Modified = tb.Focused ? true : modified;
        else if (item is ComboBox cb)
            cb.TextChanged += (sender, e) => Modified = cb.Focused ? true : modified;
    }
}

如上所示,我们为TextBox控件,ComboBox控件编写了相应的事件处理代码,在数据发生变更时进行记录。由于这个函数是对窗体所有的控件有效,所以窗体中所有的TextBox控件,ComboBox控件都加上了相应的代码。

通过以上代码的编写,我们即可实现了其基本功能。为了便于操作,源代码中还加入了事件(参见附录)。

使用方法

使用此类只需要两步:

  1. 在窗体内定义一个全局变量 ControlValueChangedListener listener;
  2. 在窗体Load事件中初始化此对象 listener = new ControlValueChangedListener(this);

设置完成以后,当窗体的数据被编辑改变后,listener.Modifed 的值会相应改变,所以需要判断是否有值被修改,只需检测 listener.Modifed 的值即可。

注意事项

  1. 请在窗体所有控件都加载完成以后再初始化此类。建议在Form_Load 最后执行第2步。
  2. 如果需要在Modifed变更后执行一些操作,可以使用 ModifedChanged事件。举例来说,如果值发生变化时,我希望保存按钮 btnSave.Enable = true。具体用法为:
    listener = new ControlValueChangedListener(this);
    listener.ModifedChanged += (sender, arg) => tiSave.Enabled = true;

附录:源代码

using System;
using System.Collections.Generic;
using System.Windows.Forms;

namespace Hao
{
    /// <summary>
    /// 参数为旧值,新值和是否取消修改.
    /// </summary>
    public class ModifedChangedEventArgs : EventArgs
    {
        public bool OldValue { get; set; } = false;
        public bool NewValue { get; set; } = false;
        public bool IsCanceled { get; set; } = false;
    }

    /// <summary>
    /// 属性发生变化代理
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e">修改相关的参数。</param>
    public delegate void ControlModificationEventHandler(object sender, ModifedChangedEventArgs e);

    /// <summary>
    /// 用于对窗体中的编辑事件进行监听。
    /// </summary>
    public class ControlValueChangedListener
    {
        /// <summary>
        /// 在Modifed的值变化后触发。
        /// </summary>
        public event ControlModificationEventHandler ModifedChanged;

        bool modified = false;
        /// <summary>
        /// 控件是否已经修改,同时会触发 ModifedChanged 事件。
        /// </summary>
        public bool Modified
        {
            get { return modified; }
            set
            {
                Console.WriteLine("Old value: " + modified + "\tnew value: " + value);
                if (modified != value && ModifedChanged != null)
                {
                    ModifedChangedEventArgs args = new ModifedChangedEventArgs()
                    {
                        OldValue = modified,
                        NewValue = value,
                        IsCanceled = false
                    };
                    ModifedChanged.Invoke(this, args);
                    if (!args.IsCanceled)
                        modified = value;
                }

            }
        }

        /// <summary>
        /// 对指定窗体进行绑定,用于监听编辑控件中的值的变化。
        /// </summary>
        /// <param name="control"></param>
        public ControlValueChangedListener(Control control)
        {
            Modified = false;
            foreach (var item in GetAllControls(control))
            {
                if (item is TextBox tb)
                    tb.TextChanged += (sender, e) => Modified = tb.Focused ? true : modified;
                else if (item is ComboBox cb)
                    cb.TextChanged += (sender, e) => Modified = cb.Focused ? true : modified;
                // 如果有更多的控件需要监听,可在此加入相应的代码
            }
        }

        /// <summary>
        /// 返回指定控件其子属性。
        /// </summary>
        /// <param name="control">待遍历控件。</param>
        /// <param name="controls">控件列表。</param>
        /// <returns></returns>
        public List<Control> GetAllControls(Control control)
        {
            List<Control> controls = new List<Control>();
            if (control != null)
            {
                foreach (Control subControl in control.Controls)
                {
                    controls.Add(subControl);
                    controls.AddRange(GetAllControls(subControl));
                }
            }
            return controls;
        }
    }
}

猜你喜欢

转载自blog.csdn.net/weixin_43145361/article/details/100051937