From 84f6a4294d7374c57d7c38887848833c0bbe8fc6 Mon Sep 17 00:00:00 2001 From: LiRuoChen <571244399@qq.com> Date: Tue, 28 Jul 2026 14:14:27 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E8=A1=A8=E6=A0=BC=E7=B3=BB?= =?UTF-8?q?=E7=BB=9F=E8=B0=83=E8=AF=95=E6=97=B6=E4=BC=9A=E5=87=BA=E7=8E=B0?= =?UTF-8?q?=E6=AD=BB=E5=BE=AA=E7=8E=AF=E7=9A=84=E9=97=AE=E9=A2=98=EF=BC=8C?= =?UTF-8?q?=E4=BC=98=E5=8C=96=E9=87=8A=E6=94=BE=E6=B5=81=E7=A8=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Editor/XTable/XericUIActionTableEditor.cs | 4 +- .../Component/XericUIActionTable.Api.cs | 188 ++++++++++++------ .../Component/XericUIActionTable.Editor.cs | 2 +- .../Rendering/Component/XericUIActionTable.cs | 5 +- 4 files changed, 136 insertions(+), 63 deletions(-) diff --git a/Editor/XTable/XericUIActionTableEditor.cs b/Editor/XTable/XericUIActionTableEditor.cs index 5aca052..e3b0ffc 100644 --- a/Editor/XTable/XericUIActionTableEditor.cs +++ b/Editor/XTable/XericUIActionTableEditor.cs @@ -95,14 +95,14 @@ namespace XericUIEditor.XTable if (GUILayout.Button("重新生成表格", GUILayout.Height(26))) { m_Table.FullRebuildPreservingData(); - m_Table.SetChildrenVisible(m_ShowChildren); + m_ShowChildren = m_Table.ChildrenVisible; EditorApplication.RepaintHierarchyWindow(); } if (GUILayout.Button("强制刷新样式", GUILayout.Height(26))) { m_Table.ForceStyleRefresh(); - m_Table.SetChildrenVisible(m_ShowChildren); + m_ShowChildren = m_Table.ChildrenVisible; EditorApplication.RepaintHierarchyWindow(); } diff --git a/Runtime/XTable/Rendering/Component/XericUIActionTable.Api.cs b/Runtime/XTable/Rendering/Component/XericUIActionTable.Api.cs index e1366a3..84a8e43 100644 --- a/Runtime/XTable/Rendering/Component/XericUIActionTable.Api.cs +++ b/Runtime/XTable/Rendering/Component/XericUIActionTable.Api.cs @@ -421,58 +421,100 @@ namespace XericUI.XTable.Rendering.Component [ContextMenu("Xeric UI/完全重建表格")] public void FullRebuild() { - m_Assembler?.DestroyAll(); - m_PrefabPool?.DestroyAll(); - ClearAllChildren(); - m_BackgroundGo = null; - m_BorderRenderer = null; + m_IsRebuilding = true; + try + { + // 清理跟踪状态(在销毁旧 Assembler 前先解除引用) + ReleaseAllTrackedCells(); + m_ActivePrefabMap?.Clear(); - m_TableData = new XTableData(); + m_Assembler?.DestroyAll(); + m_PrefabPool?.DestroyAll(); + ClearAllChildren(); + m_BackgroundGo = null; + m_BorderRenderer = null; - m_Assembler = new CellAssembler(ContentTransform, m_DefaultStyleNamespace); - m_PrefabPool = new PrefabPrototypePool(ContentTransform); - m_ActivePrefabMap = new Dictionary<(int, int), GameObject>(); - RecalculateTotalSize(); - CreateDefaultSampleData(); - CreateBackground(); - CreateViewportRenderer(); - MarkDirty(TableDirtyType.All); - RefreshView(); - SetChildrenVisible(m_ChildrenVisible); + m_TableData = new XTableData(); + + m_Assembler = new CellAssembler(ContentTransform, m_DefaultStyleNamespace); + m_PrefabPool = new PrefabPrototypePool(ContentTransform); + m_ActivePrefabMap = new Dictionary<(int, int), GameObject>(); + RecalculateTotalSize(); + CreateDefaultSampleData(); + CreateBackground(); + CreateViewportRenderer(); + MarkDirty(TableDirtyType.All); + RefreshView(); + SetChildrenVisible(m_ChildrenVisible); + } + finally + { + m_IsRebuilding = false; + } } /// 重新生成表格但保留已有文本数据——先保存,重建后再回填 public void FullRebuildPreservingData() { - // 保存当前单元格文本 - var savedTexts = new Dictionary<(int, int), string>(); - if (m_TableData != null) + m_IsRebuilding = true; + try { - int rows = m_RowHeights?.Length ?? 0; - int cols = m_ColWidths?.Length ?? 0; - for (int r = 0; r < rows; r++) + // 保存当前单元格文本 + var savedTexts = new Dictionary<(int, int), string>(); + if (m_TableData != null) { - for (int c = 0; c < cols; c++) + int rows = m_RowHeights?.Length ?? 0; + int cols = m_ColWidths?.Length ?? 0; + for (int r = 0; r < rows; r++) { - var cell = m_TableData.GetCell(r, c); - if (cell != null && !string.IsNullOrEmpty(cell.Text)) - savedTexts[(r, c)] = cell.Text; + for (int c = 0; c < cols; c++) + { + var cell = m_TableData.GetCell(r, c); + if (cell != null && !string.IsNullOrEmpty(cell.Text)) + savedTexts[(r, c)] = cell.Text; + } } } + + // 先清理跟踪状态再销毁旧对象 + ReleaseAllTrackedCells(); + m_ActivePrefabMap?.Clear(); + + m_Assembler?.DestroyAll(); + m_PrefabPool?.DestroyAll(); + ClearAllChildren(); + m_BackgroundGo = null; + m_BorderRenderer = null; + + m_TableData = new XTableData(); + + m_Assembler = new CellAssembler(ContentTransform, m_DefaultStyleNamespace); + m_PrefabPool = new PrefabPrototypePool(ContentTransform); + m_ActivePrefabMap = new Dictionary<(int, int), GameObject>(); + RecalculateTotalSize(); + + // 恢复文本数据到新 TableData + foreach (var kv in savedTexts) + { + int r = kv.Key.Item1, c = kv.Key.Item2; + if (r < (m_RowHeights?.Length ?? 0) && c < (m_ColWidths?.Length ?? 0)) + m_TableData.GetOrCreateCell(r, c).Text = kv.Value; + } + + // 如果没有恢复任何数据,则创建默认示例 + if (savedTexts.Count == 0) + CreateDefaultSampleData(); + + CreateBackground(); + CreateViewportRenderer(); + MarkDirty(TableDirtyType.All); + RefreshView(); + SetChildrenVisible(m_ChildrenVisible); } - - FullRebuild(); - - // 恢复文本数据 - foreach (var kv in savedTexts) + finally { - int r = kv.Key.Item1, c = kv.Key.Item2; - if (r < (m_RowHeights?.Length ?? 0) && c < (m_ColWidths?.Length ?? 0)) - m_TableData.GetOrCreateCell(r, c).Text = kv.Value; + m_IsRebuilding = false; } - - RefreshView(); - SetChildrenVisible(m_ChildrenVisible); } /// @@ -483,11 +525,21 @@ namespace XericUI.XTable.Rendering.Component { if (m_TableData != null) { + // 清理预制体:先调用 OnPrefabRelease 再清理映射 + if (m_ActivePrefabMap != null) + { + foreach (var kv in m_ActivePrefabMap) + { + var cellData = m_TableData.GetCell(kv.Key.Item1, kv.Key.Item2); + cellData?.OnPrefabRelease?.Invoke(kv.Value); + } + m_ActivePrefabMap.Clear(); + } + m_PrefabPool?.ReturnAll(); + m_TableData.ClearAllMerges(); m_TableData.BlockMap.Clear(); } - m_ActivePrefabMap?.Clear(); - m_PrefabPool?.ReturnAll(); m_Quadtree?.Clear(); ClearSelection(); MarkDirty(TableDirtyType.DataChanged); @@ -499,28 +551,46 @@ namespace XericUI.XTable.Rendering.Component /// public void ClearTable() { - m_Assembler?.DestroyAll(); - m_PrefabPool?.DestroyAll(); - m_ActivePrefabMap?.Clear(); - m_Quadtree?.Clear(); - ClearAllChildren(); - m_BackgroundGo = null; - m_BorderRenderer = null; + m_IsRebuilding = true; + try + { + // 清理预制体回调 + if (m_ActivePrefabMap != null && m_TableData != null) + { + foreach (var kv in m_ActivePrefabMap) + { + var cellData = m_TableData.GetCell(kv.Key.Item1, kv.Key.Item2); + cellData?.OnPrefabRelease?.Invoke(kv.Value); + } + } - m_TableData = new XTableData(); - m_RowHeights = null; - m_ColWidths = null; - ClearSelection(); + ReleaseAllTrackedCells(); + m_ActivePrefabMap?.Clear(); + m_Quadtree?.Clear(); - m_Assembler = new CellAssembler(ContentTransform, m_DefaultStyleNamespace); - m_PrefabPool = new PrefabPrototypePool(ContentTransform); - m_ActivePrefabMap = new Dictionary<(int, int), GameObject>(); - MarkDirty(TableDirtyType.All); - RecalculateTotalSize(); - CreateBackground(); - CreateViewportRenderer(); - RefreshView(); - SetChildrenVisible(m_ChildrenVisible); + m_Assembler?.DestroyAll(); + m_PrefabPool?.DestroyAll(); + ClearAllChildren(); + m_BackgroundGo = null; + m_BorderRenderer = null; + + m_TableData = new XTableData(); + ClearSelection(); + + m_Assembler = new CellAssembler(ContentTransform, m_DefaultStyleNamespace); + m_PrefabPool = new PrefabPrototypePool(ContentTransform); + m_ActivePrefabMap = new Dictionary<(int, int), GameObject>(); + MarkDirty(TableDirtyType.All); + RecalculateTotalSize(); + CreateBackground(); + CreateViewportRenderer(); + RefreshView(); + SetChildrenVisible(m_ChildrenVisible); + } + finally + { + m_IsRebuilding = false; + } } /// 仅强制刷新样式,不重建数据结构 diff --git a/Runtime/XTable/Rendering/Component/XericUIActionTable.Editor.cs b/Runtime/XTable/Rendering/Component/XericUIActionTable.Editor.cs index 98b94a7..c1f51b3 100644 --- a/Runtime/XTable/Rendering/Component/XericUIActionTable.Editor.cs +++ b/Runtime/XTable/Rendering/Component/XericUIActionTable.Editor.cs @@ -39,7 +39,7 @@ namespace XericUI.XTable.Rendering.Component return; } - if (!m_DirtyFlag.IsDirty) return; + if (m_IsRebuilding || !m_DirtyFlag.IsDirty) return; var flags = m_DirtyFlag.Flags; if ((flags & ~(TableDirtyType.ScrollChanged | TableDirtyType.SelectionChanged)) == 0) diff --git a/Runtime/XTable/Rendering/Component/XericUIActionTable.cs b/Runtime/XTable/Rendering/Component/XericUIActionTable.cs index fc7d73f..1e3bdf2 100644 --- a/Runtime/XTable/Rendering/Component/XericUIActionTable.cs +++ b/Runtime/XTable/Rendering/Component/XericUIActionTable.cs @@ -318,9 +318,12 @@ namespace XericUI.XTable.Rendering.Component base.OnDestroy(); } + /// 是否正在同步重建中,此时 Update / EditorUpdate 应跳过以避免重入 + [System.NonSerialized] private bool m_IsRebuilding; + private void Update() { - if (!m_DirtyFlag.IsDirty) return; + if (m_IsRebuilding || !m_DirtyFlag.IsDirty) return; var flags = m_DirtyFlag.Flags; // 仅滚动或选区变更 → 轻刷新(不重建边框/背景/预制体全回收)