I'm trying to dynamically alter the menu items in a RadMenu when another action occurs in my application.
I've tried menu.Items.Clear() and menu.Items.Add(). Both result in an InvalidOperationException being thrown with the detail "Operation not supported on read-only collection.".
Is there a way to alter the menu items at run time?
Thanks,
Glen
17 Answers, 1 is accepted
ItemsControl.Items collection is ReadOnly if you set ItemsSource property. So in order to change to Items you should alter the ItemsSource collection. If your collection implements INotifyCollectionChange just remove the item from your collection and the change will be reflected automaticaly in RadMenu.
The other way is not to use ItemsSource. Just add items directly to Items property. This way the Items collection will not be readonly.
If you need more help, we'll be glad to help.
Best wishes,
Hristo
the Telerik team
Check out Telerik Trainer, the state of the art learning tool for Telerik products.
Thanks for that info, I can add items now.
My next stumbling block is that I don't know how to add sub items. My menu needs to be dynamic and will sometimes have 3 levels and sometimes have 4. So it will look something like:
Country
-> State
-> Province
-> City
But not all states have provinces. If there are no provinces I don't want to have that level appearing in the menu.
So my code looks like:
foreach (var country in Countries)
{
CountryMenu.Items.Add(country);
foreach (var state in country.States)
{
// What goes here?
CountryMenu.Items(Country).Items.Add(state); // This doesn't work. The item is the data object, not the RadMenuItem
}
}
What I really need is a way to access the RadMenuitems, not the "Items" property so that I can add sub menu items.
I could create an xml doc or even just bind to the data structure, but I don't know how I'd exclude the menu layer if a state has provinces. Also, I need the leaf node in the menu to be clickable, and if I can't trap the OnClick method of the leaf node, I'm not sure how I'd know it's been clicked.
Do you have any thoughts how I could do this?
Thanks,
Glen
You can create an ObservableCollection from your data items and set them as ItemsSource on RadMenu. Then using HierarchicalDataTemplate you can create menu with unlimited nested leves.
Here is an example:
http://demos.telerik.com/silverlight/#Menu/DataSource
Let me know if you need more help.
Regards,
Hristo
the Telerik team
Check out Telerik Trainer, the state of the art learning tool for Telerik products.
I've seen that example and have implemented something similar. I was actually asking about something different.
What I am trying to do is have a menu structure where the number of sub menus is not fixed. I need it to be fully dynamic. As far as I can tell, using HierarchicalDataTemplate means that you're setting a template so that the first level menu is always of a certain type, then the second level menu is always of a certain (different) type. It won't allow me the flexibility of having different sub menu structures.
So what I want is:
Menu
-> Australia
->Victoria
->Melbourne
-> Bendigo
->NSW
->Sydney
-> UK
->London
->Leeds
Do you see how under the Australia node there are two sub menu levels (state and city) where under the UK node there is only one level (city only).
Glen
Using HierarchicalDataTemplate allows you to create hirarchy. HierarchicalDataTemplate have ItemsSource property that tells the item from where to get its children.
I've attached a simple Page (UserControl) that demonstrate how to achieve dynamic MenuItems using classes like Country, State etc. You need to add it to existing project and add reference to our assemblies in order to run it.
There is a problem with menuitem which is not loaded but change its items. This problem will be fixed for the next release - service pack 2 (due to middle of december). If you need it earlier just open a support ticket and I will send you the hotfix.
If you need more help, I'll be glad to help
Greetings,
Hristo
the Telerik team
Check out Telerik Trainer, the state of the art learning tool for Telerik products.
Thankyou for the information, but you are still misunderstanding what I'm actually asking. I've seen that sample before and it works fine. But it doesn't do what I want it to do.
The example you have provided has dynamic menu data but I want dynamic menu structure.
I want to allow one of the sub menus to not even have a "Province" item. So it goes Country->State->City. The other sub menu should have the province. It should go Country->State->Province->City. Can you see that the structure of the menu is different? In this case, there is not a single class hierarchy that can be bound to the menu ItemSource to provide this.
Glen
Now I get what you want to achieve.
They way I see it you can use generic collection and fill it with items that have Name and Items properties. This way you can use a single HierarchicalDataTemplate. I've attached an updated version of the sample illustrating this approach.
The other way is to fill manually Items collection with RadMenuItem objects. This way you can take the RadMenuItem from Items collection with cast:
foreach (var country in Countries) |
{ |
RadMenuItem countryItem = new RadMenuItem() { Header = country.Name }; |
CountryMenu.Items.Add(countryItem); |
foreach (var state in country.States) |
{ |
RadMenuItem stateItem = new RadMenuItem() { Header = state.Name }; |
// Either use countryItem |
countryItem.Items.Add(stateItem) |
// Or if you don't have reference to countryItem you can take it like this; |
//RadMenuItem countryItem = CountryMenu.Items[0] as RadMenuItem; |
} |
} |
I hope this help.
If you need more help, just drop me a line.
Kind regards,
Hristo
the Telerik team
Check out Telerik Trainer, the state of the art learning tool for Telerik products.
Thanks for the information. I tried adding RadMenuitems but I was getting exceptions thrown when the menu was displayed.
I like your suggestion of having a generic structure with Name and Item properties. I'll try that out.
Thanks,
Glen
I am getting the same problem here. I have created Menu. The main Menu contains File, GoTo.
I have created MenuItems dynamically using menu,Items.Add() method. As per my requirment. on the acton of any in my page the child Items are different. So I need the remove the all child Items and Add new Items under GoTo Main Menu Item.
When I am trying to remove items under GoTo menu I am getting Parse error. on gotoItem.Items.Clear(); "AG_E_UNKNOWN_ERROR [Line: 1 Position: 1426]"
RadMenu --> rdmenu
RadMenuItem[] items = new RadMenuItem[rdmenu.Items.Count];
rdmenu.Items.ToArray().CopyTo(items, 0);
RadMenuItem gotoItem = (from menuItem in items
where string.Compare(menuItem.Tag.ToString(), "Goto", StringComparison.InvariantCultureIgnoreCase) == 0
select menuItem).Single();
gotoItem.Items.Clear();
Can u please help me to fix this issue.
this is the error :" at MS.Internal.XcpImports.MethodEx(IntPtr ptr, String name, CValue[] cvData)\r\n at MS.Internal.XcpImports.MethodEx(DependencyObject obj, String name)\r\n at MS.Internal.XcpImports.Control_ApplyTemplate(Control control)\r\n at System.Windows.Controls.Control.ApplyTemplate()\r\n at Telerik.Windows.Controls.RadMenuItem.ChangeTemplate()\r\n at Telerik.Windows.Controls.RadMenuItem.UpdateRole()\r\n at Telerik.Windows.Controls.RadMenuItem.OnItemsChanged(NotifyCollectionChangedEventArgs e)\r\n at System.Windows.Controls.ItemsControl.RaiseOnItemsChanged(NotifyCollectionChangedEventArgs e)\r\n at System.Windows.Controls.ItemCollection.NotifyItemsControl(NotifyCollectionChangedEventArgs e)\r\n at System.Windows.Controls.ItemCollection.RemoveAtImpl(Int32 index)\r\n at System.Windows.PresentationFrameworkCollection`1.RemoveAt(Int32 index)\r\n at System.Windows.Controls.ItemCollection.RemoveInternal(Object value)\r\n at System.Windows.PresentationFrameworkCollection`1.Remove(T value)\r\n at Xcel.Framework.RIA.ActivityManagement.CommonUI.Menu.notifyGotoMenuBuild_PropertyChanged(Object sender, PropertyChangedEventArgs e)"
Can you send us a simple project where we can investigate this issue. I have tried your case but there was no exception. Can you please check that you are using the latest version of our assemblies?
Also do you put UIElements in the Header property of RadMenuItem or just strings?
Waiting for your reply.
Best wishes,
Hristo
the Telerik team
Check out Telerik Trainer, the state of the art learning tool for Telerik products.
I have used old version .. I put UIElements in the Header property .
If there is no issues in new version so i will use that one.
Is there any issue to add UIElements in the Header property ?
Thanks
Bichitra
Unfortunately there is an issue when Header is populated with UIElement. RadMenuItem Template contains ContentPresenter (or in some themes ContentControl) that is bound to Header property. When template is changed Silverlight doesn't clean this binding and when the new template is applied is tries to bind to the same UI object in the Header. But this object have parent and cannot have other parent until the first binding is removed so an exception is raised.
We will try to find some workaround but for the moment I can think of one solution.
Theme changing is happening when you remove all the Items. So instead of removing all items try to leave one item then add some new items and at the end remove the item that that was left.
Like this:
private void Button_Click(object sender, RoutedEventArgs e) |
{ |
// Leave at least 1 item |
for (int i = 1; i < menu1.Items.Count; i++) |
{ |
menu1.Items.RemoveAt(1); |
} |
// Add the new items |
menu1.Items.Add(new RadMenuItem() { Header = "asdasd" }); |
// remove the last item from the previos menu |
menu1.Items.RemoveAt(0); |
} |
Here menu1 is root RadMenuItem.
Let me know if this works for you.
Best wishes,
Hristo
the Telerik team
Check out Telerik Trainer, the state of the art learning tool for Telerik products.
Thanks for helping.. It is working now.
Regards
Bichitra
I've got a similar problem, but I want to bind to a menu structure defined in a SQL Server database. I can write the SQL to retrieve the structure and add the items one by one, but is there a way to bind the menu directly to a single query resultset or is it necessary to iterate over the items and levels? If this is possible, can you point me at an example?
Best wishes,
Kaloyan
the Telerik team
Instantly find answers to your questions on the new Telerik Support Portal.
Watch a video on how to optimize your support resource searches and check out more tips on the blogs.
foreach (var country in Countries) |
{ |
RadMenuItem countryItem = new RadMenuItem() { Header = country.Name }; |
CountryMenu.Items.Add(countryItem); |
foreach (var state in country.States) |
{ |
RadMenuItem stateItem = new RadMenuItem() { Header = state.Name }; |
// Either use countryItem |
countryItem.Items.Add(stateItem) |
// Or if you don't have reference to countryItem you can take it like this; |
//RadMenuItem countryItem = CountryMenu.Items[0] as RadMenuItem; |
} |
} |
This is well and good. Question tho, how do I add event handlers to the items?
Thanks in advance!
RadMenuItem control is exposing a whole lot of events(Click, MouseLeftButtonDown...etc.etc) that can be used for adding event handlers. Exactly which event are you looking for?
Kind regards,
Kaloyan
the Telerik team
Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items.