Search code examples
c#wpfmefcaliburn.micro

Managing prerequisites with MEF and Caliburn Micro


Lets say I have a component with a number of smaller components which check prerequisites before the first one will be initialized. They are not dependent on one another so I don't care about order and would like them to run simultaneously. I am using MEF and Caliburn.Micro for presentation.

I thought about this setup:

class Big
{
    [ImportMany]
    public IEnumerable<IBigPrerequisite> Prerequisites {get; set;}
    public void Initialize(){...}
}

and

interface IBigPrerequisite
{
    public bool IsBusy {...}
    public bool Allow {...}
    public void StartChecking();
}

Now what I would like to accomplish with this is that the classes implementing IBigPrerequisite can open up a window (for example "File X was not found - this could lead to errors. Continue?") - this should be possible.

But I would only want one window to be visible at a time. How would I accomplish that besides just going synchronously?

EDIT - since the question seemed too vague

I need these Actions to run specifically before Big will be activated. Let's say we switch up the activation logic to something like this:

Big big; //we got this through Importing somewhere in composition
var allow = true;
var count = 0;
if(!pre.Any()) //no prerequisites, show window immediately
    windowManager.ShowWindow(big)
foreach(var pre in big.Prerequisities)
{
    pre.PropertyChanged += (s, args) => 
    {
        if(args.PropertyName == "IsBusy" && !pre.IsBusy) // if a prerequisite finished it's check
        {
            allow = allow && pre.Allow; //if one prerequisite says nay we could just return, actually...
            count++;
            if(count == big.Prerequisites.Count() && allow)
                windowManager.ShowWindow(big);
        }
    }
    pre.StartChecking();
}

Now, I explicitly want the classes implementing IBigPrerequisite to be able to open a window, but in case all prerequisites are met (no user interaction required) no window should be showing. I do not wish to open up a window for every class here.

I am looking for a way to, say, give the IBigPrerequisite (which should probably be called IPrerequisiteViewModel anyways) a property like bool RequestsWindow {get;} and have the View only created when a) the viewmodel requests it and b) no other prerequisite window is open at the time.

Note: the code here is for illustration only as I am not sure how to implement this behaviour yet. I am not experienced with these frameworks (and concepts) so if this question seems silly please bear with me.


Solution

  • I am going to answer this question myself detailing how I ended up solving this.

    I made a LoaderViewModel : Conductor<PropertyChangedBase>.Collection.OneActive, IChild<Shell> and gave it a Queue<PropertyChangedBase>.

    It has Show/HideWindow methods by traversing the Parent-Properties until it arrives at the Window-Level.

    It has Queue and Dequeue methods. Queue is used when PropertyChanged is fired on a RequestsView-Property and calls Dequeue if there's either no ActiveItem or the ActiveItem is not marked as busy. Dequeue will activate a new item if there is one in the queue and then call ShowWindow, if there is no item it will call HideWindow instead.

    The initial HideWindow is done in the ViewAttached-Event since if the window is hidden, CM seems to have some strange behaviour. Here, the parallel checking of the prerequisites is started and an event-handler registered similar to the one in the first post.

    Sorry for being verbose, but the code has gotten a bit lengthy. If someone wants me to post it up write a comment.