👾 VirtualPanel/Segmented/Breadcrumb/Menu/Tree/Steps/Timeline 适配语言切换、修复 Menu 分割线错位、Menu 对齐 Item.Rect 方法

This commit is contained in:
Tom
2026-02-25 17:26:07 +08:00
parent 8e040f9936
commit c9a23620fc
10 changed files with 138 additions and 35 deletions

View File

@@ -7,7 +7,7 @@
<UseWindowsForms>true</UseWindowsForms>
<Authors>Tom</Authors>
<Company>Tom</Company>
<Copyright>Copyright © Tom 2021-2025</Copyright>
<Copyright>Copyright © Tom 2024-2030</Copyright>
<Product>AntdUI</Product>
<AssemblyTitle>Ant Design Winform UI</AssemblyTitle>
<Description>👚 基于 Ant Design 设计语言的 Winform 界面库</Description>

View File

@@ -21,7 +21,7 @@ namespace AntdUI
[ToolboxItem(true)]
[DefaultProperty("Items")]
[DefaultEvent("ItemClick")]
public class Breadcrumb : IControl
public class Breadcrumb : IControl, IEventListener
{
#region
@@ -117,6 +117,7 @@ namespace AntdUI
{
base.OnHandleCreated(e);
ChangeItems();
this.AddListener();
}
protected override void OnMarginChanged(EventArgs e)
@@ -137,6 +138,16 @@ namespace AntdUI
base.OnFontChanged(e);
}
public void HandleEvent(EventType id, object? tag)
{
switch (id)
{
case EventType.LANG:
ChangeItems();
break;
}
}
#endregion
#endregion

View File

@@ -1033,7 +1033,18 @@ namespace AntdUI
{
BlurBar = null;
_event?.WaitDispose();
if (shadow_dir_tmp.Count > 0)
{
lock (shadow_dir_tmp)
{
foreach (var item in shadow_dir_tmp) item.Value.Dispose();
shadow_dir_tmp.Clear();
}
}
base.Dispose(disposing);
if (items == null || items.Count == 0) return;
foreach (var it in items) it.Dispose(this, true);
items.Dispose();
}
#endregion
@@ -1053,6 +1064,14 @@ namespace AntdUI
case EventType.THEME:
if (Config.HasAnimation(nameof(VirtualPanel), Name) && BlurBar != null) _event.SetWait();
break;
case EventType.LANG:
CellCount = -1;
if (items == null || items.Count == 0) return;
foreach (var it in items) it.Dispose(this, false);
LoadLayout();
Invalidate();
if (Config.HasAnimation(nameof(VirtualPanel), Name) && BlurBar != null) _event.SetWait();
break;
}
}
@@ -1302,6 +1321,8 @@ namespace AntdUI
public virtual void MouseLeave(VirtualPanel sender, VirtualPanelMouseArgs e) { }
public virtual void MouseClick(VirtualPanel sender, VirtualPanelMouseArgs e) { }
public virtual void Dispose(VirtualPanel sender, bool disposed) { }
public void Invalidate() => invalidate?.Invoke(this, null);
public void Invalidate(Rectangle rect) => invalidate?.Invoke(this, rect);

View File

@@ -21,7 +21,7 @@ namespace AntdUI
[ToolboxItem(true)]
[DefaultProperty("Items")]
[DefaultEvent("SelectChanged")]
public class Menu : IControl, SubLayeredForm
public class Menu : IControl, SubLayeredForm, IEventListener
{
#region
@@ -517,6 +517,7 @@ namespace AntdUI
{
base.OnHandleCreated(e);
ChangeList();
this.AddListener();
var item = GetSelectItem(out var sub);
if (item != null)
{
@@ -579,6 +580,16 @@ namespace AntdUI
base.OnSizeChanged(e);
}
public void HandleEvent(EventType id, object? tag)
{
switch (id)
{
case EventType.LANG:
ChangeList();
break;
}
}
int collapseWidth = 0, collapsedWidth = 0;
/// <summary>
/// 展开之前宽度
@@ -970,7 +981,7 @@ namespace AntdUI
it.show = it.Show && it.Visible && rect.IsItemVisibleExpand(sy, it.rect, it.Expand, it.SubHeight);
if (it.show)
{
if (it.Depth == -1) g.Fill(brush_split, it.Rect);
if (it.Depth == -1) g.Fill(brush_split, it.rect);
else
{
PaintIt(g, it, fore, fore_active, fore_enabled, back_hover, back_active, radius);
@@ -993,7 +1004,7 @@ namespace AntdUI
it.show = it.Show && it.Visible && rect.IsItemVisibleExpand(sy, it.rect, it.Expand, it.SubHeight);
if (it.show)
{
if (it.Depth == -1) g.Fill(brush_split, it.Rect);
if (it.Depth == -1) g.Fill(brush_split, it.rect);
else
{
PaintIt(g, it, fore, fore_active, fore_enabled, back_hover, back_active, radius);
@@ -1135,7 +1146,7 @@ namespace AntdUI
using (var pen = new Pen(fore_active, Dpi * 2))
{
pen.StartCap = pen.EndCap = System.Drawing.Drawing2D.LineCap.Round;
g.DrawLines(pen, it.arr_rect.TriangleLinesVertical(it.GetArrowProg(), .4F));
g.DrawLines(pen, it.arrow_rect.TriangleLinesVertical(it.GetArrowProg(), .4F));
}
}
else PaintBack(g, back_active, it.rect, radius);
@@ -1145,7 +1156,7 @@ namespace AntdUI
using (var pen = new Pen(fore_enabled, Dpi * 2))
{
pen.StartCap = pen.EndCap = System.Drawing.Drawing2D.LineCap.Round;
g.DrawLines(pen, it.arr_rect.TriangleLinesVertical(it.GetArrowProg(), .4F));
g.DrawLines(pen, it.arrow_rect.TriangleLinesVertical(it.GetArrowProg(), .4F));
}
}
PaintTextIcon(g, it, fore_enabled, radius);
@@ -1189,7 +1200,7 @@ namespace AntdUI
using (var pen = new Pen(fore, Dpi * 2))
{
pen.StartCap = pen.EndCap = System.Drawing.Drawing2D.LineCap.Round;
g.DrawLines(pen, it.arr_rect.TriangleLinesVertical(it.GetArrowProg(), .4F));
g.DrawLines(pen, it.arrow_rect.TriangleLinesVertical(it.GetArrowProg(), .4F));
}
}
else if (mode == TMenuMode.Vertical)
@@ -1197,7 +1208,7 @@ namespace AntdUI
using (var pen = new Pen(fore, Dpi * 2))
{
pen.StartCap = pen.EndCap = System.Drawing.Drawing2D.LineCap.Round;
g.DrawLines(pen, TAlignMini.Right.TriangleLines(it.arr_rect, .4F));
g.DrawLines(pen, TAlignMini.Right.TriangleLines(it.arrow_rect, .4F));
}
}
else if (mode == TMenuMode.Horizontal_Arrow)
@@ -1205,7 +1216,7 @@ namespace AntdUI
using (var pen = new Pen(fore, Dpi * 2))
{
pen.StartCap = pen.EndCap = System.Drawing.Drawing2D.LineCap.Round;
g.DrawLines(pen, it.arr_rect.TriangleLinesVertical(-1, .4F));
g.DrawLines(pen, it.arrow_rect.TriangleLinesVertical(-1, .4F));
}
}
}
@@ -1505,7 +1516,7 @@ namespace AntdUI
switch (drop)
{
case 0:
if (OpenDropDown(it)) OpenTip(it, it.Rect);
if (OpenDropDown(it)) OpenTip(it, it.Rect(0, ScrollBar.ValueY));
break;
case 1:
OpenDropDown(it);
@@ -2082,7 +2093,7 @@ namespace AntdUI
{
if (it.items == null || it.items.Count == 0) return true;
select_x = 0;
subForm = new LayeredFormMenuDown(this, radius, it.Rect, it.items);
subForm = new LayeredFormMenuDown(this, radius, it.Rect(0, ScrollBar.ValueY), it.items);
subForm.Show(this);
return false;
}
@@ -2647,17 +2658,38 @@ namespace AntdUI
#region
/// <summary>
/// 菜单坐标位置
/// </summary>
public Rectangle Rect
public Rectangle Rect() => Rect("");
public Rectangle Rect(int x, int y) => Rect("", x, y);
public Rectangle Rect(string type, int x = 0, int y = 0)
{
get
if (x > 0 || y > 0)
{
if (PARENT == null) return rect;
int y = PARENT.ScrollBar.Value;
if (y != 0F) return new Rectangle(rect.X, rect.Y - y, rect.Width, rect.Height);
return rect;
switch (type)
{
case "Text":
return new Rectangle(txt_rect.X - x, txt_rect.Y - y, txt_rect.Width, txt_rect.Height);
case "Sub":
return new Rectangle(rect.X - x, rect.Y - y, rect.Width, rect.Height + (Expand ? SubHeight : 0));
case "Icon":
return new Rectangle(ico_rect.X - x, ico_rect.Y - y, ico_rect.Width, ico_rect.Height);
case "Arrow":
return new Rectangle(arrow_rect.X - x, arrow_rect.Y - y, arrow_rect.Width, arrow_rect.Height);
default:
return new Rectangle(rect.X - x, rect.Y - y, rect.Width, rect.Height);
}
}
switch (type)
{
case "Text":
return txt_rect;
case "Sub":
return new Rectangle(rect.X, rect.Y, rect.Width, rect.Height + (Expand ? SubHeight : 0));
case "Icon":
return ico_rect;
case "Arrow":
return arrow_rect;
default:
return rect;
}
}
@@ -2691,7 +2723,7 @@ namespace AntdUI
else txt_rect = new Rectangle(_rect.X + x, _rect.Y, _rect.Width - usew, _rect.Height);
int ur = _rect.Right - arrow_size - gap - scx;
arr_rect = new Rectangle(ur, _rect.Y + (_rect.Height - arrow_size) / 2, arrow_size, arrow_size);
arrow_rect = new Rectangle(ur, _rect.Y + (_rect.Height - arrow_size) / 2, arrow_size, arrow_size);
exr = 0;
if (Button != null)
@@ -2725,7 +2757,7 @@ namespace AntdUI
txt_rect = new Rectangle(_rect.X + x, _rect.Y, _rect.Width - usew, _rect.Height);
}
else txt_rect = new Rectangle(_rect.X + x, _rect.Y, _rect.Width - usew, _rect.Height);
arr_rect = new Rectangle(_rect.Right - (arrow_size - sp), _rect.Y + (_rect.Height - arrow_size) / 2, arrow_size, arrow_size);
arrow_rect = new Rectangle(_rect.Right - (arrow_size - sp), _rect.Y + (_rect.Height - arrow_size) / 2, arrow_size, arrow_size);
Show = true;
return usew;
}
@@ -2735,7 +2767,7 @@ namespace AntdUI
rect = _rect;
txt_rect = rect_text;
arr_rect = new Rectangle(_rect.Right - (arrow_size + sp), _rect.Y + (_rect.Height - arrow_size) / 2, arrow_size, arrow_size);
arrow_rect = new Rectangle(_rect.Right - (arrow_size + sp), _rect.Y + (_rect.Height - arrow_size) / 2, arrow_size, arrow_size);
Show = true;
}
@@ -2755,7 +2787,7 @@ namespace AntdUI
}
internal Rectangle rect { get; set; }
internal Rectangle arr_rect { get; set; }
internal Rectangle arrow_rect { get; set; }
internal bool Contains(int x, int y, int sx, int sy, out MenuButton? btn)
{

View File

@@ -21,7 +21,7 @@ namespace AntdUI
[ToolboxItem(true)]
[DefaultProperty("Items")]
[DefaultEvent("SelectIndexChanged")]
public class Segmented : IControl
public class Segmented : IControl, IEventListener
{
public Segmented()
{
@@ -1268,6 +1268,7 @@ namespace AntdUI
{
base.OnHandleCreated(e);
ChangeItems();
this.AddListener();
}
protected override void OnMarginChanged(EventArgs e)
@@ -1288,6 +1289,16 @@ namespace AntdUI
base.OnFontChanged(e);
}
public void HandleEvent(EventType id, object? tag)
{
switch (id)
{
case EventType.LANG:
ChangeItems();
break;
}
}
#endregion
#endregion

View File

@@ -325,7 +325,7 @@ namespace AntdUI
}
use_x += pie_size + padd;
}
var rect_real = new Rectangle(rect.X + padd + use_x, rect.Y, rect.Width - padd * 2-use_x, rect.Height);
var rect_real = new Rectangle(rect.X + padd + use_x, rect.Y, rect.Width - padd * 2 - use_x, rect.Height);
var rect_text = new Rectangle(rect_real.X, rect_real.Y, rect_real.Width, h_text);
var rect_value = new Rectangle(rect_real.X, rect_real.Y + rect_text.Height + gap, rect_real.Width, h_value);
g.String(text, Font, Colour.TextTertiary.Get(nameof(Statistic), ColorScheme), rect_text, sf);

View File

@@ -23,7 +23,7 @@ namespace AntdUI
[ToolboxItem(true)]
[DefaultProperty("Current")]
[DefaultEvent("ItemClick")]
public class Steps : IControl
public class Steps : IControl, IEventListener
{
#region
@@ -233,6 +233,17 @@ namespace AntdUI
{
base.OnHandleCreated(e);
ChangeList();
this.AddListener();
}
public void HandleEvent(EventType id, object? tag)
{
switch (id)
{
case EventType.LANG:
ChangeList();
break;
}
}
bool pauseLayout = false;

View File

@@ -21,7 +21,7 @@ namespace AntdUI
[ToolboxItem(true)]
[DefaultProperty("Items")]
[DefaultEvent("ItemClick")]
public class Timeline : IControl
public class Timeline : IControl, IEventListener
{
#region
@@ -77,6 +77,17 @@ namespace AntdUI
{
base.OnHandleCreated(e);
ChangeList();
this.AddListener();
}
public void HandleEvent(EventType id, object? tag)
{
switch (id)
{
case EventType.LANG:
ChangeList();
break;
}
}

View File

@@ -22,7 +22,7 @@ namespace AntdUI
[ToolboxItem(true)]
[DefaultProperty("Items")]
[DefaultEvent("SelectChanged")]
public class Tree : IControl
public class Tree : IControl, IEventListener
{
#region
@@ -368,6 +368,17 @@ namespace AntdUI
{
base.OnHandleCreated(e);
ChangeList();
this.AddListener();
}
public void HandleEvent(EventType id, object? tag)
{
switch (id)
{
case EventType.LANG:
ChangeList();
break;
}
}
bool CanLayout()

View File

@@ -23,11 +23,6 @@ namespace AntdUI
static string Rest(string svg) => "<svg " + svg.Replace("[VBD", "viewBox=\"").Replace("[VB2", "viewBox=\"0 0 1024 1024\">").Replace("[PD", "<path d=\"").Replace("[PE", "</path>").Replace("[PG", "\"></path>") + "</svg>";
static string YS(string svg)
{
return svg.Replace("viewBox=\"0 0 1024 1024\">", "[VB2").Replace("viewBox=\"", "[VBD").Replace("<path d=\"", "[PD").Replace("\"></path>", "[PG").Replace("</path>", "[PE");
}
public static Dictionary<string, string> Custom;
public static Dictionary<string, string> Emoji = new Dictionary<string, string>(0);