使用MEF和Caliburn Micro管理先决条件

时间:2013-07-25 03:10:40

标签: c# wpf mef caliburn.micro

假设我有一个包含许多较小组件的组件,它们会在初始化第一个组件之前检查先决条件。他们不依赖于彼此,所以我不关心秩序,并希望他们同时运行。我正在使用MEF和Caliburn.Micro进行演示。

我考虑过这个设置:

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

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

现在我想要实现的是,实现IBigPrerequisite的类可以打开一个窗口(例如“找不到文件X - 这可能会导致错误。继续?”) - 这应该有可能。

但我只希望一次看到一个窗口。除了同步之外,我将如何实现这一目标?

编辑 - 因为这个问题似乎太模糊了

我需要在激活Big之前专门运行这些操作。假设我们将激活逻辑切换为如下所示:

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();
}

现在,我明确希望实现IBigPrerequisite的类能够打开一个窗口,但是如果满足所有先决条件(不需要用户交互),则不应显示任何窗口。我不想在这里打开每个班级的窗口。

我正在寻找一种方法,例如,给出IBigPrerequisite(可能应该被称为IPrerequisiteViewModel)一个属性,如bool RequestsWindow {get;},并且只在a)viewmodel请求它时才创建View b)当时没有其他先决条件窗口开启。

注意:此处的代码仅供参考,因为我不确定如何实现此行为。我对这些框架(和概念)没有经验,所以如果这个问题看起来很傻,请耐心等待。

2 个答案:

答案 0 :(得分:2)

你在这里混合概念。

Caliburn.Micro中的活动视图管理由Conductor类处理。导体派生的ViewModel可以显示大量屏幕派生的ViewModel(或其他Conductors)。可用项目存储在Items属性中。

您可以在“Screens, Conductors and Composition

找到更好的说明

MEF与导体和组合机制无关,尽管它可用于将项目列表传递给指挥。您可以定义一个[ImportMany]构造函数参数或公共属性,它接收在初始化期间显示的屏幕,并将它们存储在指挥的Items属性中。

使用构造函数参数更优雅,因为您不必将项目从属性的setter复制到Items属性。

最后,在创建视图和视图模型时不应显示消息。这应该留待以后的步骤,例如。在Activate方法期间。 Conductors和MEF将零件组合在一起并构建UI。只有在合成步骤完成后才能执行操作并与用户交谈。

答案 1 :(得分:0)

我将自己回答这个问题,详细说明我最终是如何解决这个问题的。

我制作了LoaderViewModel : Conductor<PropertyChangedBase>.Collection.OneActive, IChild<Shell>,然后给了Queue<PropertyChangedBase>

它具有Show / HideWindow方法,遍历Parent-Properties直到它到达Window-Level。

它有QueueDequeue方法。 QueuePropertyChanged - 财产上触发时使用RequestsView,如果没有标记DequeueActiveItem则调用ActiveItem很忙Dequeue会激活一个新项目,如果队列中有一个项目,然后拨打ShowWindow,如果没有项目,则会调用HideWindow

初始HideWindowViewAttached - 事件中完成,因为如果窗口被隐藏,CM似乎有一些奇怪的行为。在这里,开始并行检查先决条件,并注册一个类似于第一篇文章中的事件处理程序。

很抱歉很冗长,但代码有点冗长。如果有人要我发布,请写一条评论。