1

TabControl に複数の TabItems があります。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");
                }
           }
  }
4

6 に答える 6

11

コレクションの変更中にコレクションを変更すると、エラーが発生する可能性が高くなります。エラーの種類とその可能性は、基になるコレクションが実際に何であるかによって異なる傾向があります。a を反復するときに a を変更するListと、多くのオフ バイ 1 エラー (または、頻繁に変更する場合は複数オフ) が発生し、範囲外エラーが発生する可能性が非常に高くなります。a を変更するLinkedListと、null ポインター例外、無限ループ、存在しないアイテムへのアクセスなどが発生する可能性がありますが、その可能性はかなり低くなります。

一般的なケースでは、問題が発生する可能性はかなり高いため、それらの問題の影響もかなり高く、実際に何が (そしてどこで) 問題が発生したかを診断することは困難です。C# は、反復しようとするたびに例外をスローすることを選択します。反復中に変更されたコレクション。こうすることで、根本的な原因がどこにあるのか、さらに先に進むまで現れない、奇妙で予期しない問題が発生することはありません。

この問題を回避するために使用できるいくつかの異なる戦略があります。

  1. 本当に変更したいコレクションとは異なるコレクションを反復処理します。場合によってToListは、シーケンスに呼び出しを追加して新しいコレクションに移動することで、これを簡単に行うことができます。これを行う場合、反復されるコレクションは変更されるコレクションとは別であるため、エラーは発生しません。

  2. foreachループ内で実際のコレクションを変更することを避けることができます。これの一般的な例は、またはその他の「行う変更」のコレクションを作成することListです。その後、ループの後にそれらのすべてのアイテムを追加/削除/何でもすることができます。(これは、コレクションのサイズのごく一部を変更する場合に効果的です。)itemsToAdditemsToRemove

  3. 特定のタイプのコレクションは、従来の反復子 (foreachループを意味する) を実際に使用せずに「反復」できます。List例として、代わりに通常のループを使用して反復し、forアイテムを追加または削除するたびにループ変数を単純に変更 (インクリメント/デクリメント) することができます。これは、正しく行われると効率的なオプションになる傾向がありますが、間違いを犯して何か問題が発生するのは非常に簡単です。そのため、他のオプションは (わずかに) 効率的ではありませんが、パフォーマンスを重視しないコードには非常に適したオプションです。それらの単純さ。

于 2012-07-19T14:49:01.233 に答える
1

foreach ループ内で SubGraphButton_Click を呼び出すと、新しいノードが追加さtabControl.Items.Add(tabItem1); れます。これは許可されていません。代わりに for ループを使用できます。

于 2012-07-19T14:48:26.213 に答える
1

はい、この行

tabControl.Items.Add(tabItem1); 

NodeClick
で列挙するコレクションを変更します。これは、列挙の世界ではノーノーです。

標準の for でループしてみるが、逆順で……。

    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 内に追加された新しい項目が検査されなくなります。
これが望ましい効果かどうかはわかりません。

于 2012-07-19T14:52:07.740 に答える
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 コレクションを操作することはできません。

于 2012-07-19T14:49:01.173 に答える