Supporting multiple "display modes" menu in a Silverlight Prism application
Assume a standard Desktop Explorer style app:
- menu at top
- navigation tree on left
- item view on right
and everything is neatly separated into Menu, Navigation and Item modules.
The menu has a generic "View" -> "Display mode" menu selection, that changes the current item view between:
- "Icon view"
- "List view"
- "Detail view"
To 开发者_开发问答catch the display type change, I currently publish and subscribe to a DisplayModeChanged event.
First problem:
This menu option should only display when an appropriate view is visible that has the display modes. What is the best way to control shared menu buttons so they only show if at least one relevant view is active?
Second Problem:
If a view comes into existence after the selection was made, how should it pickup the current display mode state from the menu?
My first thought was that you could have solved the first problem by storing item view menu settings somewhere together with your item view. Then, on view activation you would ask your new view about its "custom menu actions" that it wants to show and one of them would be "Display mode" for item view. Other views would provide other menu actions and this one will not be shown.
But this solution contradicts with your second requirement, because you obviously want to have some global 'ItemViewDisplayModeSetting', and whenever it is changed you want all item views to be notified and change their display mode together.
So, let's just solve it right by applying the dependency injection principle. Do not look for things, ask for things. Your menu presenter (view model) requires some service that knows whether there are active item views or not. Your item view presenter requires a service that will provide initial display mode and will notify about its changes. We end up with this code:
interface IActiveViewsService : INotifyPropertyChanged
{
bool HasActiveViewsSupportingDisplayMode { get; }
}
interface IDisplayModeService : INotifyPropertyChanged
{
DisplayMode DisplayMode { get; }
}
//your item view presenter (view model)
class ItemViewModel
{
public ItemViewModel(IDisplayModeService displayModeService)
{
//obtain initial setting
//subscribe to property changes
}
}
//your menu presenter (view model)
class MenuViewModel
{
public MenuViewModel(IActiveViewsService activeViewsService)
{
//obtain initial setting
//subscribe to property changes
}
}
Then you need some way to edit your Diplay Mode from menu... you may combine that together into IDisplayModeService or you may create a new interface for that. The implementation will be a simple class that holds one DisplayMode instance and you inject one instance of that class into all your menus and item views. You'll also need to implement IActiveViewsService
, this one will probably wrap IRegionManager from PRISM or whatever is your UI management mechanism... it will listen for region changes and react when a new item view is created or when there is no one left.
interface IDisplayModeEditor
{
void ChangeDisplayMode(DisplayMode newMode);
}
//your final menu presenter (view model)
class MenuViewModel
{
public MenuViewModel(IActiveViewsService activeViewsService, IDisplayModeEditor modeEditor)
{
//obtain initial setting
//subscribe to property changes
}
}
//your final menu presenter (view model)
class DisplayModeStorage : IDisplayModeService, IDisplayModeEditor
{
private DisplayMode displayMode;
public DisplayMode DisplayMode
{
get { return this.displayMode; }
//standard propertychange notification
set
{
if(value == this.displayMode)
return;
this.displayMode = value;
this.RaisePropertyChanged("DisplayMode");
}
}
public void ChangeDisplayMode(DisplayMode newMode)
{
this.DisplayMode = newMode;
}
}
HTH.
精彩评论