Caliburn.Micro IChild.Parent is null unless activa

2019-08-27 22:04发布

问题:

I have a Parent and Child viewmodel:

public class ParentViewModel : Screen 
{
    public ChildViewModel Child { get; set; }
}

public class ChildViewModel  : PropertyChangedBase, IChild { }

When the Parent VM is displayed using Conductor.ActivateItem(), Caliburn.Micro does the usual labours of searching through the view model object graph and looking for views to display etc.

After all this is completed, I find that while ParentViewModel.Parent is a reference to the Conductor, ChildViewModel.Parent is null.

Is this by design?

Many thanks in advance.

回答1:

Yes this is by design, the method that sets the Parent property is EnsureItem in the ConductorBase, therefore it's only conductors that will set it when the active item is changed.

The Parent is therefore also only available in the activation life cycle of the child, e.g. OnInitialise or OnActivate etc.

Is there any reason your ParentViewModel isn't a Conductor type and your ChildViewModel a Screen?

Also, depending on the Parent property may be introducing coupling in your ChildViewModel.



回答2:

One workaround for this is for the parent VM to pass itself to the child VM somehow.

Either by setting the Parent property explicitly:

var child = new ChildViewModel
{
    Parent = this
};

Or, assuming you have some sort of IoC-based abstraction for initialising view model objects, you could have a convention of implementing Configure() methods that return this:

public class ChildViewModel : PropertyChangedBase, IChild
{
    // IChild members...

    public ChildViewModel Configure(IScreen parent)
    {
        Parent = parent;
        return this;
    }
}

public class ParentViewModel : Screen
{
    public ChildViewModel Child { get; set; }

    protected override void OnInitialize()
    {
        Child = _viewModelFactory.Create<ChildViewModel>()
                                 .Configure(this);
    }
}

It should be possible to customise Caliburm.Micro's view model handling code to set the parent automatically, but I'm not clever enough with it yet to know how to do that, yet. :)