2012-07-19 78 views
0

我的TabControl中有多個TabItems; tabItem1,tabItem2,tabItem3 ...這些是收藏已修改;枚舉操作可能不會執行

CloseableTabItem。

如果我添加在tabItem1一個節點,按下一個按鈕,使這個節點的子模式,

同一節點應該出現在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"); 
       } 
      } 
    } 
+1

你不應該使用像方法這樣的事件。重構代碼並使用SubGraphButton_Click中的所有代碼創建一個新方法。那麼你可以從你喜歡的任何地方使用這種方法。 – 2012-07-19 14:54:03

+0

thanx它幫助我,它的工作 – User1979 2012-07-19 15:50:43

回答

8

當您在修改集合時正在修改集合時,它很可能導致錯誤。錯誤類型及其可能性往往會根據底層集合的實際情況而有所不同。在迭代時修改List很可能會給你很多關閉一個錯誤(如果你修改了一個錯誤,關閉多個關閉),並且可能出現越界錯誤。修改LinkedList可能會導致空指針異常,無限循環,訪問不存在的項目等,但可能性較小。

由於在一般情況下問題發生的機率相當高,這些問題的影響也相當高,並且很難診斷C#選擇何時發生錯誤(以及哪裏)您嘗試迭代迭代期間修改的集合。通過這種方式,您不會遇到奇怪的,意想不到的問題,這些問題不會在自己的根源所在之前的某段時間內顯現出來。

有一些可用於避免此問題幾種不同的策略:

  1. 遍歷不同的集合比你真的要修改的一個。在某些情況下,可以簡單地通過在序列上添加ToList調用來完成,以便將其移至新集合;當這樣做時,迭代的集合與被修改的集合是分開的,所以沒有錯誤。

  2. 您可以避免修改foreach循環內的實際集合。常見的例子是創建一個List或其他「所做的更改」集合,無論它是itemsToAdd,itemsToRemove等。然後,您可以在循環後爲所有這些項目添加/刪除/任何項目。 (如果您僅修改集合的一小部分大小,則這是有效的。)

  3. 某些類型的集合可以在不實際使用傳統迭代器的情況下進行「迭代」(即循環爲foreach)。例如,您可以使用常規的for循環來遍歷List,只需添加或刪除項目即可修改(遞增/遞減)循環變量。這樣做,如果正確完成,往往是一種有效的選擇,但是很容易犯錯,並且出現錯誤,因此其他選項效率較低(邊際效率較低),對於非性能密集型代碼非常適合,因爲他們的簡單。

+2

+很好的閱讀一些背景思想。 – 2012-07-19 14:57:28

1

你是不允許修改的集合(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() 
     } 
    } 
} 
1

不能修改收集你迭代上。

您可以使用簡單的for for循環替換「foreach」循環,但請注意您在添加/刪除集合中的項目時所運行的索引。

這樣的:

 for (int i = 0; i < tabControl.Items.Count; i++) 
     { 
      TabItem item = tabControl.Items[i]; 
      ... // your logic here 
     } 

,這可能是方便的另一種選擇,是代替將物品放入標籤control.Items收集得到它的返回值,將它們保存在一個列表,您先請」我們已經完成迭代所有項目,將所有已創建的選項卡插入到項目集合中,以便在運行時不會修改集合。

+0

我試過你的代碼,它打開我需要的文件,但在多個tabItem – User1979 2012-07-19 15:18:59

1

在foreach循環中,您調用SubGraphButton_Click,然後添加一個新節點tabControl.Items.Add(tabItem1); 這是不允許的。您可以改爲使用for循環。

0

當您對TabControl中的TabItems執行ForEach時,您無法在ForEach中執行任何操作,這會導致tabControl的項目集合發生更改。

這是該框架的限制。這是因爲你正在迭代TabItems。

所以你ChildNode_Click函數中,

裏面你的foreach

foreach (TabItem item in tabControl.Items) 

您對

SubGraphButton_Click(sender, args); 

內部的函數的調用,您對通話

tabControl.Items.Add(tabItem1); 

在ForEach中不能操作Items集合。

+0

什麼_modifies_集合? – 2012-07-19 14:52:25

+1

tabControl.Items.Add(tabItem1);在函數SubGraphButton_Click中,在你的ChildNode_Click的ForEach塊中調用。 – Scen 2012-07-19 14:55:09

+0

我剛剛問過,因爲你沒有在答案中提到它。 – 2012-07-19 14:58:40

1

是,這條線

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); 
     } 
    } 

L以相反的順序進行反avoid,避免檢查SubGraphButton中添加的新項目。
我不知道這是否是一個desidered效果。

+0

我試過你的代碼,它打開我需要的文件,但在多個tabItem – User1979 2012-07-19 15:17:48

相關問題