使用 MEF 时创建子视图模型

发布于 2024-10-20 02:06:25 字数 625 浏览 4 评论 0原文

我采用传统的 MVVM 方法,例如,名为“PatientManagementViewModel”的视图模型由名为“PatientManagementView”的视图使用。一切都是使用 MEF 注入的,所以我自己不创建任何实例。

现在假设“PatientManagementViewModel”有一个属性Patient,它是“PatientViewModel”的ObervableCollection。我现在创建“PatientViewModel”实例并传递所选患者的操作如下:

var patientViewModel = _container.GetExportedValue<IPatientViewModel>();
patientViewModel.Patient = patient;

这有效,但是,我想知道这是否有意义。将患者传递给构造函数会更好,因为没有患者就无法存在“PatientViewModel”:

var patientViewModel = new PatientViewModel(patient);

但是我无法使用依赖项注入。

所以问题是:注入子视图模型是否有意义,或者我应该只注入主视图模型,并实例化所有子视图模型而不注入?

I have a traditional MVVM approach, so for example a view model called 'PatientManagementViewModel' that is used by a view called 'PatientManagementView'. Everything is injected using MEF, so I don't create any instance myself.

Now suppose that 'PatientManagementViewModel' has a property Patients, which is an ObervableCollection of 'PatientViewModel'. What I do now to create an instance of 'PatientViewModel' and pass the selected patient is like:

var patientViewModel = _container.GetExportedValue<IPatientViewModel>();
patientViewModel.Patient = patient;

This works, however, I was wondering if this makes sense. It would be nicer to pass a patient to the constructor because 'PatientViewModel' cannot exist without a Patient:

var patientViewModel = new PatientViewModel(patient);

but then I can't use dependency injection.

So the question is: does it make sense to inject a subviewmodel, or should I only inject the main view model, and instantiate all subviewmodels without injection?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

转瞬即逝 2024-10-27 02:06:25

您可以执行以下操作。您可以使用常用的构造函数创建子视图模型,然后在实例上调用 ComposeParts 来注入所有内容:

var patientViewModel = new PatientViewModel(patient);
_container.ComposeParts(patientViewModel);

但由于多种原因,每次都这样做并不是很好。为了解决这个场景并封装 MEF 的使用,我创建了一个用于创建视图模型的帮助服务。它被称为IViewModelFactory,它的外观如下:

[Export(typeof(IViewModelFactory))]
[PartCreationPolicy(CreationPolicy.Shared)]
internal class ViewModelFactory : IViewModelFactory
{
    [ImportingConstructor]
    public ViewModelFactory(CompositionContainer container) {
        Contract.Requires(container != null);

        Container = container;
    }

    protected CompositionContainer Container { get; private set; }

    public T Create<T>(params object[] args) where T : class {
        T result;

        try {
            bool populateDependencies = false;

            if (args == null || args.Length == 0) {
                // There are no parameters for contructor, so
                // try to create an instance by asking the container.
                result = Container.GetExportedValueOrDefault<T>();

                if (result == null) {
                    // The view model is not exported. Just create an instance using reflection
                    // and then populate all the dependencied using the container.
                    result = Activator.CreateInstance<T>();
                    populateDependencies = true;
                }
            }
            else {
                // There are constructor parameters. Create an instance using those parameters
                // and then populate all the dependencied using the container.
                result = (T)Activator.CreateInstance(typeof(T), args);
                populateDependencies = true;
            }

            // Populate dependencies if needed
            if (populateDependencies) {
                Container.ComposeParts(result);
            }

            // Initialize the object if applicable
            var initializable = result as IInitializable;

            if (initializable != null) {
                initializable.Initialize();
            }
        }
        catch (Exception ex) {

            throw new ViewModelCreationException(
                string.Format(
                    "Unable to create and configure an instance of view model of type {0}. An error occured. See inner exception for details.",
                    typeof (T)), ex);
        }

        return result;
    }
}

使用这个工厂,您可以像这样创建子视图模型:

var patientViewModel = ViewModelFactory.Create<PatientViewModel>(patient);

这里的缺点是,当您使用构造函数参数时,您会失去对参数的类型、数量、顺序等。

You can do the following. You can create your child view model using usual constructor and then call ComposeParts on the instance to inject everything:

var patientViewModel = new PatientViewModel(patient);
_container.ComposeParts(patientViewModel);

But doing this every time is not very good for a variety of reasons. To address this scenario and to encapsulate usage of MEF I created a helper service for creating view models. It is called IViewModelFactory and here is how it looks:

[Export(typeof(IViewModelFactory))]
[PartCreationPolicy(CreationPolicy.Shared)]
internal class ViewModelFactory : IViewModelFactory
{
    [ImportingConstructor]
    public ViewModelFactory(CompositionContainer container) {
        Contract.Requires(container != null);

        Container = container;
    }

    protected CompositionContainer Container { get; private set; }

    public T Create<T>(params object[] args) where T : class {
        T result;

        try {
            bool populateDependencies = false;

            if (args == null || args.Length == 0) {
                // There are no parameters for contructor, so
                // try to create an instance by asking the container.
                result = Container.GetExportedValueOrDefault<T>();

                if (result == null) {
                    // The view model is not exported. Just create an instance using reflection
                    // and then populate all the dependencied using the container.
                    result = Activator.CreateInstance<T>();
                    populateDependencies = true;
                }
            }
            else {
                // There are constructor parameters. Create an instance using those parameters
                // and then populate all the dependencied using the container.
                result = (T)Activator.CreateInstance(typeof(T), args);
                populateDependencies = true;
            }

            // Populate dependencies if needed
            if (populateDependencies) {
                Container.ComposeParts(result);
            }

            // Initialize the object if applicable
            var initializable = result as IInitializable;

            if (initializable != null) {
                initializable.Initialize();
            }
        }
        catch (Exception ex) {

            throw new ViewModelCreationException(
                string.Format(
                    "Unable to create and configure an instance of view model of type {0}. An error occured. See inner exception for details.",
                    typeof (T)), ex);
        }

        return result;
    }
}

Using this factory you can create child view models like this:

var patientViewModel = ViewModelFactory.Create<PatientViewModel>(patient);

The downside here is that, when you use constructor parameters, you loose compile-time check for the parameters' types, count, order etc.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文