[英]Collection was modified; enumeration operation may not execute
我的TabControl中有多個TabItem; tabItem1,tabItem2,tabItem3 ...這些是
CloseableTabItem。
如果我在tabItem1中添加一個節點並按一個按鈕為此節點創建subGraph模型,則
同一節點應在帶有按鈕的tabItem2中出現; 以便
tabItem2-Header = nodeName,nodeName = tabItem1-Header。
如果我從tabitem2中的節點按按鈕,則tabitem1應該集中。 如果我關閉
tabItem1並按相同的按鈕,應該再次加載tabItem1(這種情況發生在
SubGraphButton_Click)。
您看到此代碼有問題嗎?
private void ChildNode_Click(object sender, RoutedEventArgs args)
{
System.Windows.Controls.Button button = (System.Windows.Controls.Button)sender;
Node node = Part.FindAncestor<Node>(button);
MyNodeData nodeData = node.Data as MyNodeData;
foreach (TabItem item in tabControl.Items)
{
if (nodeData.Text == item.Header.ToString())
{
item.Focus();
}
else if (nodeData.Text != item.Header.ToString())
{
SubGraphButton_Click(sender, args);
}
}
}
private void SubGraphButton_Click(object sender, RoutedEventArgs args)
{
string activeDirectory = @"X:\SubGraph\";
string[] files = Directory.GetFiles(activeDirectory);
foreach (string fileName in files)
{
FileStream file = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read);
System.Windows.Controls.Button button = (System.Windows.Controls.Button)sender;
Node node = Part.FindAncestor<Node>(button);
MyNodeData nodeData = node.Data as MyNodeData;
if (node != null)
{
if (nodeData.Text + ".epk" == fileName.Substring(12, fileName.Length - 12) && !tabControl.Items.Contains(tabItem1))
{
tabControl.Items.Add(tabItem1);
tabItem1.Focus();
var model = new MyGraphLinksModel();
model.Modifiable = true;
model.HasUndoManager = true;
activateDiagram(myDiagram1);
activeDiagram.Model = model;
model.Name = fileName.Substring(12, fileName.Length - 12);
model.Name = model.Name.Substring(0, model.Name.Length - 4);
tabItem1.Header = model.Name;
activeDiagram.PartManager.UpdatesRouteDataPoints = false;
StreamReader reader = new StreamReader(file);
string contents = reader.ReadToEnd();
XElement root = XElement.Parse(contents);
activeDiagram.LayoutCompleted += LoadLinkRoutes;
model.Load<MyNodeData, MyLinkData>(root, "MyNodeData", "MyLinkData");
}
}
}
當您在修改集合的同時對其進行修改時,很可能會導致錯誤。 錯誤的類型及其相似性往往會根據底層集合的實際情況而有所不同。 迭代時修改List
很可能會給您帶來很多錯誤(如果您對其進行大量修改,則可能導致不止一個錯誤),並且有可能超出范圍。 修改LinkedList
可能會導致空指針異常,無限循環,訪問不存在的項等,但是可能性要小得多。
因為在一般情況下,出現問題的機會很大,所以這些問題的影響也很大,而且在診斷實際出了問題的地方(以及在何處)的難度很大,C#選擇在每次嘗試迭代時僅拋出異常在迭代過程中修改的集合。 這樣一來,您就不會遇到怪異的,意想不到的問題,直到問題的根本原因遠了一段時間,這些問題才會顯現出來。
有幾種不同的策略可以用來避免此問題:
遍歷與您真正想要修改的集合不同的集合。 在某些情況下,只需在序列上添加ToList
調用,然后將其移至新集合即可完成。 這樣做時,要迭代的集合與要修改的集合是分開的,因此沒有錯誤。
您可以避免在foreach
循環中修改實際的集合。 常見的示例是創建List
或其他“進行更改”的itemsToAdd
,無論是itemsToAdd
, itemsToRemove
等。然后,您可以在循環后為所有這些項添加/刪除/任何內容。 (如果僅修改集合大小的一小部分,這將非常有效。)
某些類型的集合可以“迭代”,而無需實際使用傳統的迭代器(意味着foreach
循環)。 例如,您可以使用常規的for
循環來遍歷List
,並在添加或刪除項目時簡單地修改(遞增/遞減)循環變量。 如果正確完成,這通常是一個有效的選擇,但是很容易犯錯誤並出錯,因此,盡管其他選擇(略有效率)低效率,但由於對性能的要求不高,因此它們是非常好的選擇他們的簡單。
在枚舉集合時(本例中為tabControl.Items
)(在foreach
循環中正在執行此操作),您將不能修改它,因為這會使枚舉器無效。
導致錯誤的特定代碼行可能是
// In SubGraphButton_Click
// This line of code is called inside an enumeration of tabControl.Items
// This is not permitted!
tabControl.Items.Add(tabItem1);
從概念上講,您的代碼如下所示:
private void ChildNode_Click(object sender, RoutedEventArgs args)
{
System.Windows.Controls.Button button = (System.Windows.Controls.Button)sender;
Node node = Part.FindAncestor<Node>(button);
MyNodeData nodeData = node.Data as MyNodeData;
foreach (TabItem item in tabControl.Items)
{
if (nodeData.Text == item.Header.ToString())
{
item.Focus();
}
else if (nodeData.Text != item.Header.ToString())
{
// This line will throw an exception
DoSomethingThatModifiesTabControlItemsCollection()
}
}
}
您無法修改要迭代的集合。
您可以將“ foreach”循環替換為簡單的“ for”循環,但是請注意在從集合中添加/刪除項目時正在運行的索引。
像這樣:
for (int i = 0; i < tabControl.Items.Count; i++)
{
TabItem item = tabControl.Items[i];
... // your logic here
}
另一個可能方便的選項是,不將項目添加到選項卡控件中.Items集合將其作為返回值獲取,將其保存在列表中,並在完成所有項目的迭代之后,插入您已經擁有的所有選項卡已創建到項目集合中,因此您在運行集合時無需修改它。
在foreach循環中,您調用SubGraphButton_Click,這又添加了一個新節點tabControl.Items.Add(tabItem1);
這是不允許的。 您可以改用for循環。
是的,這條線
tabControl.Items.Add(tabItem1);
更改您在NodeClick中枚舉的集合
在枚舉世界中這是不行的
嘗試以的標准循環,但順序相反...
for( int x = tabControl.Items.Count - 1; x>= 0; x--)
{
TabItem item = tabControl.Items[x];
if (nodeData.Text == item.Header.ToString())
{
item.Focus();
}
else if (nodeData.Text != item.Header.ToString())
{
SubGraphButton_Click(sender, args);
}
}
以相反的順序循環避免檢查在SubGraphButton內添加的新項目。
我不知道這是否是不良影響。
當您遍歷tabControl中的TabItems時,您無法在ForEach中執行任何會導致tabControl的item集合發生更改的操作。
這是框架的局限性。 這是因為您當前正在遍歷TabItem。
因此,在您的ChildNode_Click函數中,
在您的ForEach內部
foreach (TabItem item in tabControl.Items)
你打電話給
SubGraphButton_Click(sender, args);
在該函數內部,您可以調用
tabControl.Items.Add(tabItem1);
在ForEach內部時,您無法操作Items集合。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.