Before I spent a bunch of time on this, only to find out there is an easier way, I thought I would check first.
I have a large number of menu items. Some are controlled by user roles. Others are controlled by user (or admin) selection.
The roles part is easy (now.... - to bad we can't easily add links to those discussions)
In my StartViewModel - I build the menus (with appropriate roles specified).
As I am creating the menu or once the menu is up, if the user indicates they want (or don't want) a menu option, what is the best way to implement this?
1) It would be nice to have an easy way to find out which menu options are enabled for the user already - i.e. foreaching the Actions to see what is there or not. Any suggestions on this? Then I can just cycle through all the menu options and only create those
that are desired. Even if not needed for this issue, a sample of doing that to find any action might be nice.)
2) Or can I just create a new ViewAction and it will see there is a duplicate and override the duplicate?
3) From the UI config page, when the user so indicates, I should be able to just add the desired action - but then I have 2 separate lines of the code to instantiate the menu (startviewmodel and whatever responds to the user IO) - unless I have a menuHandler
routine where I just pass it the name of the menu item and it creates it.
4) I should be able to remove an action via Actions.Remove(...) as well - but I don't seem to see any code that does that, so I am wondering if there is a better approach to removing menu items.
5) It may be that I don't need the conditional logic to create/remove the menu actions because there is way to specify an event that can be associated with the menu and a binding source and if the binding source changes, the menu goes away and that I should
just bind the menus visibility to that (in addition to the roles.)
I know I can figure out which of these works, which works best, etc., but that would take a fair amount of time (and testing.) And I am fairly positive you can just say "oh, yeah, just do ....." and save us all a bunch of time.
Jun 17, 2013 at 11:37 AM
Here's a link to that original role discussion:
Just a general comment about menus: Make sure you do not create all possible menu items at once and then hide and show them, but just create the main menu items when the app starts in the start view model. Then, create the items that apply to each view with
that view(model) only. This way, they automatically only show up with the appropriate view and that covers most of your needs for hiding/showing menus.
Now for your specific questions:
1) You can iterate over the view action collections and query things like the Availability property or call the CanExecute() method.
2) View actions do not check for duplicates.
3) If you want to implement a custom system that allows the user to manually decide which menu items they want to see, I would probably use subclassed view actions that go to whatever system you want to use to store the config the user has selected. You could
then override the Availability property to hide and show them as needed. Most themes use that property to define whether an item is to be shown or not. Another option would be to actually change the theme and use a modified menu (or Ribbon, or...). By default,
the menu just consolidates all actions and then populates itself, using categories to create top-level menus and menu hierarchies and such. You could completely customize that mechanism and create the menu based on any other logic that suits your needs.
4) I would think just hiding options is better than removing them. It fits the actual scenario better. When a user doesn't want to see a menu item in the menu, it's just that they don't want to see that anymore, but the app still has the capability to do so.
So just hiding seems more accurate. Who knows: Maybe you decide later that you want to bind that action to a hotkey or something and then you'd be in trouble, because the action the hotkey is bound to got removed or something.
5) You do not manually have to bind visibility. The themes already query the Availability property of each action. Plus, if something changes, you can always call InvalidateCanExecute() on an action, which will force a refresh.