【问题标题】:Combining MVVM Light Toolkit and Unity 2.0结合 MVVM Light Toolkit 和 Unity 2.0
【发布时间】:2011-05-29 14:37:11
【问题描述】:

这更像是一个评论而不是一个问题,尽管反馈会很好。我的任务是为我们正在做的一个新项目创建用户界面。我们想使用 WPF,我想学习所有可用的现代 UI 设计技术。由于我对 WPF 相当陌生,因此我一直在研究可用的内容。我想我已经决定使用 MVVM Light Toolkit(主要是因为它的“可混合性”和 EventToCommand 行为!),但我也想合并 IoC。所以,这就是我想出的。我已经修改了 MVVM Light 项目中的默认 ViewModelLocator 类,以使用 UnityContainer 来处理依赖项注入。考虑到 3 个月前我不知道这些术语中的 90% 是什么意思,我认为我走在正确的轨道上。

// Example of MVVM Light Toolkit ViewModelLocator class that implements Microsoft 
// Unity 2.0 Inversion of Control container to resolve ViewModel dependencies.

using Microsoft.Practices.Unity;

namespace MVVMLightUnityExample
{
    public class ViewModelLocator
    {
        public static UnityContainer Container { get; set; }

        #region Constructors
        static ViewModelLocator() 
        {
            if (Container == null)
            {
                Container = new UnityContainer();

                // register all dependencies required by view models
                Container
                    .RegisterType<IDialogService, ModalDialogService>(new ContainerControlledLifetimeManager())
                    .RegisterType<ILoggerService, LogFileService>(new ContainerControlledLifetimeManager())
                    ;
            }
        }

        /// <summary>
        /// Initializes a new instance of the ViewModelLocator class.
        /// </summary>
        public ViewModelLocator()
        {
            ////if (ViewModelBase.IsInDesignModeStatic)
            ////{
            ////    // Create design time view models
            ////}
            ////else
            ////{
            ////    // Create run time view models
            ////}

            CreateMain();
        }

        #endregion

        #region MainViewModel

        private static MainViewModel _main;

        /// <summary>
        /// Gets the Main property.
        /// </summary>
        public static MainViewModel MainStatic
        {
            get
            {
                if (_main == null)
                {
                    CreateMain();
                }
                return _main;
            }
        }

        /// <summary>
        /// Gets the Main property.
        /// </summary>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance",
            "CA1822:MarkMembersAsStatic",
            Justification = "This non-static member is needed for data binding purposes.")]
        public MainViewModel Main
        {
            get
            {
                return MainStatic;
            }
        }

        /// <summary>
        /// Provides a deterministic way to delete the Main property.
        /// </summary>
        public static void ClearMain()
        {
            _main.Cleanup();
            _main = null;
        }

        /// <summary>
        /// Provides a deterministic way to create the Main property.
        /// </summary>
        public static void CreateMain()
        {
            if (_main == null)
            {
                // allow Unity to resolve the view model and hold onto reference
                _main = Container.Resolve<MainViewModel>();
            }
        }

        #endregion

        #region OrderViewModel

        // property to hold the order number (injected into OrderViewModel() constructor when resolved)
    public static string OrderToView { get; set; }

        /// <summary>
        /// Gets the OrderViewModel property.
        /// </summary>
        public static OrderViewModel OrderViewModelStatic
        {
            get 
            {
                // allow Unity to resolve the view model
                // do not keep local reference to the instance resolved because we need a new instance 
                // each time - the corresponding View is a UserControl that can be used multiple times 
                // within a single window/view
                // pass current value of OrderToView parameter to constructor!
                return Container.Resolve<OrderViewModel>(new ParameterOverride("orderNumber", OrderToView));
            }
        }

        /// <summary>
        /// Gets the OrderViewModel property.
        /// </summary>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance",
            "CA1822:MarkMembersAsStatic",
            Justification = "This non-static member is needed for data binding purposes.")]
        public OrderViewModel Order
        {
            get
            {
                return OrderViewModelStatic;
            }
        }
        #endregion

        /// <summary>
        /// Cleans up all the resources.
        /// </summary>
        public static void Cleanup()
        {
            ClearMain();
            Container = null;
        }
    }
}

以及显示依赖注入用法的 MainViewModel 类:

using GalaSoft.MvvmLight;
using Microsoft.Practices.Unity;

namespace MVVMLightUnityExample
{
    public class MainViewModel : ViewModelBase
    {
        private IDialogService _dialogs;
        private ILoggerService _logger;

        /// <summary>
        /// Initializes a new instance of the MainViewModel class. This default constructor calls the 
        /// non-default constructor resolving the interfaces used by this view model.
        /// </summary>
        public MainViewModel() 
            : this(ViewModelLocator.Container.Resolve<IDialogService>(), ViewModelLocator.Container.Resolve<ILoggerService>())
        {
            if (IsInDesignMode)
            {
                // Code runs in Blend --> create design time data.
            }
            else
            {
                // Code runs "for real"
            }
        }

        /// <summary>
        /// Initializes a new instance of the MainViewModel class.
        /// Interfaces are automatically resolved by the IoC container.
        /// </summary>
        /// <param name="dialogs">Interface to dialog service</param>
        /// <param name="logger">Interface to logger service</param>
        public MainViewModel(IDialogService dialogs, ILoggerService logger)
        {
            _dialogs = dialogs;
            _logger = logger;

            if (IsInDesignMode)
            {
                // Code runs in Blend --> create design time data.
                _dialogs.ShowMessage("Running in design-time mode!", "Injection Constructor", DialogButton.OK, DialogImage.Information);
                _logger.WriteLine("Running in design-time mode!");
            }
            else
            {
                // Code runs "for real"
                _dialogs.ShowMessage("Running in run-time mode!", "Injection Constructor", DialogButton.OK, DialogImage.Information);
                _logger.WriteLine("Running in run-time mode!");
            }
        }

        public override void Cleanup()
        {
            // Clean up if needed
            _dialogs = null;
            _logger = null;

            base.Cleanup();
        }
    }
}

还有 OrderViewModel 类:

using GalaSoft.MvvmLight;
using Microsoft.Practices.Unity;

namespace MVVMLightUnityExample
{
    /// <summary>
    /// This class contains properties that a View can data bind to.
    /// <para>
    /// Use the <strong>mvvminpc</strong> snippet to add bindable properties to this ViewModel.
    /// </para>
    /// <para>
    /// You can also use Blend to data bind with the tool's support.
    /// </para>
    /// <para>
    /// See http://www.galasoft.ch/mvvm/getstarted
    /// </para>
    /// </summary>
    public class OrderViewModel : ViewModelBase
    {

        private const string testOrderNumber = "123456";
        private Order _order;

        /// <summary>
        /// Initializes a new instance of the OrderViewModel class.
        /// </summary>
        public OrderViewModel()
            : this(testOrderNumber)
        {

        }

        /// <summary>
        /// Initializes a new instance of the OrderViewModel class.
        /// </summary>
        public OrderViewModel(string orderNumber)
        {
            if (IsInDesignMode)
            {
                // Code runs in Blend --> create design time data.
                _order = new Order(orderNumber, "My Company", "Our Address");
            }
            else
            {
                _order = GetOrder(orderNumber);
            }
        }

        public override void Cleanup()
        {
            // Clean own resources if needed
            _order = null;

            base.Cleanup();
        }
    }
}

以及可用于显示特定订单的订单视图的代码:

public void ShowOrder(string orderNumber)
{
    // pass the order number to show to ViewModelLocator to be injected
    //into the constructor of the OrderViewModel instance
    ViewModelLocator.OrderToShow = orderNumber;

    View.OrderView orderView = new View.OrderView();
}

这些示例已被精简,仅展示 IoC 的想法。经过大量试验和错误,在 Internet 上搜索示例,并发现缺少 Unity 2.0 文档(在扩展示例代码中)来提出此解决方案。如果您认为可以改进,请告诉我。

【问题讨论】:

  • 我很想知道您认为 Unity 文档中存在哪些漏洞。您还需要什么不存在的东西?
  • Unity 文档非常好,我只是很难找到任何适用于 2.0 的示例代码 sn-ps,尤其是在使用扩展时。有很多 1.x 的示例代码,但很多都过时了(我不断收到消息说不要使用该语法做事,因为有一种新语法可以使用扩展)。
  • 自您第一次发布此内容以来已经快一年了,acordner。我开始与你当时的想法作斗争。我想知道你知道的情况,就 MVVM Light/Unity 而言。

标签: wpf unity-container ioc-container mvvm-light


【解决方案1】:

首先,您应该避免服务定位器反模式。

第二,每次要获取OrderView都要设置一个静态变量吗?这是一个非常丑陋的设计。

【讨论】:

  • 正如我所说,我对这些东西真的很陌生,只是想摸索一下。我不仅对批评持开放态度,而且对如何改进它的建议持开放态度。我还没有使用 MVVM 模式组装一个完整的工作应用程序,我想在我走得太远之前找到最好的解决方案。我认为让其他更有经验的开发人员将其分开是寻找改进机会的好方法。我将研究“服务定位器反模式”(因为我现在不知道这意味着什么):)
  • 我同意在获取 OrderView 之前设置静态变量不是一个很好的解决方案,但在我弄清楚所有参数覆盖和 DI 技术之前,这就是我想出的。
  • 更好的解决方案是可以注入的抽象工厂模式。
猜你喜欢
  • 2011-06-19
  • 2011-06-03
  • 1970-01-01
  • 2011-02-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多