结合MVVM Light Toolkit和Unity 2.0

时间:2010-12-22 19:19:08

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

这更像是一个评论而不是一个问题,尽管反馈会很好。我的任务是为我们正在做的新项目创建用户界面。我们想使用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的想法。它需要大量的试验和错误,在互联网上搜索示例,并发现Unity 2.0文档缺乏(在扩展的示例代码中)来提出这个解决方案。如果您认为可以改进,请告诉我。

1 个答案:

答案 0 :(得分:1)

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

其次,每次要获取OrderView时都必须设置一个静态变量?这是一个非常丑陋的设计。