当切换TreeView的某一个节点时,自动保存上一次节点的数据源
思路:
1.定义一个节点成员变量:记录上一次被选中的节点,当上一个节点与本节点不一致时,保存上一个节点的内容到 缓存对象中
TreeNode LastSelectedNode = null;
2.TreeView的AfterSelect事件加载当前配置,并记录选中的节点
LastSelectedNode = e.Node;
3.TreeView的BeforeSelect事件如果上一次节点 与本次的节点不一致,就先保存上一次节点的内容到内存中UpdateInterfaceInfo(LastSelectedNode.Text);
新建窗体应用程序AutoSaveTreeNodeDataDemo,将默认的Form1修改为FormSaveTreeNodeExchange,窗体设计如图:
添加对 Newtonsoft.Json.dll类库的引用。新建config.json文件,复制到输出目录:始终复制
配置文件config.json内容如下:
{
"AllConfig": [
{
"Name": "工位A进站校验接口",
"Enabled": true,
"Url": "http://abc.com/XXService?wsdl",
"ReceiveTimeout": 30000,
"UserName": "admin",
"Password": "12345",
"ListExtensionParam": [
{
"Key": "Operation",
"Val": "AAA",
"Des": "操作工站"
},
{
"Key": "Resource",
"Val": "RRR",
"Des": "资源"
},
{
"Key": "Item",
"Val": "ITEM",
"Des": ""
},
{
"Key": "ProcessMode",
"Val": "Start",
"Des": "处理方式"
}
],
"ListMesData": []
},
{
"Name": "工位A数据上传接口",
"Enabled": true,
"Url": "http://abc.com/YYService?wsdl",
"ReceiveTimeout": 30000,
"UserName": "AA",
"Password": "12345",
"ListExtensionParam": [
{
"Key": "Operation",
"Val": "AAA",
"Des": "操作工站"
},
{
"Key": "Resource",
"Val": "MMAW0012",
"Des": "资源"
},
{
"Key": "ProcessMode",
"Val": "COMPLETE_AND_POST",
"Des": "处理方式"
}
],
"ListMesData": [
{
"LocalName": "SubBarcode",
"LocalDescription": "子条码",
"MesName": "ZTM",
"DataType": "STRING",
"Unit": "",
"Value": "Sub"
},
{
"LocalName": "WorkStation",
"LocalDescription": "工位",
"MesName": "GWH",
"DataType": "NUMBER",
"Unit": "",
"Value": 1
},
{
"LocalName": "WeldSpeed",
"LocalDescription": "焊接速度",
"MesName": "HJSD",
"DataType": "NUMBER",
"Unit": "mm/s",
"Value": 200
},
{
"LocalName": "GasFlow",
"LocalDescription": "保护气流量",
"MesName": "BHQLL",
"DataType": "NUMBER",
"Unit": "",
"Value": 7.2E-3
},
{
"LocalName": "WeldVoltage",
"LocalDescription": "电压",
"MesName": "DY",
"DataType": "NUMBER",
"Unit": "伏特",
"Value": 5.67
},
{
"LocalName": "WeldPower",
"LocalDescription": "输出功率",
"MesName": "SCGL",
"DataType": "NUMBER",
"Unit": "W",
"Value": 1234.56
}
]
},
{
"Name": "工位B进站校验接口",
"Enabled": true,
"Url": "http://abc.com/ZZService?wsdl",
"ReceiveTimeout": 30000,
"UserName": "BB",
"Password": "12345",
"ListExtensionParam": [
{
"Key": "Operation",
"Val": "BBB",
"Des": "操作工站"
},
{
"Key": "Resource",
"Val": "XXX",
"Des": "资源号"
},
{
"Key": "FindInventory",
"Val": "True",
"Des": "是否查找库存"
},
{
"Key": "ProcessMode",
"Val": "CheckStatus",
"Des": "处理方式"
}
],
"ListMesData": []
},
{
"Name": "工位B数据上传接口",
"Enabled": true,
"Url": "http://abc.com/BBService?wsdl",
"ReceiveTimeout": 30000,
"UserName": "BB",
"Password": "12345",
"ListExtensionParam": [
{
"Key": "Operation",
"Val": "BBB",
"Des": "操作工站"
},
{
"Key": "Resource",
"Val": "YTR",
"Des": ""
},
{
"Key": "ProcessMode",
"Val": "COMPLETE_AND_POST",
"Des": "处理方式"
}
],
"ListMesData": [
{
"LocalName": "DataItem1",
"LocalDescription": "数据项1",
"MesName": "SJX1",
"DataType": "STRING",
"Unit": "",
"Value": "Sub"
},
{
"LocalName": "DataItem2",
"LocalDescription": "数据项2",
"MesName": "SJX2",
"DataType": "NUMBER",
"Unit": "毫米",
"Value": 1
},
{
"LocalName": "DataItem3",
"LocalDescription": "数据项3",
"MesName": "SJX3",
"DataType": "NUMBER",
"Unit": "秒",
"Value": 200
},
{
"LocalName": "DataItem4",
"LocalDescription": "数据项4",
"MesName": "SJX4",
"DataType": "NUMBER",
"Unit": "",
"Value": 7.2E-3
},
{
"LocalName": "DataItem5",
"LocalDescription": "数据项5",
"MesName": "SJX5",
"DataType": "NUMBER",
"Unit": "",
"Value": 5.67
},
{
"LocalName": "DataItem6",
"LocalDescription": "数据项6",
"MesName": "SJX6",
"DataType": "NUMBER",
"Unit": "",
"Value": 1234.56
}
]
}
]
}
新建与config.json相对应的实体类文件MesInterfaceConfig.cs。
MesInterfaceConfig.cs源程序如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AutoSaveTreeNodeDataDemo
{
/// <summary>
/// 所有接口配置
/// </summary>
public class MesInterfaceConfig
{
public MesInterfaceConfig()
{
AllConfig = new List<InterfaceConfig>();
}
/// <summary>
/// 所有接口配置列表
/// </summary>
public List<InterfaceConfig> AllConfig { get; set; }
}
/// <summary>
/// 接口基本参数,扩展参数,上传数据参数
/// </summary>
public class InterfaceConfig
{
public InterfaceConfig()
{
ListExtensionParam = new List<ExtensionParam>();
ListMesData = new List<MesData>();
}
/// <summary>
/// 接口名称
/// </summary>
public string Name { get; set; }
/// <summary>
/// 是否启用
/// </summary>
public bool Enabled { get; set; }
/// <summary>
/// Url接口地址
/// </summary>
public string Url { get; set; }
/// <summary>
/// 响应超时时间,单位ms
/// </summary>
public int ReceiveTimeout { get; set; }
/// <summary>
/// 接口用户名
/// </summary>
public string UserName { get; set; }
/// <summary>
/// 接口密码
/// </summary>
public string Password { get; set; }
/// <summary>
/// 参数集合
/// </summary>
public List<ExtensionParam> ListExtensionParam { get; set; }
/// <summary>
/// MES上传数据项集合
/// </summary>
public List<MesData> ListMesData { get; set; }
}
/// <summary>
/// 接口扩展参数
/// </summary>
public class ExtensionParam
{
/// <summary>
/// 参数键名
/// </summary>
public string Key { get; set; }
/// <summary>
/// 值
/// </summary>
public string Val { get; set; }
/// <summary>
/// 参数描述
/// </summary>
public string Des { get; set; }
}
/// <summary>
/// 某一项数据上传参数
/// </summary>
public class MesData
{
/// <summary>
/// 本地名称,一般为数据库表的字段名
/// </summary>
public string LocalName { get; set; }
/// <summary>
/// 本地描述
/// </summary>
public string LocalDescription { get; set; }
/// <summary>
/// MES名称
/// </summary>
public string MesName { get; set; }
/// <summary>
/// 数据类型
/// </summary>
public string DataType { get; set; }
/// <summary>
/// 单位
/// </summary>
public string Unit { get; set; }
/// <summary>
/// 上传的数据值
/// </summary>
public object Value { get; set; }
}
}
Json读写操作类JsonFileUtil.cs如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using Newtonsoft.Json;
namespace AutoSaveTreeNodeDataDemo
{
public class JsonFileUtil
{
#region 配置文件读写
/// <summary>
/// 将配置对象写入程序执行目录指定名称的文件
/// </summary>
/// <param name="config">配置对象</param>
/// <param name="strConfigFileFullPath">配置文件绝对路径</param>
/// <returns></returns>
public static string SaveConfig(object config, string strConfigFileFullPath, Encoding encoding = null)
{
string strRes = string.Empty;
try
{
if (config == null)
{
if (File.Exists(strConfigFileFullPath))
{
File.Delete(strConfigFileFullPath);
}
}
//使用Json缩进
string strJson = JsonConvert.SerializeObject(config, Formatting.Indented);
if (encoding == null)
{
encoding = Encoding.Default;
}
File.WriteAllText(strConfigFileFullPath, strJson, encoding);
}
catch (Exception ex)
{
strRes = ex.Message;
}
return strRes;
}
/// <summary>
/// 读取配置文件的配置信息对象
/// </summary>
/// <typeparam name="T">泛型类型</typeparam>
/// <param name="strConfigFileFullPath">配置文件的绝对路径</param>
/// <returns></returns>
public static T ReadConfig<T>(string strConfigFileFullPath, Encoding encoding) where T : class
{
T oRes = default(T);
try
{
if (File.Exists(strConfigFileFullPath))
{
string strJson = File.ReadAllText(strConfigFileFullPath, encoding);
if (!string.IsNullOrEmpty(strJson))
{
oRes = JsonConvert.DeserializeObject<T>(strJson);
}
}
}
catch (Exception ex)
{
throw ex;
}
return oRes;
}
#endregion
}
}
窗体FormSaveTreeNodeExchange.cs主要程序(忽略设计器自动生成的代码)如下:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace AutoSaveTreeNodeDataDemo
{
public partial class FormSaveTreeNodeExchange : Form
{
/// <summary>
/// 所有参数配置列表【成员变量】
/// </summary>
MesInterfaceConfig mesInterfaceConfig = new MesInterfaceConfig();
/// <summary>
/// 记录上一次被选中的节点,当上一个节点与本节点不一致时,保存上一个节点的内容到 缓存对象中
/// </summary>
TreeNode LastSelectedNode = null;
/// <summary>
/// 当前配置文件路径
/// </summary>
string curFilePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "config.json");
public FormSaveTreeNodeExchange()
{
InitializeComponent();
//绑定数据源
dgvcKey.DataPropertyName = "Key";
dgvcVal.DataPropertyName = "Val";
dgvcDes.DataPropertyName = "Des";
dgvcLocalName.DataPropertyName = "LocalName";
dgvcLocalDescription.DataPropertyName = "LocalDescription";
dgvcMesName.DataPropertyName = "MesName";
dgvcDataType.DataPropertyName = "DataType";
dgvcUnit.DataPropertyName = "Unit";
dgvcValue.DataPropertyName = "Value";
}
private void FormSaveTreeNodeExchange_Load(object sender, EventArgs e)
{
tvMesInterface.Nodes.Clear();
mesInterfaceConfig = JsonFileUtil.ReadConfig<MesInterfaceConfig>(curFilePath, Encoding.UTF8);
if (mesInterfaceConfig == null || mesInterfaceConfig.AllConfig.Count == 0)
{
MessageBox.Show($"致命错误:初始化失败,没有配置任何接口!请检查配置文件。\n{curFilePath}", "错误");
return;
}
for (int i = 0; i < mesInterfaceConfig.AllConfig.Count; i++)
{
List<string> nameCollection = new List<string>();
TreeNode treeNode = new TreeNode(mesInterfaceConfig.AllConfig[i].Name);
tvMesInterface.Nodes.Add(treeNode);
}
tvMesInterface.ExpandAll();
}
private void tvMesInterface_AfterSelect(object sender, TreeViewEventArgs e)
{
ReadConfig(e.Node.Text);
//记录选中的节点
LastSelectedNode = e.Node;
}
/// <summary>
/// 内部成员变量标记,确保BeforeSelect事件不会多次触发
/// </summary>
bool inside = false;
private void tvMesInterface_BeforeSelect(object sender, TreeViewCancelEventArgs e)
{
if (!inside)
{
inside = true;
if (LastSelectedNode != null && LastSelectedNode.Text != e.Node.Text)
{
//如果上一次节点 与本次的节点不一致,就先保存上一次节点的内容到内存中
UpdateInterfaceInfo(LastSelectedNode.Text);
}
inside = false;
}
}
/// <summary>
/// 从内存中读取配置数据
/// </summary>
/// <param name="interfaceName"></param>
private void ReadConfig(string interfaceName)
{
InterfaceConfig interfaceConfig = mesInterfaceConfig.AllConfig.Find(conf => conf.Name == interfaceName);
chkEnabled.Checked = interfaceConfig.Enabled;
txbName.Text = interfaceConfig.Name;
txbUrl.Text = interfaceConfig.Url;
txbReceiveTimeout.Text = interfaceConfig.ReceiveTimeout.ToString();
txbUserName.Text = interfaceConfig.UserName;
txbPassword.Text= interfaceConfig.Password;
dgvExtensionParam.DataSource = interfaceConfig.ListExtensionParam;
dgvMesData.DataSource = interfaceConfig.ListMesData;
}
/// <summary>
/// 更新配置数据到内存中
/// </summary>
/// <param name="interfaceName"></param>
private void UpdateInterfaceInfo(string interfaceName)
{
InterfaceConfig interfaceConfig = mesInterfaceConfig.AllConfig.Find(conf => conf.Name == interfaceName);
interfaceConfig.Enabled = chkEnabled.Checked;
interfaceConfig.Name = txbName.Text;
interfaceConfig.Url = txbUrl.Text;
interfaceConfig.ReceiveTimeout = int.Parse(txbReceiveTimeout.Text);
interfaceConfig.UserName = txbUserName.Text;
interfaceConfig.Password = txbPassword.Text;
interfaceConfig.ListExtensionParam = new List<ExtensionParam>();
for (int i = 0; i < dgvExtensionParam.Rows.Count; i++)
{
string key = Convert.ToString(dgvExtensionParam["dgvcKey", i].Value);
string val = Convert.ToString(dgvExtensionParam["dgvcVal", i].Value);
string des = Convert.ToString(dgvExtensionParam["dgvcDes", i].Value);
interfaceConfig.ListExtensionParam.Add(new ExtensionParam()
{
Key = key,
Val = val,
Des = des
});
}
interfaceConfig.ListMesData = new List<MesData>();
for (int i = 0; i < dgvMesData.Rows.Count; i++)
{
string localName = Convert.ToString(dgvMesData["dgvcLocalName", i].Value);
string localDescription = Convert.ToString(dgvMesData["dgvcLocalDescription", i].Value);
string mesName = Convert.ToString(dgvMesData["dgvcMesName", i].Value);
string dataType = Convert.ToString(dgvMesData["dgvcDataType", i].Value);
string unit = Convert.ToString(dgvMesData["dgvcUnit", i].Value);
string value = Convert.ToString(dgvMesData["dgvcValue", i].Value);
interfaceConfig.ListMesData.Add(new MesData()
{
LocalName = localName,
LocalDescription = localDescription,
MesName = mesName,
DataType = dataType,
Unit = unit,
Value = value
});
}
}
private void btnClose_Click(object sender, EventArgs e)
{
this.Close();
}
private void btnSave_Click(object sender, EventArgs e)
{
UpdateInterfaceInfo(txbName.Text);
string result = JsonFileUtil.SaveConfig(mesInterfaceConfig, curFilePath, Encoding.UTF8);
if (result.Length == 0)
{
MessageBox.Show("保存配置成功", "提示");
}
else
{
MessageBox.Show($"保存配置失败.\n{result}", "提示");
}
}
}
}
程序运行如图:
每切换一个树图节点,将自动保存上一次选中节点的内容到内存中,然后点击【保存】即可保存所有配置信息到Json文件。