ShellViewModel Caliburn.Micro中的ViewModels引用

时间:2016-06-17 12:59:30

标签: mvvm dependency-injection caliburn.micro

在这个帖子中:Can anybody provide any simple working example of the Conductor<T>.Collection.AllActive usage?我已经有了一部分答案,但我仍然很困惑。

我只想将我的所有视图模型引用到我的ShellViewModel中,以便能够打开/关闭ContentControls,但不会在构造函数中注入所有这些模型。

在答案中,建议在ShellViewModel的构造函数中注入一个接口。如果我这样做,我是否必须将所有ViewModel注入实现该接口的类中?

public MyViewModel(IMagicViewModelFactory factory)
{
    FirstSubViewModel = factory.MagicallyGiveMeTheViewModelIWant();
    SecondSubViewModel = factory.MagicallyGiveMeTheViewModelIWant();
    ThirdSubViewModel = factory.MagicallyGiveMeTheViewModelIWant();

    Items.Add(FirstSubViewModel);
    Items.Add(SecondSubViewModel);
    Items.Add(ThirdSubViewModel);
}

另外,我想避免通过IoC.Get&lt;&gt;为了获得我的视图模型的实例,我认为如果我没有弄错,它违反了IoC的原则。 在其他几个例子中,他们在需要时创建了新的viewModel,但在这种情况下使用IoC的重点是什么,特别是当我需要在这些新的ViewModel中注入服务时?

在我的Shell视图中,我有一个包含3个不同区域的布局,通过以下方式绑定到我的shell视图模型:

 <ContentControl x:Name="Header"
                    Grid.ColumnSpan="3"/>
 <ContentControl x:Name="Menu"
                    Grid.Row="1"/>
 <ContentControl x:Name="Main"
                    Grid.ColumnSpan="3"/>

在我的ShellViewModel中扩展了Conductor.Collection.AllActive,我引用了这样的3个区域:

public Screen Menu { get; private set; }
public Screen Header { get; private set; }
public Screen Main { get; private set; }

我希望能够像这样改变它们:

Menu = Items.FirstOrDefault(x => x.DisplayName == "Menu");
Header = Items.FirstOrDefault(x => x.DisplayName == "Header");
Main = Items.FirstOrDefault(x => x.DisplayName == "Landing");

我的所有ViewModel都在其构造函数中设置了DisplayName。

我试过这个,但GetChildren()是空的

foreach (var screen in GetChildren())
        {
            Items.Add(screen);
        }

我错过了一些明显的东西吗?

提前致谢!

1 个答案:

答案 0 :(得分:0)

最后,我自己找到了答案。这一切都在AppBootstrapper中!

我最终为我的Screen创建了一个ViewModelBase,这样他们就可以拥有一个IShell属性(以便ViewModel可以触发ShellViewModel中的导航),如下所示:

public class ViewModelBase : Screen
{
    private IShell _shell;

    public IShell Shell
    {
        get { return _shell; }
        set
        {
            _shell = value;
            NotifyOfPropertyChange(() => Shell);
        }
    }
}

然后在AppBoostrapper中注册了他们:

container.Singleton<ViewModelBase, SomeViewModel>();
container.Singleton<ViewModelBase, AnotherViewModel>();
container.Singleton<ViewModelBase, YetAnotherViewModel>();

然后创建一个IEnumerable作为param传递给我的ShellViewModel ctor:

IEnumerable<ViewModelBase> listScreens = GetAllScreenInstances();

container.Instance<IShell>(new  ShellViewModel(listScreens));

然后将IShell传递给每个ViewModels

foreach (ViewModelBase screen in listScreens)
{
    screen.Shell = GetShellViewModelInstance();
}

为了完整起见,这里是我的GetAllScreenInstances()和GetShellViewModelInstance():

protected IEnumerable<ViewModelBase> GetAllScreenInstances()
{
     return container.GetAllInstances<ViewModelBase>();
}
protected IShell GetShellViewModelInstance()
{
    var instance = container.GetInstance<IShell>();
    if (instance != null)
        return instance;

    throw new InvalidOperationException("Could not locate any instances.");
}

这是我的ShellViewModel ctor的样子:

public ShellViewModel(IEnumerable<ViewModelBase> screens )
{         
    Items.AddRange(screens);
}

希望这可以帮助将来的某个人!