Jon Ediger
Jon Ediger

Reputation: 989

WPF: How can you add a new menuitem to a menu at runtime?

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.

Upvotes: 25

Views: 69482

Answers (6)

Kyrylo Kovalenko
Kyrylo Kovalenko

Reputation: 2171

You can let WPF enumerate a collection of models and create a sub MenuItem for each model, e.g.

IEnumerable<RoamingDevice> devices = ...;
DevicesMenuItem.ItemsSource = devices;

Upvotes: 0

Patrick Hendry
Patrick Hendry

Reputation: 61

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

Upvotes: 6

Brandon Hawbaker
Brandon Hawbaker

Reputation: 554

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

Upvotes: 0

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

Upvotes: -2

awe
awe

Reputation: 22442

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
}

Upvotes: 12

Whytespot
Whytespot

Reputation: 951

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

Upvotes: 31

Related Questions