Hello,
I am using xamRibbon and ApplicationMenu2010 in a MVVM application. In order to put configuration items (like user setting, system wide setting etc.) into the ApplicationMenu2010 I see following options:
1. Put the content directly in XAML of the shell window
Pro: Clear and easy
Con: The whole XAML loading is done at startup of the shell and the configuration might not be used in the current session.
2. Add the menu items in code behind:
Pro: Not loaded at startup
Con: On _OnOpened() all items are created -> slow
private void ApplicationMenu2010_OnOpened(object sender, RoutedEventArgs e) { ApplicationMenu2010 menu = (ApplicationMenu2010)sender;
if (menu.Items.Count > 0) { return; }
menu.Items.Add(new ApplicationMenu2010Item { Header = "Einstellungen" });
menu.Items.Add(new ApplicationMenu2010Item { Header = "Benutzereinstellungen", Content = new vBenutzerEinstellungen(new vmBenutzerEinstellungen()) }); menu.Items.Add(new ApplicationMenu2010Item { Header = "Systemweite Farben", Content = new vSystemweiteFarben(new vmSystemweiteFarben()) }); menu.Items.Add(new ApplicationMenu2010Item { Header = "Systemweite Einstellungen", Content = new vGlobalConfig(new vmGlobalConfig()) });}
I wonder if there is a possibility to create only the currently clicked it at the time its needed.
var pwditem = new ApplicationMenu2010Item { Header = "Test", Style = (Style)GlobalStyles.Instance["ApplicationMenuItem"] }; pwditem.SetBinding(ApplicationMenu2010Item.CommandProperty, new Binding("OpenConfigurationItem")); menu.Items.Add(pwditem);
private vTest OpenConfigurationItem() { View vTest; vTest= this.Container.GetInstance<AppFact.Infrastructure.MVVM.ViewBase>("vTest"); return vTest;}
I want to create the different views with configuration records only when they are really neded.
In addition: Is there a way to mark a ApplicationMenu2010Item as header without click function?
Thanks
Niko
Hello Niko,
I am not entirely sure I completely understand your requirement in this case, but it sounds like you are looking to generate your ApplicationMenu2010Item elements as needed, depending on the view that you have. If this impression is incorrect, please let me know as the following is based upon it.
In order to do this, I would recommend that you continue with the Opened event of the ApplicationMenu2010. In this event, you can clear the Items collection of your ApplicationMenu2010 (if needed) and check the current view in your application. If you store some information regarding the ApplicationMenu2010, such as a List of ApplicationMenu2010Item elements, you can then check that information or loop through that collection of ApplicationMenu2010Item elements and add them to your ApplicationMenu2010 menu. This should allow you to create a potentially different ApplicationMenu2010 view for each of your views.
As for marking an ApplicationMenu2010Item as a header without a click function, I suppose one thing you could do is mark the IsHitTestVisible property of the ApplicationMenu2010Item as "false." This would prevent any sort of mouse event from firing on it, although, you would also lose the highlight on mouse hover effect as well. Another thing you could try in this case is to utilize the PreviewMouseDown/Up events of the ApplicationMenu2010Item and mark them handled. This should prevent the internally handled MouseDown/Up event from going through, essentially marking your ApplicationMenu2010Item "unclickable."
I hope this helps. Please let me know if you have any other questions or concerns on this matter.
Sincerely,AndrewAssociate Developer
Hello Andrew,
the ApplicationMenu2010Items will always be the same.
I would to create and render the view only if the user has selected the specific MenuItem.
For example there is a menu with 5 Items;
Each item has view (in this case a usercontrol) to show and manage the data.
In most of the cases the user wont open all Items, mainly only one or two. Currently all Items are generated (all views and viewmodels for the menutitems).
I would like to have a XAML ApplicationMenu2010Items defined in XAML (or codebehind if neccessary).
a) The user clicks on the menu item
b) The view and the viewmodel for this specific menu item are created
Hello Andrew (and the to me unknown developer who is following this thread),
I implemented you suggestion and it works.
I summarize me current understanding:
1. The ViewModel of the different setting windows are properties of the shell (= mainwindow) viewmodel
2. These viewmodels are created immediatly
3. The Views of the different setting windows are the ContentTemplate. They are generated when the user clicks on the menu item.
4. The first menu items is already created on opening the Application menu
Question: is it possible to set the first item to non functional header?
Hi Niko,
One of our XamRibbon developers has noticed our discussion here, and has brought it to my attention that perhaps the best way of dynamically generating your ApplicationMenu2010Item elements would be to use the ItemsSource property of the Application2010Menu and bind it to a collection of your objects that is based on the current condition that determines the ApplicationMenu2010Items that should be generated. In doing so, this would make the Content of your ApplicationMenu2010Item elements the objects that exist in the collection, and then you could use the ContentTemplate property of the ApplicationMenu2010Item to essentially inject your UserControl elements to the menu items.
You could use the DataTemplates either explicitly by giving them an x:Key and setting them to the ApplicationMenu2010Item.ContentTemplate or implicitly by setting the DataType property and letting the ApplicationMenu2010Item pick up on them automatically. The UserControl elements that you create would not be instantiated until the ApplicationMenu2010Item is clicked on, as they will be lazily allocated.
I have attached a sample project to demonstrate the explicit and implicit DataTemplate usage with the ApplicationMenu2010Item elements.
Please let me know if you have any other questions or concerns on this matter.
From the code that you have provided, it appears that when the ApplicationMenu2010 menu opens, you are creating a single ApplicationMenu2010Item and associating a command with it that will initiate the item's Content when fires. The issue with this is that when an ApplicationMenu2010 menu opens, it appears that if none of the items have content, nothing will be selected. This couples with the fact that the Command property of the ApplicationMenu2010Item only fires when the item is actually clicked, and so it is expected in this case that you are not seeing any Content when you first visit the ApplicationMenu2010, as when the menu actually opens, your Command is likely not firing, and so no Content is set on the ApplicationMenu2010Item.
I would recommend that in this case, when you assign your ApplicationMenu2010Item elements to your ApplicationMenu2010 when it opens, that you set the Content of that first item (or other item that you wish to have selected) and ensure that the item is selected. You can ensure that the item is selected by setting the SelectedTabItem property of the ApplicationMenu2010 element to your desired ApplicationMenu2010Item.
I am also seeing an issue locally where if the Content is set on an ApplicationMenu2010Item on click or when its Command fires, sometimes it will toggle its selected state back to false. This can be worked around by getting the ApplicationMenu2010 in your Execute method from the targetItem.Parent property and marking the SelectedTabItem of the ApplicationMenu2010 as your targetItem after setting the Content property. Are you seeing this behavior as well?
I have created following logic:
1. OnOpened() creates the menu items via the method CreateMenuItem()
2. The ViewFactoryCommand fills in the content
The only remaining problem is the fact that I don't know how to display the content. Currently its only shown when I reopen the Application Menu.
Whats the best way to display the content already at the first time on create?
menu.Items.Add(CreateMenuItem("Systemweite Einstellungen", () => new vGlobalConfig(new vmGlobalConfig())));
}
ApplicationMenu2010Item CreateMenuItem<T>(string header, Func<T> command) where T : System.Windows.Controls.UserControl { var item = new ApplicationMenu2010Item { Header = header, Style = (Style)GlobalStyles.Instance["ApplicationMenuItem"] }; item.Command = new ViewFactoryCommand<T>(item, command); return item; }
public class ViewFactoryCommand<TView> : ICommand where TView : System.Windows.Controls.UserControl { public event EventHandler CanExecuteChanged; ApplicationMenu2010Item targetItem; Func<TView> factoryFunction; public ViewFactoryCommand(ApplicationMenu2010Item targetItem, Func<TView> factoryFunction) { this.targetItem = targetItem; this.factoryFunction = factoryFunction; } public bool CanExecute(object parameter) { return true; } public void Execute(object parameter) { if (targetItem.Content == null) { targetItem.Content = factoryFunction(); } } }
Thank you for your update on this matter. That clarifies this issue a bit further.
In this case, I believe the "slow" behavior that you are seeing is likely coming from the following lines of code that you have provided:
menu.Items.Add(new ApplicationMenu2010Item { Header = "Benutzereinstellungen", Content = new vBenutzerEinstellungen(new vmBenutzerEinstellungen()) });menu.Items.Add(new ApplicationMenu2010Item { Header = "Systemweite Farben", Content = new vSystemweiteFarben(new vmSystemweiteFarben()) });menu.Items.Add(new ApplicationMenu2010Item { Header = "Systemweite Einstellungen", Content = new vGlobalConfig(new vmGlobalConfig()) });
In here, it appears that you are initializing the UserControl elements that you are looking to have as the actual Content for your ApplicationMenu2010Item elements, which I imagine is likely initializing the view and view-model for each menu item in this case, adding to the overhead of your application each time the ApplicationMenu2010 menu is opened.
In order to avoid this, I would recommend abstaining from setting the Content property of your ApplicationMenu2010Item until the item is clicked. You can detect when this click happens by handling the Click event of the ApplicationMenu2010Item. When this fires, you can set the Content of your ApplicationMenu2010Item in order to load the view for that particular item. This should prevent the creation of those views when opening the ApplicationMenu2010 menu.