Isilmë O.
Isilmë O.

Reputation: 1746

How to activate corresponding screen in Caliburn.Micro

1.In my Silverlight project, I've got several Plugins (inheriting IPlugin and IScreen) and import them into the ShellView (main view) using MEF.

2.Then I bind the metadata (I've defined myself, including some basic descriptions of a Plugin) of Plugins to a ListBox.

Now I want the ContentControl to load the viewmodel corresponding to the selcted plugin (PluginMetadata to be exactly) in the ListBox. The problem is the viewmodel has to be determined and instantiated at runtime. I've searched a lot but it seems that people usually activate the viewmodel which is already determined at design time. For example:

ActivateItem(new MyContentViewModel());

or:

<ContentControl x:Name="MyContent" cal:View.Model="{Binding Path=MyContentViewModel}" />

One idea that came to my mind was to determine the type corresponding to the plugin by defining an attribute in my PluginMetadata class and use it like this:

[Export(IPlugin)]
[PluginMetadata(Type=typeof(Plugin1), ...some other properties...)]
public class Plugin1 {...}

And load the viewmodel with an instance of the plugin created using Reflection.

ActivateItem(Activator.CreateInstance<SelectedPluginMetadata.Type>());

or maybe I can also use binding if I add a property SelectedPluginType:

<ContentControl x:Name="MyContent" cal:View.Model="{Binding Path=SelectedPluginType}" />

However, passing the type in the metadata attribute seems so ungraceful and against DRY.

So is there any better solution?

Upvotes: 0

Views: 1336

Answers (1)

Charleh
Charleh

Reputation: 14002

Ok so instead:

The ViewLocator exposes this delegate which you can replace with your own:

    public static Func<Type, DependencyObject, object, UIElement> LocateForModelType = (modelType, displayLocation, context) => {
        var viewType = LocateTypeForModelType(modelType, displayLocation, context);

        return viewType == null
                   ? new TextBlock { Text = string.Format("Cannot find view for {0}.", modelType) }
                   : GetOrCreateViewType(viewType);
    };

So I'd probably just stick this in your Bootstrapper.Configure:

    ViewLocator.LocateForModelType = (modelType, displayLocation, context) => 
    {
        if(modelType is IPlugin) modelType = ? // whatever reflection is necessary to get the underlying type? Just GetType()?
        var viewType = ViewLocator.LocateTypeForModelType(modelType, displayLocation, context);

        return viewType == null
                   ? new TextBlock { Text = string.Format("Cannot find view for {0}.", modelType) }
                   : ViewLocator.GetOrCreateViewType(viewType);
    };

Upvotes: 1

Related Questions