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), Font = "Microsoft YaHei UI, 9pt", }; _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 } }