From 6bdbdd813b6314178fb4796b270273f9c0ee51cd Mon Sep 17 00:00:00 2001 From: zhubanghao <58813184@qq.com> Date: Fri, 28 Mar 2025 15:22:57 +0800 Subject: [PATCH] =?UTF-8?q?inputTable=E7=BB=84=E5=90=88=E6=8E=A7=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Views/InputDemo.Designer.cs | 27 ++- Views/InputDemo.cs | 71 ++++++++ Views/SubView/InputTable.Designer.cs | 79 ++++++++ Views/SubView/InputTable.cs | 262 +++++++++++++++++++++++++++ 4 files changed, 437 insertions(+), 2 deletions(-) create mode 100644 Views/SubView/InputTable.Designer.cs create mode 100644 Views/SubView/InputTable.cs diff --git a/Views/InputDemo.Designer.cs b/Views/InputDemo.Designer.cs index 460cce2..372037e 100644 --- a/Views/InputDemo.Designer.cs +++ b/Views/InputDemo.Designer.cs @@ -80,6 +80,8 @@ this.input1 = new AntdUI.Input(); this.label3 = new AntdUI.Label(); this.tooltipComponent1 = new AntdUI.TooltipComponent(); + this.label1 = new AntdUI.Label(); + this.panel2 = new AntdUI.Panel(); this.stackPanel1.SuspendLayout(); this.flowPanel10.SuspendLayout(); this.flowPanel9.SuspendLayout(); @@ -112,6 +114,8 @@ // stackPanel1 // this.stackPanel1.AutoScroll = true; + this.stackPanel1.Controls.Add(this.panel2); + this.stackPanel1.Controls.Add(this.label1); this.stackPanel1.Controls.Add(this.flowPanel10); this.stackPanel1.Controls.Add(this.label12); this.stackPanel1.Controls.Add(this.flowPanel9); @@ -135,7 +139,7 @@ this.stackPanel1.Dock = System.Windows.Forms.DockStyle.Fill; this.stackPanel1.Location = new System.Drawing.Point(0, 74); this.stackPanel1.Name = "stackPanel1"; - this.stackPanel1.Size = new System.Drawing.Size(750, 797); + this.stackPanel1.Size = new System.Drawing.Size(750, 936); this.stackPanel1.TabIndex = 0; this.stackPanel1.Text = "stackPanel1"; this.stackPanel1.Vertical = true; @@ -660,12 +664,29 @@ this.tooltipComponent1.ArrowAlign = AntdUI.TAlign.TL; this.tooltipComponent1.Font = new System.Drawing.Font("Microsoft YaHei UI", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); // + // label1 + // + this.label1.Font = new System.Drawing.Font("Microsoft YaHei UI", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.label1.Location = new System.Drawing.Point(3, 781); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(744, 24); + this.label1.TabIndex = 31; + this.label1.Text = "Input+Popover+Table组合控件"; + // + // panel2 + // + this.panel2.Location = new System.Drawing.Point(3, 811); + this.panel2.Name = "panel2"; + this.panel2.Size = new System.Drawing.Size(744, 82); + this.panel2.TabIndex = 32; + this.panel2.Text = "panel2"; + // // InputDemo // this.Controls.Add(this.stackPanel1); this.Controls.Add(this.header1); this.Name = "InputDemo"; - this.Size = new System.Drawing.Size(750, 871); + this.Size = new System.Drawing.Size(750, 1010); this.stackPanel1.ResumeLayout(false); this.flowPanel10.ResumeLayout(false); this.flowPanel9.ResumeLayout(false); @@ -736,5 +757,7 @@ private AntdUI.Input input19; private AntdUI.Input input22; private AntdUI.Input input23; + private AntdUI.Label label1; + private AntdUI.Panel panel2; } } diff --git a/Views/InputDemo.cs b/Views/InputDemo.cs index 097389e..1102223 100644 --- a/Views/InputDemo.cs +++ b/Views/InputDemo.cs @@ -1,5 +1,7 @@ using AntdUI; using System; +using System.Collections.Generic; +using System.Drawing; using System.Text.RegularExpressions; using System.Threading.Tasks; using System.Windows.Forms; @@ -13,6 +15,7 @@ namespace AntdUIDemo.Views InitializeComponent(); // 绑定事件 BindEventHandler(); + InitInputTable(); } private void BindEventHandler() @@ -61,5 +64,73 @@ namespace AntdUIDemo.Views } return true; } + + + + #region Input+Popover+Table + + Form form; + /// + /// 小蚂蚁QQ:897252348 + /// + private void InitInputTable() + { + var customerInput = new InputTable + { + Dock = DockStyle.Fill, + Columns = + { + new Column("Code", "客户编号"), + new Column("Name", "客户名称"), + new Column("Address", "联系地址") + }, + DisplayTextFormatter = c => $"{c.Code} - {c.Name}", + DataSource = GetCustomers() + }; + + customerInput.SelectedItemChanged += (s, e) => + { + if (customerInput.SelectedItem != null) + { + AntdUI.Message.info(form, $"选中客户:{customerInput.SelectedItem.Code}", autoClose: 3); + } + }; + customerInput.SearchButtonClick += (s, e) => + { + if (customerInput.SelectedItem != null) + { + AntdUI.Message.success(form, $"选中客户:{customerInput.SelectedItem.Code}", autoClose: 3); + } + }; + customerInput.Size = new Size(300, 50); + customerInput.Location = new Point(label1.Location.X, label1.Location.Y+20); + panel2.Controls.Add(customerInput); + } + + //集合 + List GetCustomers() + { + var customers = new List(); + for (int i = 0; i < 100; i++) + { + customers.Add(new Customer + { + Address = $"地址{i}", + Code = i.ToString(), + Name = $"名字{i}", + }); + } + return customers; + } + + + // 定义实体类 + public class Customer + { + public string Code { get; set; } + public string Name { get; set; } + public string Address { get; set; } + } + #endregion } } diff --git a/Views/SubView/InputTable.Designer.cs b/Views/SubView/InputTable.Designer.cs new file mode 100644 index 0000000..30d124f --- /dev/null +++ b/Views/SubView/InputTable.Designer.cs @@ -0,0 +1,79 @@ +using System.Drawing; +using System.Windows.Forms; + +namespace AntdUIDemo +{ + partial class InputTable + { + /// + /// 必需的设计器变量。 + /// + private System.ComponentModel.IContainer components = null; + + + + #region 组件设计器生成的代码 + + /// + /// 设计器支持所需的方法 - 不要修改 + /// 使用代码编辑器修改此方法的内容。 + /// + private void InitializeComponent() + { + InputSearch = new AntdUI.Panel(); + txtSearch = new AntdUI.Input(); + btnSearch = new AntdUI.Button(); + InputSearch.SuspendLayout(); + SuspendLayout(); + // + // InputSearch + // + InputSearch.Controls.Add(txtSearch); + InputSearch.Controls.Add(btnSearch); + InputSearch.Dock = DockStyle.Fill; + InputSearch.Location = new Point(0, 0); + InputSearch.Name = "InputSearch"; + InputSearch.Size = new Size(297, 52); + InputSearch.TabIndex = 3; + InputSearch.Text = "panel1"; + // + // txtSearch + // + txtSearch.Dock = DockStyle.Fill; + txtSearch.IconRatio = 1F; + txtSearch.Location = new Point(0, 0); + txtSearch.Name = "txtSearch"; + txtSearch.PlaceholderText = "输入点什么搜索"; + txtSearch.Size = new Size(251, 52); + txtSearch.SuffixSvg = ""; + txtSearch.TabIndex = 0; + // + // btnSearch + // + btnSearch.Dock = DockStyle.Right; + btnSearch.IconRatio = 1F; + btnSearch.IconSvg = "SearchOutlined"; + btnSearch.Location = new Point(251, 0); + btnSearch.Name = "btnSearch"; + btnSearch.Size = new Size(46, 52); + btnSearch.TabIndex = 1; + btnSearch.Type = AntdUI.TTypeMini.Info; + // + // InputTable + // + AutoScaleDimensions = new SizeF(7F, 17F); + AutoScaleMode = AutoScaleMode.Font; + Controls.Add(InputSearch); + Name = "InputTable"; + Size = new Size(297, 52); + InputSearch.ResumeLayout(false); + ResumeLayout(false); + } + + #endregion + + private AntdUI.Panel InputSearch; + private AntdUI.Input txtSearch; + private AntdUI.Button btnSearch; + } +} diff --git a/Views/SubView/InputTable.cs b/Views/SubView/InputTable.cs new file mode 100644 index 0000000..dcd40fa --- /dev/null +++ b/Views/SubView/InputTable.cs @@ -0,0 +1,262 @@ +using AntdUI; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Drawing; +using System.Linq; +using System.Reflection; +using System.Windows.Forms; + +namespace AntdUIDemo +{ + /// + /// InputTable泛型控件 + /// + /// + public partial class InputTable : UserControl where T : class + { + #region 控件字段 + private Table _table; + private Form _popover; + private T _selectedItem; + #endregion + + #region 公共属性 + /// + /// 数据源集合 + /// + [Category("Data")] + [Description("数据源集合")] + public List DataSource { get; set; } = new List(); + + /// + /// 列配置集合 + /// + [Category("Data")] + [Description("列配置集合")] + public ColumnCollection Columns { get; set; } = new ColumnCollection(); + + /// + /// 搜索框占位符文本 + /// + [Category("Behavior")] + [Description("搜索框占位符文本")] + public string PlaceholderText + { + get => txtSearch.PlaceholderText; + set => txtSearch.PlaceholderText = value; + } + + /// + /// 当前选中的对象 + /// + [Browsable(false)] + public T SelectedItem + { + get => _selectedItem; + private set + { + if (EqualityComparer.Default.Equals(_selectedItem, value)) return; + _selectedItem = value; + SelectedItemChanged?.Invoke(this, EventArgs.Empty); + } + } + + /// + /// 显示文本格式化委托 + /// + [Category("Behavior")] + [Description("显示文本格式化委托")] + public Func DisplayTextFormatter { get; set; } + #endregion + + #region 事件 + /// + /// + /// + public event EventHandler SelectedItemChanged; + + /// + /// + /// + public event EventHandler SearchButtonClick; + #endregion + + #region 构造函数 + public InputTable() + { + InitializeComponent(); + txtSearch.TextChanged += TxtSearch_TextChanged; + btnSearch.Click += BtnSearch_Click; + InitializeTable(); + } + #endregion + + #region 初始化方法 + + + private void InitializeTable() + { + if (DesignMode) return; + + _table = new Table + { + Columns = Columns, + Size = new Size(txtSearch.Width, 300) + }; + _table.CellDoubleClick += Table_CellDoubleClick; + } + #endregion + + #region 核心方法 + + /// + /// 更新Table数据源 + /// + private void UpdateTableDataSource() + { + if (_table == null || _table.IsDisposed) return; + + var filtered = (List)ApplySearchFilter(DataSource).ToList(); + _table.DataSource = filtered; + } + + + private IEnumerable ApplySearchFilter(IEnumerable source) + { + if (string.IsNullOrWhiteSpace(txtSearch.Text)) + return source; + + return source.Where(item => Columns.Any(col => + { + var propValue = GetPropertyValue(item, col.Key); + return propValue.ToString().Contains(txtSearch.Text) ; + }) + ); + } + + private object GetPropertyValue(T item, string propertyName) + { + return item.GetType() + .GetProperty(propertyName, BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase)? + .GetValue(item); + } + #endregion + + #region 事件处理 + private void TxtSearch_TextChanged(object sender, EventArgs e) + { + if (_popover == null) + { + if (_table == null || _table.IsDisposed) InitializeTable(); + + UpdateTableDataSource(); + ShowPopover(); + } + else + { + UpdateTableDataSource(); + } + } + + /// + /// 获取当前对象 + /// + /// + /// + private void BtnSearch_Click(object sender, EventArgs e) + { + SearchButtonClick?.Invoke(this, e); + } + + /// + /// Table双击 + /// + /// + /// + private void Table_CellDoubleClick(object sender, TableClickEventArgs e) + { + if (e.Record is T selected) + { + SelectedItem = selected; + UpdateSearchText(selected); + ClosePopover(); + } + } + + /// + /// 释放 + /// + /// + /// + private void Popover_Disposed(object sender, EventArgs e) + { + _popover = null; + } + #endregion + + #region UI控制方法 + private void ShowPopover() + { + if (_table == null) return; + + // 动态获取实际宽度 + var controlWidth = txtSearch.Width > 10 ? txtSearch.Width : 200; // 设置默认最小值 + _table.Size = new Size(controlWidth, 300); + + _popover = Popover.open(new Popover.Config(txtSearch, _table) + { + OnControlLoad = () => BeginInvoke(new Action(() => + { + txtSearch.Focus(); + txtSearch.SelectAll(); + })) + }); + _popover.Disposed += Popover_Disposed; + } + + protected override void OnLayout(LayoutEventArgs e) + { + base.OnLayout(e); + // 布局变化时同步表格尺寸 + if (_table != null && !_table.IsDisposed) + { + _table.Width = txtSearch.Width; + } + } + + + private void ClosePopover() + { + _popover?.Close(); + _popover = null; + } + + private void UpdateSearchText(T item) + { + txtSearch.Text = DisplayTextFormatter?.Invoke(item) ?? item.ToString(); + } + #endregion + + #region 资源清理 + + + /// + /// 清理所有正在使用的资源。 + /// + /// 如果应释放托管资源,为 true;否则为 false。 + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + _table?.Dispose(); + ClosePopover(); + } + + base.Dispose(disposing); + } + + #endregion + } +}