简体   繁体   English

MVVM轻量级应用程序 - 如何正确清理ViewModels

[英]MVVM light application - how to properly clean ViewModels

I am working on a cookbook window application in WPF which consist of one window and several userControls that are replacing each other with relayCommands using messages from MVVM Light. 我正在使用WPF中的cookbook窗口应用程序,它包含一个窗口和几个userControls,它们使用来自MVVM Light的消息与relayCommands相互替换。

The application works with a DB that is generated from the entityFramework. 该应用程序使用从entityFramework生成的数据库。 The problem that occurs after all but the first execution of the file is that the program shows many warings and errors such as this one: 除了第一次执行文件之外发生的问题是程序显示许多警告和错误,例如:

Warning 1   Could not copy "...\cookbook\Cookbook.Services\Database1.mdf" to "bin\Debug\Database1.mdf". Beginning retry 1 in 1000ms. The process cannot access the file '...\cookbook\Cookbook.Services\Database1.mdf' because it is being used by another process. Cookbook.Services

In the ViewModelLocator I have this: 在ViewModelLocator中我有这个:

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

            SimpleIoc.Default.Register<MainWindowViewModel>();
            SimpleIoc.Default.Register<MainViewModel>();
            SimpleIoc.Default.Register<FoodTypeViewModel>();
            SimpleIoc.Default.Register<ShoppingCartViewModel>();
            SimpleIoc.Default.Register<MenuViewModel>();
            SimpleIoc.Default.Register<MenuListViewModel>();
            SimpleIoc.Default.Register<MenuCalendarViewModel>();
            SimpleIoc.Default.Register<ChooseFoodWindowViewModel>();
}

And also messages I am using to switch the userControls are creating new instances of ViewModels, such as: 而且我用来切换userControls的消息正在创建ViewModel的新实例,例如:

    BackToMainCommand = new RelayCommand(() =>
    {
        Messenger.Default.Send<ViewModelBase>(new MainViewModel());
    },
    () => true);

I have toyed with the ViewModels to make them singleton to make sure there are only single copies in the system, but SimpleIoc needs public constructors for registering. 我已经玩弄了ViewModels,使它们成为单例,以确保系统中只有单个副本,但SimpleIoc需要公共构造函数进行注册。 And also I don't know if that would even help my problem. 而且我也不知道这是否会对我的问题有所帮助。 Also what I didn't tell you is that the ViewModelLocator is used only in xaml so I don't even have its instance to clean the stuff. 另外我没有告诉你的是ViewModelLocator只在xaml中使用,所以我甚至没有它的实例来清理这些东西。 (I am probably using it wrong but I don't know how it should be used) (我可能使用它错了,但我不知道应该如何使用它)

The problem is that I don't know how and where to clean all the ViewModels since they are beying created on many places I've mentioned and some of them are probably holding the *.mdf file. 问题是我不知道如何以及在何处清理所有ViewModel,因为它们在我提到的许多地方都被创建了,其中一些可能持有* .mdf文件。

As mentioned in the comments, you are getting the 正如评论中所提到的,你得到了

Warning 1 Could not copy "...\\cookbook\\Cookbook.Services\\Database1.mdf" to "bin\\Debug\\Database1.mdf". 警告1无法将“... \\ cookbook \\ Cookbook.Services \\ Database1.mdf”复制到“bin \\ Debug \\ Database1.mdf”。 Beginning retry 1 in 1000ms. 开始在1000毫秒内重试1次。

The process cannot access the file '...\\cookbook\\Cookbook.Services\\Database1.mdf' because it is being used by another process. 该进程无法访问文件'... \\ cookbook \\ Cookbook.Services \\ Database1.mdf',因为它正由另一个进程使用。 Cookbook.Services Cookbook.Services

warning (and after sufficient retries error) message from the compiler in a build because, the process created for application that you were running/debugging: 警告(以及在充分重试错误之后)来自构建编译器的消息,因为为正在运行/调试的应用程序创建了进程:

  1. has not yet completed, or 尚未完成,或
  2. not closed all connections to the database file. 未关闭与数据库文件的所有连接。

So when you build it again, its file handle is still open and you cannot copy over the open file. 因此,当您再次构建它时,其文件句柄仍然打开,您无法复制打开的文件。

It is difficult to establish from the code you have posted in your question what the direct cause of this is, but this line: 很难根据您在问题中发布的代码确定这是直接原因,但这一行:

Messenger.Default.Send<ViewModelBase>(new MainViewModel());

clearly is problematic, because it returns a new instance, instead of the singleton lifecycle instance from the SimpleIoC container. 显然是有问题的,因为它返回一个新实例,而不是SimpleIoC容器中的单例生命周期实例。 Although still ugly from a proper DI perspective, you could change it to: 虽然从正确的DI角度来看仍然很难看,但您可以将其更改为:

Messenger.Default.Send<ViewModelBase>(ServiceLocator.Current.GetInstance<MainViewModel>());

So it will not create a new instance of your MainViewModel , but return the one from the IoC container. 因此,它不会创建MainViewModel的新实例,而是从IoC容器中返回一个实例。

Furthermore, you may want to make sure that your database context is registered in your container, and injected into the view models that need it. 此外,您可能希望确保在容器中注册了数据库上下文,并将其注入到需要它的视图模型中。 Illustrating this (assuming your database context/service class is called MyDbContext , implements IMyDbContext , and takes a connection string as its constructor argument): 说明这一点(假设您的数据库上下文/服务类名为MyDbContext ,实现IMyDbContext ,并将连接字符串作为其构造函数参数):

SimpleIoc.Default.Register<IMyDbContext>(() => new MyDbContext(GetMyConnectionString()));

Now, you must also ensure that on application exit, proper cleanup is performed so that Dispose is called on the IMyDbContext instance, and any other potential resources in your application that require disposal. 现在,您还必须确保在应用程序退出时执行适当的清理,以便在IMyDbContext实例上调用Dispose ,以及应用程序中需要处理的任何其他潜在资源。 If this is not already done, through MVVM Light, you can do that by reacting to the Application.Exit Event on your Application : 如果这不是已经完成,通过MVVM光,你可以做到这一点的反应,在Application.Exit事件上的Application

Your problem is probably caused by the way you use your DbContext. 您的问题可能是由您使用DbContext的方式引起的。 You did not present in your question how you handle so I will try to guess what happens on your side. 你没有在你的问题中提出你的处理方式,所以我会试着猜测你身边会发生什么。 You should always make sure that after using DbContext you immediately dispose it. 您应该始终确保在使用DbContext后立即处置它。 It should not be kept for the whole application living time. 它不应该保留整个应用程序的生存时间。 I do not see that you are registering it with your IoC so I assume you just instantiates it somewhere within your ViewModels. 我没有看到你在IoC中注册它,所以我假设你只是在ViewModels中的某个地方实例化它。 In such case you should always have your DbContext objects within using() to assure they are disposed. 在这种情况下,您应始终在using()中使用DbContext对象以确保它们被处置。 If you will fullfil that you certainly should not have any connection open to your db when you close your application in ordinary way. 如果您满意的话,当您以普通方式关闭应用程序时,您当然不应该对数据库打开任何连接。

The other case is connected to debugging your application in VS. 另一种情况与在VS中调试应用程序有关。 It is done by default with VS hosting process, so when you hit "stop debugging" button DbContexts with opened connections are not disposed and VS hosting process is not killed. 它默认使用VS主机进程完成,所以当你点击“停止调试”按钮时,没有处理打开连接的DbContexts并且VS主机进程没有被杀死。 To avoid such situations I would recommend you to try to disable VS hosting process. 为避免这种情况,我建议您尝试禁用VS主机进程。 You can set it in project properties -> Debug -> and uncheck Enable the Visual Studio hosting process. 您可以在项目属性中设置它 - >调试 - >并取消选中启用Visual Studio主机进程。 However this may lower down a bit time in which your application starts to run when you debug it. 但是,这可能会降低应用程序在调试时开始运行的时间。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM