// COPYRIGHT (C) Tom. ALL RIGHTS RESERVED. // THE AntdUI PROJECT IS AN WINFORM LIBRARY LICENSED UNDER THE Apache-2.0 License. // LICENSED UNDER THE Apache License, VERSION 2.0 (THE "License") // YOU MAY NOT USE THIS FILE EXCEPT IN COMPLIANCE WITH THE License. // YOU MAY OBTAIN A COPY OF THE LICENSE AT // // http://www.apache.org/licenses/LICENSE-2.0 // // UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING, SOFTWARE // DISTRIBUTED UNDER THE LICENSE IS DISTRIBUTED ON AN "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. // SEE THE LICENSE FOR THE SPECIFIC LANGUAGE GOVERNING PERMISSIONS AND // LIMITATIONS UNDER THE License. // GITEE: https://gitee.com/antdui/AntdUI // GITHUB: https://github.com/AntdUI/AntdUI // CSDN: https://blog.csdn.net/v_132 // QQ: 17379620 using System.Collections; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Windows.Forms; namespace AntdUI { partial class Table { TempTable? dataTmp = null; bool dataOne = true; void ExtractData() { dataOne = true; dataTmp = null; if (columns != null) { // 重置复选状态 foreach (var item in columns) { if (item is ColumnCheck check) check.CheckState = CheckState.Unchecked; } } if (dataSource == null) { rows_Expand.Clear(); // 空数据 ScrollBar.ValueX = ScrollBar.ValueY = 0; return; } if (dataSource is DataTable table) { if (table.Columns.Count > 0 && table.Rows.Count > 0) { var columns = new List(table.Columns.Count); var rows = new List(table.Rows.Count + 1); for (int i = 0; i < table.Columns.Count; i++) columns.Add(new TempiColumn(i, table.Columns[i].ColumnName)); for (int i = 0; i < table.Rows.Count; i++) { var row = table.Rows[i]; if (row != null) { var cells = new Dictionary(columns.Count); foreach (var it in columns) cells.Add(it.key, row[it.key]); if (cells.Count > 0) rows.Add(new IRow(i, row, cells)); } } dataTmp = new TempTable(columns.ToArray(), rows.ToArray()); } } else if (dataSource is IList list) { var columns = new TempiColumn[0]; var rows = new List(list.Count + 1); for (int i = 0; i < list.Count; i++) GetRowAuto(ref rows, list[i], i, ref columns); dataTmp = new TempTable(columns, rows.ToArray()); } } #region AntList public void Binding(AntList list) { dataOne = true; if (list == null) return; dataSource = list; list.action = (code, obj) => { if (dataTmp != null) { try { if (code == "add") { if (obj is int i) { var row = list[i]; if (row != null) { var cells = GetRow(row, dataTmp.columns.Length); if (cells.Count == 0) return; int len = dataTmp.rows.Length + 1; if (len < i) return; var rows = new List(len); rows.AddRange(dataTmp.rows); rows.Insert(i, new IRow(i, row, cells)); dataTmp.rows = ChangeList(rows); LoadLayout(); Invalidate(); } } else if (obj is int[] i_s) { var _list = new List(i_s.Length); foreach (int id in i_s) { var row = list[id]; if (row != null) { var cells = GetRow(row, dataTmp.columns.Length); if (cells.Count > 0) _list.Add(new IRow(id, row, cells)); } } var rows = new List(dataTmp.rows.Length + _list.Count); rows.AddRange(dataTmp.rows); rows.InsertRange(i_s[0], _list); dataTmp.rows = ChangeList(rows); LoadLayout(); Invalidate(); } } else if (code == "edit") { LoadLayout(); Invalidate(); } else if (code == "del") { if (obj is int i) { if (i >= 0 && i < dataTmp.rows.Length) { var rows = new List(dataTmp.rows.Length); rows.AddRange(dataTmp.rows); rows.RemoveAt(i); dataTmp.rows = ChangeList(rows); LoadLayout(); Invalidate(); } } else if (obj is string) { dataTmp.rows = new IRow[0]; LoadLayout(); Invalidate(); } } } catch { // 刷新数据 IBinding(list); } } }; IBinding(list); } void IBinding(AntList list) { ExtractHeaderFixed(); var columns = new TempiColumn[0]; var rows = new List(list.Count + 1); for (int i = 0; i < list.Count; i++) GetRowAuto(ref rows, list[i], i, ref columns); dataTmp = new TempTable(columns, rows.ToArray()); LoadLayout(); Invalidate(); } #endregion #region BindingList public void Binding(BindingList list) { dataOne = true; if (list == null) return; list.ListChanged += (Sender, Args) => { BindingItem(Sender, Args); }; DataSource = list; } void BindingItem(object? sender, ListChangedEventArgs args) { switch (args.ListChangedType) { case ListChangedType.ItemAdded: BindingItemAdded(sender, args.NewIndex); break; case ListChangedType.ItemDeleted: BindingItemDeleted(sender, args.NewIndex); break; case ListChangedType.ItemChanged: BindingItemChanged(sender, args.NewIndex); break; case ListChangedType.Reset: if (dataTmp == null) return; dataTmp.rows = new IRow[0]; LoadLayout(); Invalidate(); break; case ListChangedType.ItemMoved: default: if (sender is IList list) DataSource = list; break; } } void BindingItemAdded(object? sender, int i) { if (dataTmp == null) return; if (sender is IList list) { var row = list[i]; if (row == null) return; var cells = GetRow(row, dataTmp.columns.Length); if (cells.Count == 0) return; int len = dataTmp.rows.Length + 1; if (len < i) return; var rows = new List(len); rows.AddRange(dataTmp.rows); rows.Insert(i, new IRow(i, row, cells)); dataTmp.rows = ChangeList(rows); LoadLayout(); Invalidate(); } } void BindingItemChanged(object? sender, int i) { if (dataTmp == null) return; if (sender is IList list) { var row = list[i]; if (row == null) return; var cells = GetRow(row, dataTmp.columns.Length); if (cells.Count == 0) return; int len = dataTmp.rows.Length; var rows = new List(len); rows.AddRange(dataTmp.rows); rows[i] = new IRow(i, row, cells); dataTmp.rows = ChangeList(rows); LoadLayout(); Invalidate(); } } void BindingItemDeleted(object? sender, int i) { if (dataTmp == null) return; if (sender is IList list) { var rows = new List(dataTmp.rows.Length); rows.AddRange(dataTmp.rows); rows.RemoveAt(i); dataTmp.rows = ChangeList(rows); LoadLayout(); Invalidate(); } } #endregion IRow[] ChangeList(List rows) { for (int i = 0; i < rows.Count; i++) rows[i].i = i; return rows.ToArray(); } void GetRowAuto(ref List rows, object? row, int i, ref TempiColumn[] columns) { if (row == null) return; if (row is IList arows) { var irow = new IRow(i, row, arows); rows.Add(irow); if (columns.Length == 0) { columns = new TempiColumn[arows.Count]; for (int j = 0; j < arows.Count; j++) columns[j] = new TempiColumn(j, arows[j].key); } } else { var cells = GetRowAuto(row, ref columns); if (cells.Count > 0) rows.Add(new IRow(i, row, cells)); } } Dictionary GetRowAuto(object row, ref TempiColumn[] columns) { if (columns.Length == 0) return GetRow(row, out columns); else return GetRow(row, columns.Length); } Dictionary GetRow(object row, int len) { if (row is IList arows) { var cells = new Dictionary(arows.Count); foreach (AntItem it in arows) cells.Add(it.key, it); return cells; } else { var cells = new Dictionary(len); foreach (PropertyDescriptor it in TypeDescriptor.GetProperties(row)) cells.Add(it.Name, it); return cells; } } Dictionary GetRow(object row, out TempiColumn[] _columns) { var list = TypeDescriptor.GetProperties(row); var cells = new Dictionary(list.Count); int index = 0; var columns = new List(list.Count); foreach (PropertyDescriptor it in list) { columns.Add(new TempiColumn(index, it.Name)); index++; cells.Add(it.Name, it); } _columns = columns.ToArray(); return cells; } bool showFixedColumnL = false, showFixedColumnR = false; int sFixedR = 0; List? fixedColumnL = null, fixedColumnR = null; internal void ExtractHeaderFixed() { if (columns == null) { fixedColumnL = fixedColumnR = null; return; } var dir = new List(); int index = 0; foreach (var column in columns) { if (column.Visible) { if (column.Fixed) dir.Add(index); index++; } } if (dir.Count > 0) { List _fixedColumnL = new List(), _fixedColumnR = new List(); foreach (int i in dir) { if (i == 0) _fixedColumnL.Add(i); else if (_fixedColumnL.Count > 0 && _fixedColumnL[_fixedColumnL.Count - 1] + 1 == i) _fixedColumnL.Add(i); } foreach (int it in _fixedColumnL) dir.Remove(it); if (dir.Count > 0) { dir.Reverse(); foreach (int i in dir) { if (i == index - 1) _fixedColumnR.Add(i); else if (_fixedColumnR.Count > 0 && _fixedColumnR[_fixedColumnR.Count - 1] - 1 == i) _fixedColumnR.Add(i); } } if (_fixedColumnL.Count > 0) fixedColumnL = _fixedColumnL; else fixedColumnL = null; if (_fixedColumnR.Count > 0) fixedColumnR = _fixedColumnR; else fixedColumnR = null; } else fixedColumnL = fixedColumnR = null; } class TempTable { public TempTable(TempiColumn[] _columns, IRow[] _rows) { columns = _columns; rows = _rows; } /// /// 表头 - 列 /// public TempiColumn[] columns { get; set; } /// /// 数据 - 行 /// public IRow[] rows { get; set; } } class TempiColumn { public TempiColumn(int index, string name) { i = index; key = name; } /// /// 表头名称 /// public string key { get; set; } /// /// 列序号 /// public int i { get; set; } } public class IRow { public IRow(int index, object _record, Dictionary _cells) { i = index; record = _record; cells = _cells; } public IRow(int index, object _record, IList _cells) { i = index; record = _record; cells = new Dictionary(_cells.Count); foreach (var it in _cells) cells.Add(it.key, it); } /// /// 行序号 /// public int i { get; set; } /// /// 行原始数据 /// public object record { get; set; } public Dictionary cells { get; set; } public object? this[int index] { get { if (cells == null) return null; int i = 0; foreach (var item in cells) { if (i == index) { if (item.Value is PropertyDescriptor prop) return prop.GetValue(record); else if (item.Value is AntItem it) return it.value; else return item.Value; } i++; } return null; } } public object? this[string key] { get { if (cells == null) return null; if (cells.TryGetValue(key, out var value)) { if (value is PropertyDescriptor prop) return prop.GetValue(record); else if (value is AntItem it) return it.value; else return value; } return null; } } } } }