Silverlight MVVM MEF ViewInjection
since my title is buzzword compliant I hope I will get lots of answers to my question or any pointers to the right direction.
OK what I usually do is have a ViewModel which contains a list of ViewModels itself.
public class MasterViewModel
{
public ObservableCollection<DetailViewModel> DetailViewModels { get; set; }
public DetailViewModel Detail { get; set; }
}
<ItemsControl ItemsSource="{Binding DetailViewModels}">
<ItemsControl>
<ItemsPanelTemplate>
<StackPanel />
</ItemsPanelTemplate>
</ItemsControl>
<ItemsControl.ItemTemplate>
<DataTemplate>
<views:DetailsView />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
With this in mind I will now come to my questions. I read a lot of good things about MEF and also saw the dashboard sample of Glenn Block but this was not helping me enough.
What I want to do is sidbar (like the windows sidebar). Sidebar = StackPanel ListItems = Gadget
ButI want it MVVM style
OK I have something like a contract
IGadget
I implemented an custom Export.
[ExportGadget(GadgetType = GadgetTypes.News)]
I have my NewsGadgetView.xaml (which implements IGadget) and imports the NewsGadgetViewModel and also makes itself available as ExportGadget.
so far so good. With this I can create a set of gadgets.
Then I have my SidbarView.xaml which imports a sidebarViewModel.
and now I get lost...
I thought of something like a GadgetFactory which uses PartCreator to create my Gadgets. but this would sit in my SidebarView.xaml But I want to have control over my Gadgets to add and remove them from my sidebar. So I thought about something like an ObserveableCollection...
Which I bind to
The GadgetHost is basicaly Grid which will dynamicaly load the Gadget....
So how would I create my sidebar containing different gadgets without knowin开发者_JAVA百科g which Gadgets are available and have a ViewModel for the sidebar as well as for each gadget?...
Thanks for any help....
This is where the power of the Managed Extensibility Framework comes in. I basically have the same challenge with an existing project.
My resolution was to abstract the views and regions, and then use a routing mechanism.
Basically, there is a custom export for a region, and I export a FrameworkElement (might be a StackPanel, Grid, etc etc), The views have a set of attributes, those are exported as UserControl.
A manager handles the imports using a lazy import collection. It simply assigns these to a dictionary so we have view enums mapping to instances of views, then region enums mapping to instances of the regions.
The route table then waits for a request to activate a view (this may happen on load), and finds the route from the view to the region, then inserts it.
What about the view model?
For "global" information I'm using a contract that is exported, like this:
[Export(typeof(IMasterViewModel))]
public class MasterViewModel
{
}
That has something every plugin may need. Then I have a base view model the "child" view models inherit from:
public class BaseViewModel
{
[Import(typeof(IMasterViewModel))]
public MasterViewModel MasterVM { get; set; }
}
So now let's say I have a completely separate XAP. I will need to reference some "common" interfaces. So I'm not referencing an instance of the global view model, just the contract. However, within my plugin XAP, I can do this:
[Export]
public class PluginViewModel : BaseViewModel
{
etc ... etc ..
}
public partial class PluginControl : UserControl
{
[Import]
public PluginViewModel
{
get { return LayoutRoot.DataContext as PluginViewModel; }
set { LayoutRoot.DataContext = value;
}
}
When the view model is imported to the view, it will also import the master view model, providing access to those other parts. If you need to trigger some action when the view model is available, simply implement IPartImportsSatisfiedNotification and you can fire when ready.
精彩评论