Initialize hierarchical tree viewmodels with unity

↘锁芯ラ 提交于 2019-12-25 07:44:47

问题


I'm investigating a change in our application to use Prism. At the moment I'm struggling with the initialization of hierarchical structures.

Basically I have a base class of which other classes inherit, simplified like this:

public class NodeViewModel : INodeViewModel
{
    Node Node { get; private set; }
    public ObservableCollection<INodeViewModel> ChildNodeViewModels { get; private set; }

    public NodeViewModel(IUnityContainer container, Node node)
    {
        Node = node;
        ChildNodeViewModels = new ObservableCollection<INodeViewModel>();

        foreach (Node childNode in Node.ChildNodes)
        {
            // Some initialization code
        }
    }
}

Up to now I didn't use the container so we only had the Node argument. Each inherited class had an attribute which we used for model to viewmodel mapping.

[ModelToViewModelMapping(typeof(InheritedNode ))]
public class InheritedViewModel: NodeViewModel
{
    public InheritedViewModel(InheritedNode inheritedNode)
        : base(inheritedNode)
    {
    }
}

I then had an initialization line like this:

ChildNodeViewModels.Add((INodeViewModel)System.Activator.CreateInstance(ModelToViewModelMappingDictionary.GetMappedViewModelType(childNode.GetType()), System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance, null, new object[] { childNode }, null));

My question is twofold.

  • I don't know if my old trick with the attribute is a common solution for the mapping. I suppose not but it keeps things together and manageable in an easy way. I'm not sure the viewmodellocator is a good solution and I'm completely new with it, I haven't tried.
  • How can the initialization be done. The Resolve method uses a type that I can resolve in one way or another (my attribute solution, viewmodellocator, ...) but Unity's ParameterOverride needs a string parameterName. As shown in the code above that fails because the parameterName is not constant, every inheritted class has its own parameterName.

Thanks in advance!


回答1:


Ad 1:

I like your current option because you avoid creating a lot of factories this way.

Ad 2:

You have to provide the parameter name for unity, so you have to manually reflect the constructor and find the name of the parameter you want to override. Then you can resolve your view model through unity and pass in the model. But there's a catch! When resolving with a parameter override, you override any parameters that happen to match the parameter name in the override, anywhere in the hierarchy and no matter what type. In the best case, the types don't match and you get an exception, in the worst case, a wrong dependency is injected, silently. Have fun debugging that...

Recommendation:

Stick with your current way of producing the view models, and inject the dependencies when the objects are constructed. This has drawbacks, too, because you cannot use constructor injection and you need a reference to the container, but I'd prefer those to the rather unpredictable parameter override.

var viewModel = Activator.CreateInstance(...);
_container.BuildUp( viewModel );

with

internal class MyChildViewModel
{
    [Dependency]
    public ISomeService MyDependency { get; set; }
}



回答2:


  1. Your trick is common. It is more common to see:

InheritedViewModel < InheritedNode >

Where also:

NodeViewModel < T >

And of course:

INodeViewModel < T >

  1. Part of the power of Prism is getting the Instance you need from the Container like this:

Container(or how you'll call it).GetInstance(or whatever its called) < INodeViewModel < InheritedNode >>()

You need to register first in the container InheritedViewModel < T > with INodeViewModel < T > for that to work



来源:https://stackoverflow.com/questions/42908224/initialize-hierarchical-tree-viewmodels-with-unity

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!