From 2c11ef7491270fb43627309691bbb76ff6eb6fbe Mon Sep 17 00:00:00 2001 From: ww-rm Date: Sun, 2 Mar 2025 21:24:17 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=8F=AA=E8=AF=BB=E8=AE=BF?= =?UTF-8?q?=E9=97=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- SpineViewer/src/SpineListView.cs | 96 ++++++++++++++------------------ 1 file changed, 42 insertions(+), 54 deletions(-) diff --git a/SpineViewer/src/SpineListView.cs b/SpineViewer/src/SpineListView.cs index 01bf3d8..2a4b726 100644 --- a/SpineViewer/src/SpineListView.cs +++ b/SpineViewer/src/SpineListView.cs @@ -20,26 +20,19 @@ namespace SpineViewer public PropertyGrid? PropertyGrid { get; set; } /// - /// Spine 列表浅拷贝 + /// 获取数组快照, 访问时必须使用 lock 语句锁定对象本身 + /// + public readonly ReadOnlyCollection Spines; + + /// + /// Spine 列表, 访问时必须使用 lock 语句锁定 Spines /// - [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] - [Browsable(false)] - public Spine.Spine[] Spines - { - get - { - dataMutex.WaitOne(); - var shallowCopy = spines.ToArray(); - dataMutex.ReleaseMutex(); - return shallowCopy; - } - } private readonly List spines = []; - private readonly Mutex dataMutex = new(); public SpineListView() { InitializeComponent(); + Spines = spines.AsReadOnly(); } /// @@ -47,10 +40,6 @@ namespace SpineViewer /// private void Insert(int index = -1) { - // 如果索引无效则在末尾添加 - if (index < 0 || index > spines.Count) - index = spines.Count; - var dialog = new OpenSpineDialog(); if (dialog.ShowDialog() != DialogResult.OK) return; @@ -58,7 +47,13 @@ namespace SpineViewer try { var spine = Spine.Spine.New(dialog.Version, dialog.SkelPath, dialog.AtlasPath); - spines.Insert(index, spine); + + // 如果索引无效则在末尾添加 + if (index < 0 || index > listView.Items.Count) + index = listView.Items.Count; + + // 锁定外部的读操作 + lock (Spines) { spines.Insert(index, spine); } listView.Items.Insert(index, new ListViewItem([spine.Name, spine.Version.String()], -1) { ToolTipText = spine.SkelPath }); // 选中新增项 @@ -121,20 +116,8 @@ namespace SpineViewer try { var spine = Spine.Spine.New(version, skelPath); - // 对 spines 和 Items 的操作都要转到窗口线程操作 - if (listView.InvokeRequired) - { - listView.Invoke(() => - { - spines.Add(spine); - listView.Items.Add(new ListViewItem([spine.Name, spine.Version.String()], -1) { ToolTipText = spine.SkelPath }); - }); - } - else - { - spines.Add(spine); - listView.Items.Add(new ListViewItem([spine.Name, spine.Version.String()], -1) { ToolTipText = spine.SkelPath }); - } + lock (Spines) { spines.Add(spine); } + listView.Invoke(() => listView.Items.Add(new ListViewItem([spine.Name, spine.Version.String()], -1) { ToolTipText = spine.SkelPath })); success++; } catch (Exception ex) @@ -159,13 +142,15 @@ namespace SpineViewer { if (PropertyGrid is not null) { - - if (listView.SelectedIndices.Count <= 0) - PropertyGrid.SelectedObject = null; - else if (listView.SelectedIndices.Count <= 1) - PropertyGrid.SelectedObject = spines[listView.SelectedIndices[0]]; - else - PropertyGrid.SelectedObjects = listView.SelectedIndices.Cast().Select(index => spines[index]).ToArray(); + lock (Spines) + { + if (listView.SelectedIndices.Count <= 0) + PropertyGrid.SelectedObject = null; + else if (listView.SelectedIndices.Count <= 1) + PropertyGrid.SelectedObject = spines[listView.SelectedIndices[0]]; + else + PropertyGrid.SelectedObjects = listView.SelectedIndices.Cast().Select(index => spines[index]).ToArray(); + } } } @@ -212,23 +197,29 @@ namespace SpineViewer // 获取拖放源项和目标项 var draggedItem = (ListViewItem)e.Data.GetData(typeof(ListViewItem)); int draggedIndex = draggedItem.Index; - var draggedSpine = spines[draggedIndex]; - var point = listView.PointToClient(new Point(e.X, e.Y)); var targetItem = listView.GetItemAt(point.X, point.Y); int targetIndex = targetItem is null ? listView.Items.Count : targetItem.Index; if (targetIndex <= draggedIndex) { - spines.RemoveAt(draggedIndex); - spines.Insert(targetIndex, draggedSpine); + lock (Spines) + { + var draggedSpine = spines[draggedIndex]; + spines.RemoveAt(draggedIndex); + spines.Insert(targetIndex, draggedSpine); + } listView.Items.RemoveAt(draggedIndex); listView.Items.Insert(targetIndex, draggedItem); } else { - spines.RemoveAt(draggedIndex); - spines.Insert(targetIndex - 1, draggedSpine); + lock (Spines) + { + var draggedSpine = spines[draggedIndex]; + spines.RemoveAt(draggedIndex); + spines.Insert(targetIndex - 1, draggedSpine); + } listView.Items.RemoveAt(draggedIndex); listView.Items.Insert(targetIndex - 1, draggedItem); } @@ -275,19 +266,16 @@ namespace SpineViewer if (listView.SelectedIndices.Count > 1) { if (MessageBox.Show($"确定移除所选 {listView.SelectedIndices.Count} 项吗?", "操作确认", MessageBoxButtons.OKCancel, MessageBoxIcon.Question) != DialogResult.OK) - { return; - } } foreach (var i in listView.SelectedIndices.Cast().OrderByDescending(x => x)) { - spines.RemoveAt(i); + lock (Spines) { spines.RemoveAt(i); } listView.Items.RemoveAt(i); } } - private void toolStripMenuItem_MoveUp_Click(object sender, EventArgs e) { if (listView.SelectedIndices.Count != 1) @@ -296,7 +284,7 @@ namespace SpineViewer var index = listView.SelectedIndices[0]; if (index > 0) { - (spines[index - 1], spines[index]) = (spines[index], spines[index - 1]); + lock (Spines) { (spines[index - 1], spines[index]) = (spines[index], spines[index - 1]); } var item = listView.Items[index]; listView.Items.RemoveAt(index); listView.Items.Insert(index - 1, item); @@ -309,9 +297,9 @@ namespace SpineViewer return; var index = listView.SelectedIndices[0]; - if (index < spines.Count - 1) + if (index < listView.Items.Count - 1) { - (spines[index], spines[index + 1]) = (spines[index + 1], spines[index]); + lock (Spines) { (spines[index], spines[index + 1]) = (spines[index + 1], spines[index]); } var item = listView.Items[index + 1]; listView.Items.RemoveAt(index + 1); listView.Items.Insert(index, item); @@ -325,7 +313,7 @@ namespace SpineViewer if (MessageBox.Show($"确认移除所有 {listView.Items.Count} 项吗?", "操作确认", MessageBoxButtons.OKCancel, MessageBoxIcon.Question) == DialogResult.OK) { - spines.Clear(); + lock (Spines) { spines.Clear(); } listView.Items.Clear(); if (PropertyGrid is not null) PropertyGrid.SelectedObject = null;