1001 lines
37 KiB
C#
1001 lines
37 KiB
C#
using System;
|
||
using System.Collections.Generic;
|
||
using System.ComponentModel;
|
||
using System.Data;
|
||
using System.Drawing;
|
||
using System.IO;
|
||
using System.Linq;
|
||
using System.Net;
|
||
using System.Reflection;
|
||
using System.Text;
|
||
using System.Text.RegularExpressions;
|
||
using System.Threading.Tasks;
|
||
using System.Windows.Forms;
|
||
using StandardScene.Utils;
|
||
|
||
namespace StandardScene.ExtendDevice.ButtonBox
|
||
{
|
||
public partial class ButtonBoxManager : Form
|
||
{
|
||
private static ButtonBoxManager _instance = null;
|
||
private static readonly object _lock = new object();
|
||
|
||
private const string DataFileName = "ButtonBoxConfig.json";
|
||
private string _dataFilePath;
|
||
|
||
private List<ButtonBoxModel> _buttonBoxes = new List<ButtonBoxModel>();
|
||
private ButtonBoxModel _currentButtonBox = null;
|
||
private ButtonModel _currentButton = null;
|
||
|
||
/// <summary>
|
||
/// 获取单例实例
|
||
/// </summary>
|
||
public static ButtonBoxManager Instance
|
||
{
|
||
get
|
||
{
|
||
if (_instance == null || _instance.IsDisposed)
|
||
{
|
||
lock (_lock)
|
||
{
|
||
if (_instance == null || _instance.IsDisposed)
|
||
{
|
||
_instance = new ButtonBoxManager();
|
||
}
|
||
}
|
||
}
|
||
return _instance;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 私有构造函数,确保单例模式
|
||
/// </summary>
|
||
private ButtonBoxManager()
|
||
{
|
||
InitializeComponent();
|
||
// 设置数据文件路径
|
||
_dataFilePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, DataFileName);
|
||
}
|
||
|
||
private void ButtonBoxManager_Load(object sender, EventArgs e)
|
||
{
|
||
// 设置ListView的视觉样式
|
||
SetupListViewStyles();
|
||
|
||
// 设置按钮的鼠标悬停效果
|
||
SetupButtonHoverEffects();
|
||
|
||
// 初始化类型下拉框
|
||
InitializeTypeComboBox();
|
||
|
||
// 初始化触发状态下拉框
|
||
InitializeTriggerStateComboBox();
|
||
|
||
LoadData();
|
||
RefreshButtonBoxList();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 初始化触发状态下拉框
|
||
/// </summary>
|
||
private void InitializeTriggerStateComboBox()
|
||
{
|
||
comboBoxTriggerState.Items.Clear();
|
||
|
||
// 添加ButtonState枚举的所有值
|
||
foreach (ButtonState state in Enum.GetValues(typeof(ButtonState)))
|
||
{
|
||
comboBoxTriggerState.Items.Add(state.ToString());
|
||
}
|
||
|
||
// 如果没有选中项,默认选择第一个
|
||
if (comboBoxTriggerState.Items.Count > 0 && comboBoxTriggerState.SelectedIndex == -1)
|
||
{
|
||
comboBoxTriggerState.SelectedIndex = 0;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 初始化类型下拉框
|
||
/// </summary>
|
||
private void InitializeTypeComboBox()
|
||
{
|
||
comboBoxType.Items.Clear();
|
||
|
||
try
|
||
{
|
||
// 获取当前命名空间下所有继承自BasicButtonBox的类
|
||
// 跨程序集发现:按钮盒具体类型可能位于卫星插件 dll(StandardScene.Devices.ButtonBox),
|
||
// 用内核同款全域类型发现替代仅扫当前程序集的 GetExecutingAssembly。
|
||
var buttonBoxTypes = SimpleLite.Utils.UiTypeDiscovery.AllTypes()
|
||
.Where(t => t.IsClass
|
||
&& !t.IsAbstract
|
||
&& t.Namespace == typeof(BasicButtonBox).Namespace
|
||
&& t.IsSubclassOf(typeof(BasicButtonBox)))
|
||
.OrderBy(t => t.Name)
|
||
.ToList();
|
||
|
||
foreach (var type in buttonBoxTypes)
|
||
{
|
||
comboBoxType.Items.Add(type.Name);
|
||
}
|
||
|
||
// 如果没有找到任何类型,添加默认选项
|
||
if (comboBoxType.Items.Count == 0)
|
||
{
|
||
comboBoxType.Items.Add("BasicButtonBox");
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
MessageBox.Show($"Failed to init type dropdown: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||
comboBoxType.Items.Add("BasicButtonBox");
|
||
}
|
||
}
|
||
|
||
private int _buttonBoxHoverIndex = -1;
|
||
private int _buttonHoverIndex = -1;
|
||
|
||
/// <summary>
|
||
/// 设置ListView的视觉样式
|
||
/// </summary>
|
||
private void SetupListViewStyles()
|
||
{
|
||
SetupListView(buttonBoxListView,
|
||
ButtonBoxListView_DrawItem,
|
||
ButtonBoxListView_DrawSubItem,
|
||
ButtonBoxListView_DrawColumnHeader,
|
||
ButtonBoxListView_MouseMove,
|
||
ButtonBoxListView_MouseLeave);
|
||
|
||
SetupListView(buttonListView,
|
||
ButtonListView_DrawItem,
|
||
ButtonListView_DrawSubItem,
|
||
ButtonListView_DrawColumnHeader,
|
||
ButtonListView_MouseMove,
|
||
ButtonListView_MouseLeave);
|
||
}
|
||
|
||
private void SetupListView(ListView listView,
|
||
DrawListViewItemEventHandler itemHandler,
|
||
DrawListViewSubItemEventHandler subItemHandler,
|
||
DrawListViewColumnHeaderEventHandler headerHandler,
|
||
MouseEventHandler mouseMoveHandler,
|
||
EventHandler mouseLeaveHandler)
|
||
{
|
||
listView.OwnerDraw = true;
|
||
listView.BackColor = Color.White;
|
||
listView.DrawItem += itemHandler;
|
||
listView.DrawSubItem += subItemHandler;
|
||
listView.DrawColumnHeader += headerHandler;
|
||
listView.MouseMove += mouseMoveHandler;
|
||
listView.MouseLeave += mouseLeaveHandler;
|
||
|
||
// 启用双缓冲,防止重绘时的灰色覆盖
|
||
typeof(Control)?.GetProperty("DoubleBuffered", BindingFlags.Instance | BindingFlags.NonPublic)?
|
||
.SetValue(listView, true, null);
|
||
}
|
||
|
||
private static readonly Color RowEvenColor = Color.FromArgb(250, 250, 252);
|
||
private static readonly Color RowOddColor = Color.White;
|
||
private static readonly Color RowHighlightColor = Color.FromArgb(230, 240, 255);
|
||
private static readonly Color TextRegularColor = Color.FromArgb(68, 68, 68);
|
||
private static readonly Color TextHighlightColor = Color.FromArgb(51, 51, 51);
|
||
|
||
private void ButtonBoxListView_MouseMove(object sender, MouseEventArgs e)
|
||
{
|
||
UpdateHoverIndex(buttonBoxListView, e, true);
|
||
}
|
||
|
||
private void ButtonBoxListView_MouseLeave(object sender, EventArgs e)
|
||
{
|
||
ResetHoverIndex(buttonBoxListView, true);
|
||
}
|
||
|
||
private void ButtonListView_MouseMove(object sender, MouseEventArgs e)
|
||
{
|
||
UpdateHoverIndex(buttonListView, e, false);
|
||
}
|
||
|
||
private void ButtonListView_MouseLeave(object sender, EventArgs e)
|
||
{
|
||
ResetHoverIndex(buttonListView, false);
|
||
}
|
||
|
||
private void UpdateHoverIndex(ListView listView, MouseEventArgs e, bool isButtonBoxList)
|
||
{
|
||
var hoveredItem = listView.GetItemAt(e.X, e.Y);
|
||
int newIndex = hoveredItem?.Index ?? -1;
|
||
|
||
if (isButtonBoxList)
|
||
{
|
||
if (_buttonBoxHoverIndex != newIndex)
|
||
{
|
||
_buttonBoxHoverIndex = newIndex;
|
||
listView.Invalidate();
|
||
}
|
||
}
|
||
else
|
||
{
|
||
if (_buttonHoverIndex != newIndex)
|
||
{
|
||
_buttonHoverIndex = newIndex;
|
||
listView.Invalidate();
|
||
}
|
||
}
|
||
}
|
||
|
||
private void ResetHoverIndex(ListView listView, bool isButtonBoxList)
|
||
{
|
||
if (isButtonBoxList)
|
||
{
|
||
if (_buttonBoxHoverIndex != -1)
|
||
{
|
||
_buttonBoxHoverIndex = -1;
|
||
listView.Invalidate();
|
||
}
|
||
}
|
||
else
|
||
{
|
||
if (_buttonHoverIndex != -1)
|
||
{
|
||
_buttonHoverIndex = -1;
|
||
listView.Invalidate();
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 按钮盒ListView绘制项
|
||
/// </summary>
|
||
private void ButtonBoxListView_DrawItem(object sender, DrawListViewItemEventArgs e)
|
||
{
|
||
var isHighlighted = e.Item.Selected
|
||
|| e.ItemIndex == _buttonBoxHoverIndex
|
||
|| (e.State & ListViewItemStates.Focused) != 0;
|
||
|
||
var backColor = isHighlighted
|
||
? RowHighlightColor
|
||
: (e.ItemIndex % 2 == 0 ? RowEvenColor : RowOddColor);
|
||
|
||
using (var brush = new SolidBrush(backColor))
|
||
{
|
||
e.Graphics.FillRectangle(brush, e.Bounds);
|
||
}
|
||
|
||
var textColor = isHighlighted ? TextHighlightColor : TextRegularColor;
|
||
|
||
TextRenderer.DrawText(e.Graphics, e.Item.Text, e.Item.Font, e.Bounds,
|
||
textColor,
|
||
TextFormatFlags.VerticalCenter | TextFormatFlags.Left | TextFormatFlags.EndEllipsis);
|
||
|
||
e.DrawFocusRectangle();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 按钮盒ListView绘制子项
|
||
/// </summary>
|
||
private void ButtonBoxListView_DrawSubItem(object sender, DrawListViewSubItemEventArgs e)
|
||
{
|
||
var isHighlighted = e.Item.Selected
|
||
|| e.ItemIndex == _buttonBoxHoverIndex
|
||
|| (e.ItemState & ListViewItemStates.Focused) != 0;
|
||
|
||
var backColor = isHighlighted
|
||
? RowHighlightColor
|
||
: (e.ItemIndex % 2 == 0 ? RowEvenColor : RowOddColor);
|
||
|
||
using (var brush = new SolidBrush(backColor))
|
||
{
|
||
e.Graphics.FillRectangle(brush, e.Bounds);
|
||
}
|
||
|
||
var textColor = isHighlighted ? TextHighlightColor : TextRegularColor;
|
||
|
||
TextRenderer.DrawText(e.Graphics, e.SubItem.Text, e.SubItem.Font, e.Bounds,
|
||
textColor,
|
||
TextFormatFlags.VerticalCenter | TextFormatFlags.Left | TextFormatFlags.EndEllipsis);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 按钮盒ListView绘制列标题
|
||
/// </summary>
|
||
private void ButtonBoxListView_DrawColumnHeader(object sender, DrawListViewColumnHeaderEventArgs e)
|
||
{
|
||
// 绘制列标题背景
|
||
e.Graphics.FillRectangle(new SolidBrush(Color.FromArgb(245, 247, 250)), e.Bounds);
|
||
|
||
// 绘制边框
|
||
e.Graphics.DrawLine(new Pen(Color.FromArgb(220, 220, 220)),
|
||
e.Bounds.Left, e.Bounds.Bottom - 1, e.Bounds.Right, e.Bounds.Bottom - 1);
|
||
|
||
// 绘制文本
|
||
TextRenderer.DrawText(e.Graphics, e.Header.Text,
|
||
new Font("微软雅黑", 10.5F, FontStyle.Bold),
|
||
e.Bounds, Color.FromArgb(68, 68, 68),
|
||
TextFormatFlags.VerticalCenter | TextFormatFlags.Left | TextFormatFlags.HorizontalCenter);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 按钮ListView绘制项
|
||
/// </summary>
|
||
private void ButtonListView_DrawItem(object sender, DrawListViewItemEventArgs e)
|
||
{
|
||
var isHighlighted = e.Item.Selected
|
||
|| e.ItemIndex == _buttonHoverIndex
|
||
|| (e.State & ListViewItemStates.Focused) != 0;
|
||
|
||
var backColor = isHighlighted
|
||
? RowHighlightColor
|
||
: (e.ItemIndex % 2 == 0 ? RowEvenColor : RowOddColor);
|
||
|
||
using (var brush = new SolidBrush(backColor))
|
||
{
|
||
e.Graphics.FillRectangle(brush, e.Bounds);
|
||
}
|
||
|
||
var textColor = isHighlighted ? TextHighlightColor : TextRegularColor;
|
||
|
||
TextRenderer.DrawText(e.Graphics, e.Item.Text, e.Item.Font, e.Bounds,
|
||
textColor,
|
||
TextFormatFlags.VerticalCenter | TextFormatFlags.Left | TextFormatFlags.EndEllipsis);
|
||
|
||
e.DrawFocusRectangle();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 按钮ListView绘制子项
|
||
/// </summary>
|
||
private void ButtonListView_DrawSubItem(object sender, DrawListViewSubItemEventArgs e)
|
||
{
|
||
var isHighlighted = e.Item.Selected
|
||
|| e.ItemIndex == _buttonHoverIndex
|
||
|| (e.ItemState & ListViewItemStates.Focused) != 0;
|
||
|
||
var backColor = isHighlighted
|
||
? RowHighlightColor
|
||
: (e.ItemIndex % 2 == 0 ? RowEvenColor : RowOddColor);
|
||
|
||
using (var brush = new SolidBrush(backColor))
|
||
{
|
||
e.Graphics.FillRectangle(brush, e.Bounds);
|
||
}
|
||
|
||
var textColor = isHighlighted ? TextHighlightColor : TextRegularColor;
|
||
|
||
TextRenderer.DrawText(e.Graphics, e.SubItem.Text, e.SubItem.Font, e.Bounds,
|
||
textColor,
|
||
TextFormatFlags.VerticalCenter | TextFormatFlags.Left | TextFormatFlags.EndEllipsis);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 按钮ListView绘制列标题
|
||
/// </summary>
|
||
private void ButtonListView_DrawColumnHeader(object sender, DrawListViewColumnHeaderEventArgs e)
|
||
{
|
||
// 绘制列标题背景
|
||
e.Graphics.FillRectangle(new SolidBrush(Color.FromArgb(245, 247, 250)), e.Bounds);
|
||
|
||
// 绘制边框
|
||
e.Graphics.DrawLine(new Pen(Color.FromArgb(220, 220, 220)),
|
||
e.Bounds.Left, e.Bounds.Bottom - 1, e.Bounds.Right, e.Bounds.Bottom - 1);
|
||
|
||
// 绘制文本
|
||
TextRenderer.DrawText(e.Graphics, e.Header.Text,
|
||
new Font("微软雅黑", 10.5F, FontStyle.Bold),
|
||
e.Bounds, Color.FromArgb(68, 68, 68),
|
||
TextFormatFlags.VerticalCenter | TextFormatFlags.Left | TextFormatFlags.HorizontalCenter);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 设置按钮的鼠标悬停效果
|
||
/// </summary>
|
||
private void SetupButtonHoverEffects()
|
||
{
|
||
// 按钮的悬停效果现在通过FlatAppearance属性在Designer中设置
|
||
// 这里可以添加其他额外的效果,如工具提示等
|
||
}
|
||
|
||
/// <summary>
|
||
/// 刷新按钮盒列表
|
||
/// </summary>
|
||
private void RefreshButtonBoxList()
|
||
{
|
||
buttonBoxListView.Items.Clear();
|
||
foreach (var box in _buttonBoxes)
|
||
{
|
||
var item = new ListViewItem(box.Index.ToString());
|
||
item.SubItems.Add(box.Ip);
|
||
item.SubItems.Add(box.Port.ToString());
|
||
item.SubItems.Add(box.Type);
|
||
item.Tag = box;
|
||
item.UseItemStyleForSubItems = false;
|
||
buttonBoxListView.Items.Add(item);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 刷新按钮列表
|
||
/// </summary>
|
||
private void RefreshButtonList()
|
||
{
|
||
buttonListView.Items.Clear();
|
||
if (_currentButtonBox != null)
|
||
{
|
||
foreach (var button in _currentButtonBox.Buttons)
|
||
{
|
||
var item = new ListViewItem(button.Index.ToString());
|
||
item.SubItems.Add(button.TriggerState);
|
||
item.SubItems.Add(button.TriggerDelay.ToString());
|
||
item.SubItems.Add(button.TriggerMission);
|
||
item.SubItems.Add(button.TriggerMethod);
|
||
item.SubItems.Add(button.TriggerMethodParams);
|
||
item.Tag = button;
|
||
item.UseItemStyleForSubItems = false;
|
||
buttonListView.Items.Add(item);
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 按钮盒列表选择改变
|
||
/// </summary>
|
||
private void buttonBoxListView_SelectedIndexChanged(object sender, EventArgs e)
|
||
{
|
||
if (buttonBoxListView.SelectedItems.Count > 0)
|
||
{
|
||
_currentButtonBox = buttonBoxListView.SelectedItems[0].Tag as ButtonBoxModel;
|
||
if (_currentButtonBox != null)
|
||
{
|
||
// 填充按钮盒编辑区域
|
||
textBoxIp.Text = _currentButtonBox.Ip;
|
||
textBoxPort.Text = _currentButtonBox.Port.ToString();
|
||
textBoxBoxIndex.Text = _currentButtonBox.Index.ToString();
|
||
// 设置类型下拉框
|
||
if (comboBoxType.Items.Contains(_currentButtonBox.Type))
|
||
{
|
||
comboBoxType.SelectedItem = _currentButtonBox.Type;
|
||
}
|
||
else
|
||
{
|
||
comboBoxType.SelectedIndex = comboBoxType.Items.Count > 0 ? 0 : -1;
|
||
}
|
||
|
||
// 刷新按钮列表
|
||
RefreshButtonList();
|
||
}
|
||
}
|
||
else
|
||
{
|
||
_currentButtonBox = null;
|
||
ClearButtonBoxFields();
|
||
buttonListView.Items.Clear();
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 按钮列表选择改变
|
||
/// </summary>
|
||
private void buttonListView_SelectedIndexChanged(object sender, EventArgs e)
|
||
{
|
||
if (buttonListView.SelectedItems.Count > 0)
|
||
{
|
||
_currentButton = buttonListView.SelectedItems[0].Tag as ButtonModel;
|
||
if (_currentButton != null)
|
||
{
|
||
// 填充按钮编辑区域
|
||
textBoxButtonIndex.Text = _currentButton.Index.ToString();
|
||
textBoxTriggerMission.Text = _currentButton.TriggerMission;
|
||
textBoxTriggerMethod.Text = _currentButton.TriggerMethod;
|
||
textBoxTriggerMethodParams.Text = _currentButton.TriggerMethodParams;
|
||
|
||
// 设置触发状态下拉框
|
||
if (comboBoxTriggerState.Items.Contains(_currentButton.TriggerState))
|
||
{
|
||
comboBoxTriggerState.SelectedItem = _currentButton.TriggerState;
|
||
}
|
||
else
|
||
{
|
||
comboBoxTriggerState.SelectedIndex = comboBoxTriggerState.Items.Count > 0 ? 0 : -1;
|
||
}
|
||
|
||
textBoxTriggerDelay.Text = _currentButton.TriggerDelay.ToString();
|
||
}
|
||
}
|
||
else
|
||
{
|
||
_currentButton = null;
|
||
ClearButtonFields();
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 添加按钮盒
|
||
/// </summary>
|
||
private void btnAddButtonBox_Click(object sender, EventArgs e)
|
||
{
|
||
try
|
||
{
|
||
// 获取输入框的值
|
||
string ip = textBoxIp.Text.Trim();
|
||
string portText = textBoxPort.Text.Trim();
|
||
string indexText = textBoxBoxIndex.Text.Trim();
|
||
string type = comboBoxType.SelectedItem?.ToString() ?? string.Empty;
|
||
|
||
// 确定要使用的值:如果输入框不为空则使用输入值,否则使用默认值
|
||
int newIndex;
|
||
if (!string.IsNullOrWhiteSpace(indexText))
|
||
{
|
||
if (!int.TryParse(indexText, out newIndex))
|
||
{
|
||
MessageBox.Show("Index must be numeric", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||
return;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
newIndex = _buttonBoxes.Count > 0 ? _buttonBoxes.Max(b => b.Index) + 1 : 1;
|
||
}
|
||
|
||
string newIp;
|
||
if (!string.IsNullOrWhiteSpace(ip))
|
||
{
|
||
// 验证IP地址格式
|
||
if (!IsValidIpAddress(ip))
|
||
{
|
||
MessageBox.Show("Invalid IP address, e.g. 192.168.1.100", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||
return;
|
||
}
|
||
newIp = ip;
|
||
}
|
||
else
|
||
{
|
||
newIp = "192.168.1.100";
|
||
}
|
||
|
||
int newPort;
|
||
if (!string.IsNullOrWhiteSpace(portText))
|
||
{
|
||
if (!int.TryParse(portText, out newPort))
|
||
{
|
||
MessageBox.Show("Port must be numeric", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||
return;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
newPort = 502;
|
||
}
|
||
|
||
string newType;
|
||
if (!string.IsNullOrWhiteSpace(type))
|
||
{
|
||
newType = type;
|
||
}
|
||
else
|
||
{
|
||
// 如果下拉框有选项,使用第一个选项作为默认值
|
||
newType = comboBoxType.Items.Count > 0 ? comboBoxType.Items[0].ToString() : "BasicButtonBox";
|
||
}
|
||
|
||
// 检查编码是否重复
|
||
if (_buttonBoxes.Any(b => b.Index == newIndex))
|
||
{
|
||
MessageBox.Show($"Index {newIndex} already exists, use another", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||
return;
|
||
}
|
||
|
||
// 检查IP地址是否重复
|
||
if (_buttonBoxes.Any(b => b.Ip == newIp))
|
||
{
|
||
MessageBox.Show($"IP {newIp} already exists, use another", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||
return;
|
||
}
|
||
|
||
var newBox = new ButtonBoxModel
|
||
{
|
||
Index = newIndex,
|
||
Ip = newIp,
|
||
Port = newPort,
|
||
Type = newType
|
||
};
|
||
|
||
_buttonBoxes.Add(newBox);
|
||
RefreshButtonBoxList();
|
||
SaveData();
|
||
|
||
// 选中新添加的按钮盒
|
||
foreach (ListViewItem item in buttonBoxListView.Items)
|
||
{
|
||
if (item.Tag == newBox)
|
||
{
|
||
item.Selected = true;
|
||
item.EnsureVisible();
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
MessageBox.Show($"Failed to add button box: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 删除按钮盒
|
||
/// </summary>
|
||
private void btnDeleteButtonBox_Click(object sender, EventArgs e)
|
||
{
|
||
if (_currentButtonBox == null)
|
||
{
|
||
MessageBox.Show("Please select a button box to delete", "Info", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||
return;
|
||
}
|
||
|
||
var result = MessageBox.Show($"Delete button box with index {_currentButtonBox.Index}?", "Confirm delete",
|
||
MessageBoxButtons.YesNo, MessageBoxIcon.Question);
|
||
|
||
if (result == DialogResult.Yes)
|
||
{
|
||
_buttonBoxes.Remove(_currentButtonBox);
|
||
_currentButtonBox = null;
|
||
ClearButtonBoxFields();
|
||
RefreshButtonBoxList();
|
||
buttonListView.Items.Clear();
|
||
SaveData();
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 保存按钮盒
|
||
/// </summary>
|
||
private void btnSaveButtonBox_Click(object sender, EventArgs e)
|
||
{
|
||
if (_currentButtonBox == null)
|
||
{
|
||
MessageBox.Show("Please select a button box to save", "Info", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||
return;
|
||
}
|
||
|
||
try
|
||
{
|
||
string newIp = textBoxIp.Text.Trim();
|
||
|
||
// 验证IP地址格式
|
||
if (!IsValidIpAddress(newIp))
|
||
{
|
||
MessageBox.Show("Invalid IP address, e.g. 192.168.1.100", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||
return;
|
||
}
|
||
|
||
if (!int.TryParse(textBoxPort.Text, out int port))
|
||
{
|
||
MessageBox.Show("Port must be numeric", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||
return;
|
||
}
|
||
_currentButtonBox.Port = port;
|
||
|
||
if (!int.TryParse(textBoxBoxIndex.Text, out int index))
|
||
{
|
||
MessageBox.Show("Index must be numeric", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||
return;
|
||
}
|
||
|
||
// 检查编码是否重复(排除当前项)
|
||
if (_buttonBoxes.Any(b => b.Index == index && b != _currentButtonBox))
|
||
{
|
||
MessageBox.Show($"Index {index} already exists, use another", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||
return;
|
||
}
|
||
|
||
// 检查IP地址是否重复(排除当前项)
|
||
if (_buttonBoxes.Any(b => b.Ip == newIp && b != _currentButtonBox))
|
||
{
|
||
MessageBox.Show($"IP {newIp} already exists, use another", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||
return;
|
||
}
|
||
|
||
_currentButtonBox.Index = index;
|
||
_currentButtonBox.Type = comboBoxType.SelectedItem?.ToString() ?? string.Empty;
|
||
_currentButtonBox.Ip = newIp;
|
||
|
||
RefreshButtonBoxList();
|
||
SaveData();
|
||
MessageBox.Show("Saved", "Info", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
MessageBox.Show($"Save failed: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 添加按钮
|
||
/// </summary>
|
||
private void btnAddButton_Click(object sender, EventArgs e)
|
||
{
|
||
if (_currentButtonBox == null)
|
||
{
|
||
MessageBox.Show("Please select a button box first", "Info", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||
return;
|
||
}
|
||
|
||
try
|
||
{
|
||
// 获取输入框的值
|
||
string indexText = textBoxButtonIndex.Text.Trim();
|
||
string triggerMission = textBoxTriggerMission.Text.Trim();
|
||
string triggerMethod = textBoxTriggerMethod.Text.Trim();
|
||
string triggerMethodParams = textBoxTriggerMethodParams.Text.Trim();
|
||
string triggerState = comboBoxTriggerState.SelectedItem?.ToString() ?? string.Empty;
|
||
string triggerDelayText = textBoxTriggerDelay.Text.Trim();
|
||
|
||
// 确定要使用的值:如果输入框不为空则使用输入值,否则使用默认值
|
||
int newIndex;
|
||
if (!string.IsNullOrWhiteSpace(indexText))
|
||
{
|
||
if (!int.TryParse(indexText, out newIndex))
|
||
{
|
||
MessageBox.Show("Button index must be numeric", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||
return;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
newIndex = _currentButtonBox.Buttons.Count > 0
|
||
? _currentButtonBox.Buttons.Max(b => b.Index) + 1
|
||
: 1;
|
||
}
|
||
|
||
// 检查按钮编码是否重复
|
||
if (_currentButtonBox.Buttons.Any(b => b.Index == newIndex))
|
||
{
|
||
MessageBox.Show($"Button index {newIndex} already exists, use another", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||
return;
|
||
}
|
||
|
||
// 解析触发延迟(必须是ushort类型,范围0-65535)
|
||
ushort triggerDelay = 0;
|
||
if (!string.IsNullOrWhiteSpace(triggerDelayText))
|
||
{
|
||
if (!ushort.TryParse(triggerDelayText, out triggerDelay))
|
||
{
|
||
MessageBox.Show("Trigger delay must be 0-65535", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||
return;
|
||
}
|
||
}
|
||
|
||
var newButton = new ButtonModel
|
||
{
|
||
Index = newIndex,
|
||
TriggerMission = triggerMission,
|
||
TriggerMethod = triggerMethod,
|
||
TriggerMethodParams = triggerMethodParams,
|
||
TriggerState = triggerState,
|
||
TriggerDelay = triggerDelay
|
||
};
|
||
|
||
_currentButtonBox.Buttons.Add(newButton);
|
||
RefreshButtonList();
|
||
SaveData();
|
||
|
||
// 选中新添加的按钮
|
||
foreach (ListViewItem item in buttonListView.Items)
|
||
{
|
||
if (item.Tag == newButton)
|
||
{
|
||
item.Selected = true;
|
||
item.EnsureVisible();
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
MessageBox.Show($"Failed to add button: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 删除按钮
|
||
/// </summary>
|
||
private void btnDeleteButton_Click(object sender, EventArgs e)
|
||
{
|
||
if (_currentButtonBox == null)
|
||
{
|
||
MessageBox.Show("Please select a button box first", "Info", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||
return;
|
||
}
|
||
|
||
if (_currentButton == null)
|
||
{
|
||
MessageBox.Show("Please select a button to delete", "Info", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||
return;
|
||
}
|
||
|
||
var result = MessageBox.Show($"Delete button with index {_currentButton.Index}?", "Confirm delete",
|
||
MessageBoxButtons.YesNo, MessageBoxIcon.Question);
|
||
|
||
if (result == DialogResult.Yes)
|
||
{
|
||
_currentButtonBox.Buttons.Remove(_currentButton);
|
||
_currentButton = null;
|
||
ClearButtonFields();
|
||
RefreshButtonList();
|
||
SaveData();
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 保存按钮
|
||
/// </summary>
|
||
private void btnSaveButton_Click(object sender, EventArgs e)
|
||
{
|
||
if (_currentButtonBox == null)
|
||
{
|
||
MessageBox.Show("Please select a button box first", "Info", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||
return;
|
||
}
|
||
|
||
if (_currentButton == null)
|
||
{
|
||
MessageBox.Show("Please select a button to save", "Info", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||
return;
|
||
}
|
||
|
||
try
|
||
{
|
||
if (!int.TryParse(textBoxButtonIndex.Text, out int index))
|
||
{
|
||
MessageBox.Show("Button index must be numeric", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||
return;
|
||
}
|
||
|
||
// 检查按钮编码是否重复(排除当前按钮)
|
||
if (_currentButtonBox.Buttons.Any(b => b.Index == index && b != _currentButton))
|
||
{
|
||
MessageBox.Show($"Button index {index} already exists, use another", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||
return;
|
||
}
|
||
|
||
// 验证触发延迟(必须是ushort类型,范围0-65535)
|
||
if (!ushort.TryParse(textBoxTriggerDelay.Text, out ushort triggerDelay))
|
||
{
|
||
MessageBox.Show("Trigger delay must be 0-65535", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||
return;
|
||
}
|
||
|
||
_currentButton.Index = index;
|
||
_currentButton.TriggerMission = textBoxTriggerMission.Text;
|
||
_currentButton.TriggerMethod = textBoxTriggerMethod.Text;
|
||
_currentButton.TriggerMethodParams = textBoxTriggerMethodParams.Text;
|
||
_currentButton.TriggerState = comboBoxTriggerState.SelectedItem?.ToString() ?? string.Empty;
|
||
_currentButton.TriggerDelay = triggerDelay;
|
||
|
||
RefreshButtonList();
|
||
SaveData();
|
||
MessageBox.Show("Saved", "Info", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
MessageBox.Show($"Save failed: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 清空按钮盒字段
|
||
/// </summary>
|
||
private void ClearButtonBoxFields()
|
||
{
|
||
textBoxIp.Text = string.Empty;
|
||
textBoxPort.Text = string.Empty;
|
||
textBoxBoxIndex.Text = string.Empty;
|
||
comboBoxType.SelectedIndex = -1;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 清空按钮字段
|
||
/// </summary>
|
||
private void ClearButtonFields()
|
||
{
|
||
textBoxButtonIndex.Text = string.Empty;
|
||
textBoxTriggerMission.Text = string.Empty;
|
||
textBoxTriggerMethod.Text = string.Empty;
|
||
textBoxTriggerMethodParams.Text = string.Empty;
|
||
comboBoxTriggerState.SelectedIndex = comboBoxTriggerState.Items.Count > 0 ? 0 : -1;
|
||
textBoxTriggerDelay.Text = string.Empty;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 加载数据
|
||
/// </summary>
|
||
private void LoadData()
|
||
{
|
||
try
|
||
{
|
||
if (File.Exists(_dataFilePath))
|
||
{
|
||
var jsonContent = File.ReadAllText(_dataFilePath, Encoding.UTF8);
|
||
if (!string.IsNullOrWhiteSpace(jsonContent))
|
||
{
|
||
_buttonBoxes = jsonContent.JsonTo<List<ButtonBoxModel>>();
|
||
if (_buttonBoxes == null)
|
||
{
|
||
_buttonBoxes = new List<ButtonBoxModel>();
|
||
}
|
||
}
|
||
else
|
||
{
|
||
_buttonBoxes = new List<ButtonBoxModel>();
|
||
}
|
||
}
|
||
else
|
||
{
|
||
_buttonBoxes = new List<ButtonBoxModel>();
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
MessageBox.Show($"Load data failed: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||
_buttonBoxes = new List<ButtonBoxModel>();
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 保存数据
|
||
/// </summary>
|
||
private void SaveData()
|
||
{
|
||
try
|
||
{
|
||
var jsonContent = _buttonBoxes.ToJson();
|
||
File.WriteAllText(_dataFilePath, jsonContent, Encoding.UTF8);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
MessageBox.Show($"Save data failed: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 验证IP地址格式
|
||
/// </summary>
|
||
/// <param name="ipAddress">IP地址字符串</param>
|
||
/// <returns>如果格式正确返回true,否则返回false</returns>
|
||
private bool IsValidIpAddress(string ipAddress)
|
||
{
|
||
if (string.IsNullOrWhiteSpace(ipAddress))
|
||
{
|
||
return false;
|
||
}
|
||
|
||
// 使用正则表达式验证IP地址格式(IPv4)
|
||
string pattern = @"^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$";
|
||
if (Regex.IsMatch(ipAddress, pattern))
|
||
{
|
||
// 使用System.Net.IPAddress.TryParse进行二次验证
|
||
IPAddress address;
|
||
return IPAddress.TryParse(ipAddress, out address) && address.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork;
|
||
}
|
||
|
||
return false;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 窗体关闭事件
|
||
/// </summary>
|
||
private void ButtonBoxManager_FormClosing(object sender, FormClosingEventArgs e)
|
||
{
|
||
if (e.CloseReason == CloseReason.UserClosing)
|
||
{
|
||
// 关闭前保存数据
|
||
SaveData();
|
||
e.Cancel = true;
|
||
this.Visible = false;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|