22

I have a simple WPF application with a menu. I need to add menu items dynamically at runtime. When I simply create a new menu item, and add it onto its parent MenuItem, it does not display in the menu, regardless of if UpdateLayout is called.

What must happen to allow a menu to have additional items dynamically added at runtime?

Note: the following code doesn't work.

            MenuItem mi = new MenuItem();
            mi.Header = "Item to add";
            mi.Visibility = Visibility.Visible;
            //addTest is a menuitem that exists in the forms defined menu
            addTest.Items.Add(mi);
            addTest.UpdateLayout();

At the moment, the default menu items are defined in the xaml file. I want to add additional menu items onto this menu and its existing menu items. However, as stated, the above code does nothing.

Jon Ediger
  • 949
  • 1
  • 10
  • 27

5 Answers5

28
//Add to main menu
MenuItem newMenuItem1 = new MenuItem();
newMenuItem1.Header = "Test 123";
this.MainMenu.Items.Add(newMenuItem1);

//Add to a sub item
MenuItem newMenuItem2 = new MenuItem();
MenuItem newExistMenuItem = (MenuItem)this.MainMenu.Items[0];
newMenuItem2.Header = "Test 456";
newExistMenuItem.Items.Add(newMenuItem2);
Whytespot
  • 921
  • 12
  • 18
  • This doesn't work for me, and mirrors what I've tried. What am I missing? Please see the example text that is not working. – Jon Ediger Nov 14 '08 at 22:05
  • I just added a new menu and ran the code with the default control properties and it worked as expected. I tried your code, and it worked on my machine. Create a new project, add a basic menu and don't adjust any of it's properties and try your code again. – Whytespot Nov 14 '08 at 22:14
  • 6
    The key appears to be to not pre-define any menu items. When I did pre-define them, I couldn't dynamically add them. When I didn't pre-define them, I could. – Jon Ediger Nov 14 '08 at 22:45
  • 1
    Not working showing this error "Unable to cast object of type 'System.String' to type 'System.Windows.Controls.MenuItem'." on this line MenuItem newExistMenuItem = (MenuItem)this.MainMenu.Items[0]; – Uzair Ali May 12 '15 at 08:05
  • What bout the click event? – Hrvoje Batrnek Dec 25 '19 at 08:20
11

I have successfully added menu items to a pre-defined menu item. In the following code, the LanguageMenu is defined in design view in th xaml, and then added the sub items in C#.

XAML:

<MenuItem Name="LanguageMenu" Header="_Language">
  <MenuItem Header="English" IsCheckable="True" Click="File_Language_Click"/>
</MenuItem>

C#:

// Clear the existing item(s) (this will actually remove the "English" element defined in XAML)
LanguageMenu.Items.Clear(); 

// Dynamically get flag images from a specified folder to use for definingthe menu items 
string[] files = Directory.GetFiles(Settings.LanguagePath, "*.png");
foreach (string imagePath in files)
{
  // Create the new menu item
  MenuItem item = new MenuItem();

  // Set the text of the menu item to the name of the file (removing the path and extention)
  item.Header = imagePath.Replace(Settings.LanguagePath, "").Replace(".png", "").Trim("\\".ToCharArray());
  if (File.Exists(imagePath))
  {
    // Create image element to set as icon on the menu element
    Image icon = new Image();
    BitmapImage bmImage = new BitmapImage();
    bmImage.BeginInit();
    bmImage.UriSource = new Uri(imagePath, UriKind.Absolute);
    bmImage.EndInit();
    icon.Source = bmImage;
    icon.MaxWidth = 25;
    item.Icon = icon;
  }

  // Hook up the event handler (in this case the method File_Language_Click handles all these menu items)
  item.Click += new RoutedEventHandler(File_Language_Click); 

  // Add menu item as child to pre-defined menu item
  LanguageMenu.Items.Add(item); // Add menu item as child to pre-defined menu item
}
awe
  • 21,938
  • 6
  • 78
  • 91
6

I ran into the same problem. In my case the problem was that in the XAML the <menuitem> was directly contained in a <toolbar>. Once I put the <menuitem> inside a <menu> it started working. So:

<toolbar>
   <menuitem>
   </menuitem>
</toolbar>   

is bad

<toolbar>
    <menu>
        <menuitem>
        </menuitem>
    </menu>
</toolbar>   

is good

StayOnTarget
  • 11,743
  • 10
  • 52
  • 81
0

I did have to provide names for the existing items I intended to dynamically create sub-items for. In addition, I ran into an issue where I was tapping into the Window_Loaded event and it was jumping out of the event after running this:

row.MoveFocus(new TraversalRequest(FocusNavigationDirection.First));

I had to ensure I loaded the menu items before running the line above.

The reason this question is likely common is because intellisense infers that the Items collection is "Read-Only". This answer is partially supplemental because the answers above seem to indicate that if you have preexisting items you either have to remove them in code or not have them at all. This isn't true. I have been able to get this working with preexisting items and adding additional dynamic menu items in code:

    <DataGrid AutoGenerateColumns="False" HorizontalAlignment="Stretch" Margin="12,29,12,12" Name="grid" VerticalAlignment="Stretch" Background="#FF3A81A0" AlternatingRowBackground="#FFD9EEF2" FontSize="15" RowHeaderWidth="0" KeyDown="grid_KeyDown">
        <DataGrid.ContextMenu>
            <ContextMenu>
                <MenuItem Header="_Encrypt Row Values" Click="MenuItem_ContextMenu_Click_EncryptRowValues" Name="MenuItem_EncryptRowValues" />
                <MenuItem Header="De_crypt Row Values" Click="MenuItem_ContextMenu_Click_DecryptRowValues" Name="MenuItem_DecryptRowValues" />
                <MenuItem Header="Copy Row_s" Click="MenuItem_ContextMenu_Click_CopyRows" />
            </ContextMenu>
        </DataGrid.ContextMenu>
        <DataGrid.Resources>


            //Add Encryption Menu Items
            for (int i=0; i< encryptionKeys.Count; i++)
            {
                MenuItem keyOption = new MenuItem();
                keyOption.Header = "_" + i.ToString() + " " + encryptionKeys[i];
                MenuItem_EncryptRowValues.Items.Add(keyOption);
            }

            //Add Decryption Menu Items
            for (int i = 0; i < encryptionKeys.Count; i++)
            {
                MenuItem keyOption = new MenuItem();
                keyOption.Header = "_" + i.ToString() + " " + encryptionKeys[i];
                MenuItem_DecryptRowValues.Items.Add(keyOption);
            }
-2

ASP.NET -> WEB Forms -> Create Menu

CREATE TABLE `webmenu` (
  `idmenu` smallint(5) NOT NULL,
  `submenu` smallint(5) DEFAULT NULL,
  `menu_title` varchar(45) DEFAULT NULL,
  `menu_url` varchar(45) DEFAULT NULL,
  `status` enum('1','0') DEFAULT '1',
  PRIMARY KEY (`idmenu`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

SELECT 
idmenu,
(select menu_title from webmenu where idmenu=wm.submenu and status='1') as childmenu,
menu_title,
menu_url 
FROM tartyp.webmenu as wm
where
status='1'
order by idmenu, submenu;

        cmd = new MySql.Data.MySqlClient.MySqlCommand(queryStr, conn);

        reader = cmd.ExecuteReader();
        MainMenu.Items.Clear();
        while (reader.Read())
        {

            if (reader["childmenu"] == DBNull.Value)
            {
                MenuItem homeMenuItem = new MenuItem(reader["menu_title"].ToString(), reader["menu_url"].ToString());
                MainMenu.Items.Add(homeMenuItem);
            }
            else
            {
                String childmenu = reader["childmenu"].ToString();                    

                for (int i = 0; i < MainMenu.Items.Count; i++)
                {
                    if (MainMenu.Items[i].Text == childmenu)
                    {                                                       
                        MenuItem childMenuItem = new MenuItem(reader["menu_title"].ToString(), reader["menu_url"].ToString());
                        MenuItem findMenuItem = MainMenu.Items[i];
                        findMenuItem.ChildItems.Add(childMenuItem);
                        break;    
                    }
                }
            }

        }
        reader.Close();
        conn.Close();