diff --git a/example/ChatUI/ChatUI.csproj b/example/ChatUI/ChatUI.csproj index 8718402b..74b4370d 100644 --- a/example/ChatUI/ChatUI.csproj +++ b/example/ChatUI/ChatUI.csproj @@ -7,6 +7,7 @@ true enable true + false diff --git a/example/Demo/Demo.csproj b/example/Demo/Demo.csproj index 10c705b7..eeecf29f 100644 --- a/example/Demo/Demo.csproj +++ b/example/Demo/Demo.csproj @@ -1,14 +1,15 @@ - + WinExe net9.0-windows true - true icon.ico + true + false - + 5.1 5.1 true @@ -27,11 +28,14 @@ - + + + + diff --git a/example/Demo/Program.cs b/example/Demo/Program.cs index b9c1d593..c70d5d3e 100644 --- a/example/Demo/Program.cs +++ b/example/Demo/Program.cs @@ -31,7 +31,9 @@ namespace Demo [STAThread] static void Main(string[] arge) { +#if !NET10_0 ComWrappers.RegisterForMarshalling(WinFormsComInterop.WinFormsComWrappers.Instance); +#endif var command = string.Join(" ", arge); AntdUI.Localization.DefaultLanguage = "zh-CN"; var lang = AntdUI.Localization.CurrentLanguage; diff --git a/example/FontTest/FontTest.csproj b/example/FontTest/FontTest.csproj index 1e2dccf3..74d0dea4 100644 --- a/example/FontTest/FontTest.csproj +++ b/example/FontTest/FontTest.csproj @@ -7,6 +7,7 @@ true enable true + false diff --git a/example/SVGView/SVGView.csproj b/example/SVGView/SVGView.csproj index 2ba7d424..ff203940 100644 --- a/example/SVGView/SVGView.csproj +++ b/example/SVGView/SVGView.csproj @@ -7,6 +7,7 @@ true enable true + false diff --git a/src/AntdUI/AntdUI.csproj b/src/AntdUI/AntdUI.csproj index 5cc32303..17b6adc5 100644 --- a/src/AntdUI/AntdUI.csproj +++ b/src/AntdUI/AntdUI.csproj @@ -2,7 +2,7 @@ Library - net9.0-windows;net8.0-windows;net6.0-windows;net48;net46;net40 + net10.0-windows;net9.0-windows;net8.0-windows;net6.0-windows;net48;net46;net40 enable true Tom @@ -27,7 +27,7 @@ Apache-2.0 - + diff --git a/src/AntdUI/Controls/DatePicker.cs b/src/AntdUI/Controls/DatePicker.cs index 672d2cfe..3dbfaa1c 100644 --- a/src/AntdUI/Controls/DatePicker.cs +++ b/src/AntdUI/Controls/DatePicker.cs @@ -197,6 +197,14 @@ namespace AntdUI [Description("预置点击时发生"), Category("行为")] public event ObjectNEventHandler? PresetsClickChanged; + /// + /// 下拉展开 属性值更改时发生 + /// + [Description("下拉展开 属性值更改时发生"), Category("行为")] + public event BoolEventHandler? ExpandDropChanged; + + protected virtual void OnExpandDropChanged(bool e) => ExpandDropChanged?.Invoke(this, new BoolEventArgs(e)); + #endregion #region 焦点 @@ -235,6 +243,7 @@ namespace AntdUI } } else subForm?.IClose(); + OnExpandDropChanged(value); } } diff --git a/src/AntdUI/Controls/DatePickerRange.cs b/src/AntdUI/Controls/DatePickerRange.cs index fa7a3c10..f80a38ee 100644 --- a/src/AntdUI/Controls/DatePickerRange.cs +++ b/src/AntdUI/Controls/DatePickerRange.cs @@ -303,6 +303,14 @@ namespace AntdUI [Description("预置点击时发生"), Category("行为")] public event ObjectNEventHandler? PresetsClickChanged; + /// + /// 下拉展开 属性值更改时发生 + /// + [Description("下拉展开 属性值更改时发生"), Category("行为")] + public event BoolEventHandler? ExpandDropChanged; + + protected virtual void OnExpandDropChanged(bool e) => ExpandDropChanged?.Invoke(this, new BoolEventArgs(e)); + #endregion #region 焦点 @@ -357,6 +365,7 @@ namespace AntdUI } } else subForm?.IClose(); + OnExpandDropChanged(value); } } diff --git a/src/AntdUI/Controls/Layout/GridPanel.cs b/src/AntdUI/Controls/Layout/GridPanel.cs index 10a8e127..0c7fce45 100644 --- a/src/AntdUI/Controls/Layout/GridPanel.cs +++ b/src/AntdUI/Controls/Layout/GridPanel.cs @@ -154,6 +154,8 @@ namespace AntdUI if (container is GridPanel parent && parent.IsHandleCreated) { if (parent.PauseLayout) return false; + var point = parent.PointToScreen(Point.Empty); + if (point.X == point.Y && point.X < 0 && point.Y < 0) return false; var rect = parent.DisplayRectangle; if (!string.IsNullOrEmpty(Span) && parent.Controls.Count > 0) { diff --git a/src/AntdUI/Controls/Panel.cs b/src/AntdUI/Controls/Panel.cs index 2e0a434e..99b496b1 100644 --- a/src/AntdUI/Controls/Panel.cs +++ b/src/AntdUI/Controls/Panel.cs @@ -422,17 +422,20 @@ namespace AntdUI { var g = e.Canvas; var rect_read = ReadRectangle; - float _radius = radius * Config.Dpi; - using (var path = DrawShadow(g, _radius, e.Rect, rect_read)) + if (rect_read.Width > 0 && rect_read.Height > 0) { - using (var brush = backExtend.BrushEx(rect_read, back ?? Colour.BgContainer.Get(nameof(Panel), ColorScheme))) + float _radius = radius * Config.Dpi; + using (var path = DrawShadow(g, _radius, e.Rect, rect_read)) { - g.Fill(brush, path); + using (var brush = backExtend.BrushEx(rect_read, back ?? Colour.BgContainer.Get(nameof(Panel), ColorScheme))) + { + g.Fill(brush, path); + } + if (backImage != null) g.Image(rect_read, backImage, backFit, _radius, false); + if (borderWidth > 0) g.Draw(borderColor ?? Colour.BorderColor.Get(nameof(Panel), ColorScheme), borderWidth * Config.Dpi, borderStyle, path); } - if (backImage != null) g.Image(rect_read, backImage, backFit, _radius, false); - if (borderWidth > 0) g.Draw(borderColor ?? Colour.BorderColor.Get(nameof(Panel), ColorScheme), borderWidth * Config.Dpi, borderStyle, path); + if (ArrowAlign != TAlign.None) g.FillPolygon(back ?? Colour.BgContainer.Get(nameof(Panel), ColorScheme), ArrowAlign.AlignLines(ArrowSize, e.Rect, rect_read)); } - if (ArrowAlign != TAlign.None) g.FillPolygon(back ?? Colour.BgContainer.Get(nameof(Panel), ColorScheme), ArrowAlign.AlignLines(ArrowSize, e.Rect, rect_read)); base.OnDraw(e); } diff --git a/src/AntdUI/Controls/Select.cs b/src/AntdUI/Controls/Select.cs index b35feedf..ee000d1d 100644 --- a/src/AntdUI/Controls/Select.cs +++ b/src/AntdUI/Controls/Select.cs @@ -346,6 +346,14 @@ namespace AntdUI protected virtual void OnSelectedValueChanged(object? e) => SelectedValueChanged?.Invoke(this, new ObjectNEventArgs(e)); + /// + /// 下拉展开 属性值更改时发生 + /// + [Description("下拉展开 属性值更改时发生"), Category("行为")] + public event BoolEventHandler? ExpandDropChanged; + + protected virtual void OnExpandDropChanged(bool e) => ExpandDropChanged?.Invoke(this, new BoolEventArgs(e)); + /// /// 关闭某项 时发生 /// @@ -540,6 +548,7 @@ namespace AntdUI subForm = null; filtertext = ""; } + OnExpandDropChanged(value); } } @@ -621,13 +630,43 @@ namespace AntdUI { base.OnMouseWheel(e); if (ReadOnly || !WheelModifyEnabled || items == null || items.Count == 0) return; - int newIndex; - if (e.Delta > 0) newIndex = SelectedIndex <= 0 ? items.Count - 1 : SelectedIndex - 1; - else newIndex = SelectedIndex >= items.Count - 1 ? 0 : SelectedIndex + 1; - SelectedIndex = newIndex; + SelectedIndex = IMouseWheel(items, e.Delta); if (e is HandledMouseEventArgs handled) handled.Handled = true; } + int IMouseWheel(BaseCollection items, int delta) + { + int count = items.Count, errcount = 0, newIndex; + if (delta > 0) + { + newIndex = SelectedIndex <= 0 ? items.Count - 1 : SelectedIndex - 1; + while (WheelItem(items[newIndex])) + { + errcount++; + if (errcount > count) return -1; + newIndex--; + if (newIndex < 0) newIndex = count - 1; + } + } + else + { + newIndex = SelectedIndex >= items.Count - 1 ? 0 : SelectedIndex + 1; + while (WheelItem(items[newIndex])) + { + errcount++; + if (errcount > count) return -1; + newIndex++; + if (newIndex > count - 1) newIndex = 0; + } + } + return newIndex; + } + bool WheelItem(object? it) + { + if (it is DividerSelectItem) return true; + return false; + } + #endregion #region 语言 diff --git a/src/AntdUI/Controls/SelectMultiple.cs b/src/AntdUI/Controls/SelectMultiple.cs index bbd136e7..52eee776 100644 --- a/src/AntdUI/Controls/SelectMultiple.cs +++ b/src/AntdUI/Controls/SelectMultiple.cs @@ -673,6 +673,18 @@ namespace AntdUI #endregion + #region 事件 + + /// + /// 下拉展开 属性值更改时发生 + /// + [Description("下拉展开 属性值更改时发生"), Category("行为")] + public event BoolEventHandler? ExpandDropChanged; + + protected virtual void OnExpandDropChanged(bool e) => ExpandDropChanged?.Invoke(this, new BoolEventArgs(e)); + + #endregion + #region 焦点 bool expandDrop = false; @@ -714,6 +726,7 @@ namespace AntdUI subForm?.IClose(); filtertext = ""; } + OnExpandDropChanged(value); } } diff --git a/src/AntdUI/Controls/Table/Table.Layout.cs b/src/AntdUI/Controls/Table/Table.Layout.cs index 2857b090..b84b934b 100644 --- a/src/AntdUI/Controls/Table/Table.Layout.cs +++ b/src/AntdUI/Controls/Table/Table.Layout.cs @@ -999,24 +999,39 @@ namespace AntdUI { //复选框 has_check = true; - bool value_check = false; + bool value_check = false, val_int = false; if (value is bool check) value_check = check; - return new TCellCheck(this, columnCheck, prop, ov, value_check); + else if (value is int check_int) + { + value_check = check_int > 0; + val_int = true; + } + return new TCellCheck(this, columnCheck, prop, ov, value_check, val_int); } else if (column is ColumnRadio columnRadio) { //单选框 has_check = true; - bool value_check = false; + bool value_check = false, val_int = false; if (value is bool check) value_check = check; - return new TCellRadio(this, columnRadio, prop, ov, value_check); + else if (value is int check_int) + { + value_check = check_int > 0; + val_int = true; + } + return new TCellRadio(this, columnRadio, prop, ov, value_check, val_int); } else if (column is ColumnSwitch columnSwitch) { //开关 - bool value_check = false; + bool value_check = false, val_int = false; if (value is bool check) value_check = check; - return new TCellSwitch(this, columnSwitch, prop, ov, value_check); + else if (value is int check_int) + { + value_check = check_int > 0; + val_int = true; + } + return new TCellSwitch(this, columnSwitch, prop, ov, value_check, val_int); } else if (column is ColumnSelect columnSelect) { @@ -1360,6 +1375,13 @@ namespace AntdUI if (count > 0 && nocount == count) columnCheck.Checked = value; } + void SetValueCheck(CELL_CHECK cel) => SetValueCheck(cel, !cel.Checked); + void SetValueCheck(CELL_CHECK cel, bool value) + { + cel.Checked = value; + if (cel.ValInt) SetValue(cel, value ? 1 : 0); + else SetValue(cel, value); + } void SetValue(CELL cel, object? value) { if (cel.PROPERTY == null) diff --git a/src/AntdUI/Controls/Table/Table.Mouse.cs b/src/AntdUI/Controls/Table/Table.Mouse.cs index c47c8502..e815df97 100644 --- a/src/AntdUI/Controls/Table/Table.Mouse.cs +++ b/src/AntdUI/Controls/Table/Table.Mouse.cs @@ -373,15 +373,13 @@ namespace AntdUI var value = columnCheck.Call(!checkCell.Checked, it.row.RECORD, it.i_row, it.i_cel); if (checkCell.Checked != value) { - checkCell.Checked = value; - SetValue(it.cell, checkCell.Checked); + SetValueCheck(checkCell, value); OnCheckedChanged(checkCell.Checked, it.row.RECORD, it.i_row, it.i_cel, db.col); } } else if (checkCell.AutoCheck) { - checkCell.Checked = !checkCell.Checked; - SetValue(it.cell, checkCell.Checked); + SetValueCheck(checkCell); OnCheckedChanged(checkCell.Checked, it.row.RECORD, it.i_row, it.i_cel, db.col); } } @@ -404,15 +402,10 @@ namespace AntdUI if (i != it.i_row) { var cell_selno = rows[i].cells[it.i_cel]; - if (cell_selno is TCellRadio radioCell2 && radioCell2.Checked) - { - radioCell2.Checked = false; - SetValue(cell_selno, false); - } + if (cell_selno is TCellRadio radioCell2 && radioCell2.Checked) SetValueCheck(radioCell2, false); } } - radioCell.Checked = true; - SetValue(it.cell, radioCell.Checked); + SetValueCheck(radioCell, true); OnCheckedChanged(radioCell.Checked, it.row.RECORD, it.i_row, it.i_cel, db.col); } } @@ -428,17 +421,12 @@ namespace AntdUI { var value = columnSwitch.Call(!switchCell.Checked, it.row.RECORD, it.i_row, it.i_cel); if (switchCell.Checked == value) return; - switchCell.Checked = value; - SetValue(it.cell, value); - }).ContinueWith(action => - { - switchCell.Loading = false; - }); + SetValueCheck(switchCell, value); + }).ContinueWith(action => switchCell.Loading = false); } else if (switchCell.AutoCheck) { - switchCell.Checked = !switchCell.Checked; - SetValue(it.cell, switchCell.Checked); + SetValueCheck(switchCell); OnCheckedChanged(switchCell.Checked, it.row.RECORD, it.i_row, it.i_cel, db.col); } } diff --git a/src/AntdUI/Controls/Table/Table.Template.cs b/src/AntdUI/Controls/Table/Table.Template.cs index feb80592..8e5a3ce3 100644 --- a/src/AntdUI/Controls/Table/Table.Template.cs +++ b/src/AntdUI/Controls/Table/Table.Template.cs @@ -239,7 +239,7 @@ namespace AntdUI /// /// 复选框 /// - class TCellCheck : CELL + class TCellCheck : CELL_CHECK { /// /// 复选框 @@ -249,7 +249,7 @@ namespace AntdUI /// 反射 /// 行数据 /// 值 - public TCellCheck(Table table, ColumnCheck column, PropertyDescriptor? prop, object? ov, bool value) : base(table, column, prop, ov) + public TCellCheck(Table table, ColumnCheck column, PropertyDescriptor? prop, object? ov, bool value, bool valint) : base(table, column, prop, ov, valint) { _checked = value; AnimationCheckValue = _checked ? 1F : 0F; @@ -268,7 +268,7 @@ namespace AntdUI bool _checked = false; [Description("选中状态"), Category("行为"), DefaultValue(false)] - public bool Checked + public override bool Checked { get => _checked; set @@ -327,7 +327,6 @@ namespace AntdUI #endregion public bool NoTitle { get; set; } - public bool AutoCheck { get; set; } #endregion @@ -411,7 +410,7 @@ namespace AntdUI /// /// 单选框 /// - class TCellRadio : CELL + class TCellRadio : CELL_CHECK { /// /// 单选框 @@ -421,7 +420,7 @@ namespace AntdUI /// 反射 /// 行数据 /// 值 - public TCellRadio(Table table, ColumnRadio column, PropertyDescriptor? prop, object? ov, bool value) : base(table, column, prop, ov) + public TCellRadio(Table table, ColumnRadio column, PropertyDescriptor? prop, object? ov, bool value, bool valint) : base(table, column, prop, ov, valint) { _checked = value; AnimationCheckValue = _checked ? 1F : 0F; @@ -439,7 +438,7 @@ namespace AntdUI bool _checked = false; [Description("选中状态"), Category("行为"), DefaultValue(false)] - public bool Checked + public override bool Checked { get => _checked; set @@ -497,8 +496,6 @@ namespace AntdUI #endregion - public bool AutoCheck { get; set; } - #endregion #region 布局 @@ -573,7 +570,7 @@ namespace AntdUI /// /// 开关 /// - class TCellSwitch : CELL + class TCellSwitch : CELL_CHECK { /// /// 开关 @@ -583,7 +580,7 @@ namespace AntdUI /// 反射 /// 行数据 /// 值 - public TCellSwitch(Table table, ColumnSwitch column, PropertyDescriptor? prop, object? ov, bool value) : base(table, column, prop, ov) + public TCellSwitch(Table table, ColumnSwitch column, PropertyDescriptor? prop, object? ov, bool value, bool valint) : base(table, column, prop, ov, valint) { _checked = value; AnimationCheckValue = _checked ? 1F : 0F; @@ -601,7 +598,7 @@ namespace AntdUI bool _checked = false; [Description("选中状态"), Category("行为"), DefaultValue(false)] - public bool Checked + public override bool Checked { get => _checked; set @@ -757,8 +754,6 @@ namespace AntdUI #endregion - public bool AutoCheck { get; set; } - #endregion #region 布局 @@ -845,6 +840,18 @@ namespace AntdUI public override string ToString() => Checked.ToString(); } + abstract class CELL_CHECK : CELL + { + public CELL_CHECK(Table table, Column column, PropertyDescriptor? prop, object? ov, bool val_int) : base(table, column, prop, ov) + { + ValInt = val_int; + } + + public abstract bool Checked { get; set; } + public bool AutoCheck { get; set; } + public bool ValInt { get; set; } + } + /// /// 拖拽手柄 /// diff --git a/src/AntdUI/Controls/Tabs/Tabs.cs b/src/AntdUI/Controls/Tabs/Tabs.cs index 8004f986..44acd00a 100644 --- a/src/AntdUI/Controls/Tabs/Tabs.cs +++ b/src/AntdUI/Controls/Tabs/Tabs.cs @@ -1636,21 +1636,9 @@ namespace AntdUI action_add = item => { item.PARENT = it; - bool top = it.Controls.Count == 0; item.Dock = DockStyle.Fill; - if (it.InvokeRequired) - { - it.Invoke(() => - { - it.Controls.Add(item); - if (top) item.Showed = true; - }); - } - else - { - it.Controls.Add(item); - if (top) item.Showed = true; - } + if (it.InvokeRequired) it.Invoke(() => it.Controls.Add(item)); + else it.Controls.Add(item); }; action_del = (item, index) => { @@ -1867,11 +1855,13 @@ namespace AntdUI #region 隐藏显示 bool showed = false; + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] [Description("显示的"), Category("外观"), DefaultValue(false)] public bool Showed { get => showed; - set + internal set { if (showed == value) return; showed = value; diff --git a/src/AntdUI/Controls/TimePicker.cs b/src/AntdUI/Controls/TimePicker.cs index e43a904e..8d76aefc 100644 --- a/src/AntdUI/Controls/TimePicker.cs +++ b/src/AntdUI/Controls/TimePicker.cs @@ -134,6 +134,14 @@ namespace AntdUI protected virtual void OnValueChanged(TimeSpan e) => ValueChanged?.Invoke(this, new TimeSpanNEventArgs(e)); + /// + /// 下拉展开 属性值更改时发生 + /// + [Description("下拉展开 属性值更改时发生"), Category("行为")] + public event BoolEventHandler? ExpandDropChanged; + + protected virtual void OnExpandDropChanged(bool e) => ExpandDropChanged?.Invoke(this, new BoolEventArgs(e)); + #endregion #region 焦点 @@ -172,6 +180,7 @@ namespace AntdUI } } else subForm?.IClose(); + OnExpandDropChanged(value); } } diff --git a/src/AntdUI/Forms/LayeredWindow/LayeredFormMask.cs b/src/AntdUI/Forms/LayeredWindow/LayeredFormMask.cs index 3d1adafa..e25200fa 100644 --- a/src/AntdUI/Forms/LayeredWindow/LayeredFormMask.cs +++ b/src/AntdUI/Forms/LayeredWindow/LayeredFormMask.cs @@ -73,6 +73,7 @@ namespace AntdUI public override string name => "Mask"; Func? RenderRegion; + Control[]? list; protected override void OnLoad(EventArgs e) { if (control == null) @@ -91,24 +92,32 @@ namespace AntdUI Size = owner.Size; Location = owner.Location; } + owner.VisibleChanged += Parent_VisibleChanged; } else { - if (control is TabPage page) page.ShowedChanged += Parent_VisibleChanged; - control.VisibleChanged += Parent_VisibleChanged; var point = control.PointToScreen(Point.Empty); SetLocation(point); SetSize(control.Size); Size = control.Size; Location = point; + var tmps = control.FindPARENTs(); + list = tmps.ToArray(); + foreach (var control in list) + { + if (control is TabPage page) page.ShowedChanged += Parent_VisibleChanged; + control.VisibleChanged += Parent_VisibleChanged; + control.Disposed += Parent_Disposed; + } } - owner.VisibleChanged += Parent_VisibleChanged; owner.LocationChanged += Parent_LocationChanged; owner.SizeChanged += Parent_SizeChanged; LoadVisible(); base.OnLoad(e); } + + private void Parent_Disposed(object? sender, EventArgs e) => IClose(); private void Parent_VisibleChanged(object? sender, EventArgs e) => LoadVisible(); private void Parent_LocationChanged(object? sender, EventArgs e) { @@ -177,20 +186,32 @@ namespace AntdUI } bool GetVisible() { - if (control == null) return owner.Visible; + if (list == null) return owner.Visible; else { - if (control is TabPage page) return page.Showed && page.Visible; - return control.Visible; + foreach (var control in list) + { + if (control is TabPage page) + { + if (!page.Showed) return false; + } + else if (!control.Visible) return false; + } + return true; } } protected override void Dispose(bool disposing) { - if (control != null) + if (list == null) owner.VisibleChanged -= Parent_VisibleChanged; + else { - control.VisibleChanged -= Parent_VisibleChanged; - if (control is TabPage page) page.ShowedChanged -= Parent_VisibleChanged; + foreach (var control in list) + { + control.Disposed -= Parent_Disposed; + control.VisibleChanged -= Parent_VisibleChanged; + if (control is TabPage page) page.ShowedChanged -= Parent_VisibleChanged; + } } owner.LocationChanged -= Parent_LocationChanged; owner.SizeChanged -= Parent_SizeChanged; diff --git a/src/AntdUI/Lib/Helper/Helper.cs b/src/AntdUI/Lib/Helper/Helper.cs index abc2f25e..6711b208 100644 --- a/src/AntdUI/Lib/Helper/Helper.cs +++ b/src/AntdUI/Lib/Helper/Helper.cs @@ -101,6 +101,42 @@ namespace AntdUI else if (target.Value is Control control) return FindPARENT(control.Parent, mdi); return null; } + + public static List FindPARENTs(this Control control, bool mdi = false) + { + var list = new List(2); + if (control is DoubleBufferForm formd) + { + list.Add(formd); + if (formd.Tag is Form form) + { + list.Add(form); + return list; + } + else if (formd.Parent != null) + { + var tmp = FindPARENTs(formd.Parent, mdi); + if (tmp != null) list.AddRange(tmp); + return list; + } + else return list; + } + else if (control is Form form) + { + if (mdi) list.Add(form); + else list.Add(form.ParentForm ?? form); + return list; + } + else if (control.Parent != null) + { + list.Add(control); + var tmp = FindPARENTs(control.Parent, mdi); + if (tmp != null) list.AddRange(tmp); + } + else list.Add(control); + return list; + } + public static bool SetTopMost(this Control? control, IntPtr hand) { var form = control.FindPARENT();