MVVMLight简单IOC - 动态注册和注销数据服务实现

9
我有一个使用MVVM Light Toolkit的WPF应用程序,其场景如下。该应用有两种数据连接模式,一种是WCF服务,另一种是直接数据库。该应用应通过上述任一模式连接到数据库。连接模式选择位于登录窗口中,最终用户可以选择其中一种连接模式(WCF服务或直接数据库),并基于此选择在组合框中加载连接配置列表(详见附图)。连接配置位于本地XML配置文件中。我还有一个默认连接配置,如果选择了任何连接配置,则应分配该默认连接配置。
在视图模型定位器中,我注册默认服务如下:
public ViewModelLocator()
        {
            ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);

            if (ViewModelBase.IsInDesignModeStatic)
            {
                // Create design time view services and models
                if (!SimpleIoc.Default.IsRegistered<IDataService>())
                    SimpleIoc.Default.Register<IDataService, MockDataClient>();
            }
            else
            {
                // Create run time view services and models
                if (!SimpleIoc.Default.IsRegistered<IDataService>())
                {
                    switch (DefaultConnectionConfiguration.ConnectionMode)
                    {
                        case DataConnectionMode.WcfService:
                            var wcfServiceConfiguration = (WcfServiceConfiguration)CurrentConnectionConfiguration;
                            SimpleIoc.Default.Register<IDataService>(
                                () =>
                                wcfServiceConfiguration != null
                                    ? new DataServiceClient("WSHttpBinding_IDataService",
                                                                 wcfServiceConfiguration.EndpointUrl)
                                    : null);
                            break;

                        case DataConnectionMode.Database:
                            SimpleIoc.Default.Register<IDataService, DbClient>();
                            break;
                    }
                }

            }
        SimpleIoc.Default.Register<LoginViewModel>();
        SimpleIoc.Default.Register<ManageConfigurationsViewModel>();

DbClient和DataServiceClient均实现了IDataservice接口。

如果配置文件中已经指定了默认连接,则在视图模型定位器在应用程序启动时注册视图模型时,上述代码可以正常工作。即IDataservice已使用默认连接配置进行注册。

现在真正的问题是当用户选择一个连接配置时,该连接配置将成为默认配置,我希望MVVM Light取消注册先前的数据服务并注册新选择的数据服务,并使用它连接到数据。

我尝试在“登录”按钮单击事件中使用以下代码,但它失败了:(

void SignInButtonClick()
{
        if(SimpleIoc.Default.IsRegistered<IDataService>())
                                    SimpleIoc.Default.Unregister<IDataService>();

    switch (DefaultConnectionConfiguration.ConnectionMode)
                            {
                                case DataConnectionMode.WcfService:
                                    var wcfServiceConfiguration = (WcfServiceConfiguration)CurrentConnectionConfiguration;
                                    SimpleIoc.Default.Register<IDataService>(
                                        () =>
                                        wcfServiceConfiguration != null
                                            ? new DataServiceClient("WSHttpBinding_IDataService",
                                                                         wcfServiceConfiguration.EndpointUrl)
                                            : null);
                                    break;

                                case DataConnectionMode.Database:
                                    SimpleIoc.Default.Register<IDataService, DbClient>();
                                    break;
                            }
//perform authentication process
}

更新的代码

public class ViewModelLocator
    {
        public ViewModelLocator()
        {
            ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);

            if (ViewModelBase.IsInDesignModeStatic)
            {
                // Create design time view services and models
                if (!SimpleIoc.Default.IsRegistered<IDataService>())
                    SimpleIoc.Default.Register<IDataService, MockDataClient>();
            }
            SimpleIoc.Default.Register<LoginViewModel>();
        }

        public LoginViewModel LoginViewModel
        {
            get
            {
                return ServiceLocator.Current.GetInstance<LoginViewModel>();
            }
        }

        public static void Cleanup()
        {
            // TODO Clear the ViewModels
            ServiceLocator.Current.GetInstance<LoginViewModel>().Cleanup();
        }
    }



public class LoginViewModel : ViewModelBase
    {
        ICometDataService service;

    #region Constructor
        public LoginViewModel()
        {

        }
        public LoginViewModel(IDataService dataService)
            : base(dataService)
        {
            service = dataService;
        }

        #endregion
}

在您上面的代码中,“ICometDataService”和“IDataService”有什么区别? - tcarvin
@tcarvin - 实际上它是IDataService。 - Dennis Jose
1个回答

1

我会直接删除:

if (!SimpleIoc.Default.IsRegistered<IDataService>())
                {
                    switch (DefaultConnectionConfiguration.ConnectionMode)
                    {
                        case DataConnectionMode.WcfService:
                            var wcfServiceConfiguration = (WcfServiceConfiguration)CurrentConnectionConfiguration;
                            SimpleIoc.Default.Register<IDataService>(
                                () =>
                                wcfServiceConfiguration != null
                                    ? new DataServiceClient("WSHttpBinding_IDataService",
                                                                 wcfServiceConfiguration.EndpointUrl)
                                    : null);
                            break;

                        case DataConnectionMode.Database:
                            SimpleIoc.Default.Register<IDataService, DbClient>();
                            break;
                    }
                }

从您的ViewModelLocator中获取并将SignInButtonClick中的代码更改为:
void SignInButtonClick()
{

    switch (DefaultConnectionConfiguration.ConnectionMode)
                            {
                                case DataConnectionMode.WcfService:
                                    var wcfServiceConfiguration = (WcfServiceConfiguration)CurrentConnectionConfiguration;
                                    SimpleIoc.Default.Register<IDataService>(
                                        () =>
                                        wcfServiceConfiguration != null
                                            ? new DataServiceClient("WSHttpBinding_IDataService",
                                                                         wcfServiceConfiguration.EndpointUrl)
                                            : null);
                                    break;

                                case DataConnectionMode.Database:
                                    SimpleIoc.Default.Register<IDataService, DbClient>();
                                    break;
                            }
//perform authentication process
}

通过这样做,您只需要注册一次服务,就可以确保您正在注册正确的接口。

我试过了。但是在ViewModelLocator中实例化Login ViewModel属性时会抛出错误。异常详细信息如下 - “目标调用的异常已经被抛出”。内部异常 - 在缓存中找不到类型:DataService.IDataService。 - Dennis Jose
你能发布一下你的登录视图模型代码吗?我怀疑问题可能是你正在尝试注销一个正在使用的类。 - Faster Solutions
我的LoginViewModel没有默认构造函数。所以我添加了一个。然后上述异常就消失了。当前LoginViewModel有两个构造函数:默认的和带参数的。在注册LoginViewModel(SimpleIoc.Default.Register <LoginViewModel>();)时,我遇到以下异常:“无法注册:在LoginViewModel中发现多个构造函数,但没有标记为PreferredConstructor。”。我已经在问题本身中添加了更新的代码块,请看一下。 - Dennis Jose
如果您有多个构造函数,您需要将PreferredConstructor属性添加到您想要MVVM Light在SimpleIoc中解析视图模型时使用的构造函数。 - Faster Solutions
谢谢更快的速度。它确实很有帮助。我会实施并尽快回复您... :) - Dennis Jose

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接