2015-11-17 1 views
1

У меня есть WinForm с меню, как это:не удается получить все пункты подменю в WinForm в C#

File==>Add==>New Project 
File==>Add==>Existing Project 
File==>Open 
File==>Exit 
Edit==>Copy 
Edit==>Cut 
Help==>View Help 
Help==>About 

Я хочу, чтобы текст всех пунктов меню и пунктов подменю.
Я попробовал этот код:

for (int i = 0; i < menuStrip1.Items.Count; i++) 
{ 
foreach (ToolStripMenuItem item in ((ToolStripMenuItem)menuStrip1.Items[i]).DropDownItems) 
{ 
    textBox1.Text += item.OwnerItem.Text + @"==>" + item.Text + Environment.NewLine; 
} 
} 

и это приводит к:

File==>Add 
File==>Open 
File==>Exit 
Edit==>Copy 
Edit==>Cut 
Help==>View Help 
Help==>About 

, как это показывает, что он не показывает все пункты подменю. Я попробовал этот код:

for (int i = 0; i < menuStrip1.Items.Count; i++) 
{ 
    for (int j = 0; j < ((ToolStripMenuItem) menuStrip1.Items[i]).DropDownItems.Count; j++) 
    { 
    foreach (ToolStripMenuItem item in (ToolStripMenuItem)menuStrip1.Items[i]).DropDownItems[j])) 
    { 
     textBox1.Text += item.OwnerItem.Text + @"==>" + item.Text + Environment.NewLine; 

     } 
    } 
} 

, но он дает эту ошибку:

foreach statement cannot operate on variables of type 'System.Windows.Forms.ToolStripItem' because 'System.Windows.Forms.ToolStripItem' does not contain a public definition for 'GetEnumerator' 



Примечание: Я ищу общее решение (для произвольного числа пункт меню и произвольное количество вложенных пунктов подменю) не только для этой проблемы.

Заранее спасибо.

ответ

0

Использование recursion.

Напишите метод, который вызывает себя (но также проверяет на завершение, чтобы он не вызывал себя, когда не нужно было углубляться).

Вот код:

static string GetText2(ToolStripMenuItem c) 
{ 
    string s = c.OwnerItem.Text + @"==>" + c.Text + Environment.NewLine; 
    foreach (ToolStripMenuItem c2 in c.DropDownItems) 
    { 
     s += GetText2(c2); 
    } 
    return s; 
} 
+0

Я использовал рекурсию, но это приводит к «stackoverflow» – BlueFlower

+0

Вот почему вам нужно проверить на завершение. В коде, который я добавил в свой ответ, который является автоматическим - если 'c.Controls' пуст - он никогда не вызывает' GetText (c2) '. – User42

+0

Я использовал рекурсию во внутреннем methed, но это приводит к «stackoverflow», и я протестировал ваш метод, но он не работает. вы протестировали свое решение? можете ли вы предоставить мне свое решение в деталях? спасибо – BlueFlower

0

Вы можете использовать следующую функцию общего обхода дерева, взятую из How to flatten tree via LINQ?

public static class TreeHelper 
{ 
    public static IEnumerable<T> Expand<T>(this IEnumerable<T> source, 
     Func<T, IEnumerable<T>> elementSelector) 
    { 
     var stack = new Stack<IEnumerator<T>>(); 
     var e = source.GetEnumerator(); 
     try 
     { 
      while (true) 
      { 
       while (e.MoveNext()) 
       { 
        var item = e.Current; 
        yield return item; 
        var elements = elementSelector(item); 
        if (elements == null) continue; 
        stack.Push(e); 
        e = elements.GetEnumerator(); 
       } 
       if (stack.Count == 0) break; 
       e.Dispose(); 
       e = stack.Pop(); 
      } 
     } 
     finally 
     { 
      e.Dispose(); 
      while (stack.Count != 0) stack.Pop().Dispose(); 
     } 
    } 
} 

С этой функцией и LINQ, получая все пункты меню просто

var allMenuItems = menuStrip1.Items.OfType<ToolStripMenuItem>() 
    .Expand(item => item.DropDownItems.OfType<ToolStripMenuItem>()); 

и выработка текста, как в вашем примере

textBox1.Text = string.Join(Environment.NewLine, allMenuItems 
    .Select(item => item.OwnerItem.Text + @"==>" + item.Text));