4

我正在开发 WPF 中的食谱窗口应用程序,它由一个窗口和几个用户控件组成,这些用户控件使用来自 MVVM Light 的消息用 relayCommands 相互替换。

该应用程序使用从 entityFramework 生成的数据库。除了第一次执行文件之外,出现的问题是程序显示了许多警告和错误,例如:

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

在 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>();
}

我用来切换 userControls 的消息也在创建 ViewModels 的新实例,例如:

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

我玩弄了 ViewModel 以使它们成为单例,以确保系统中只有单个副本,但 SimpleIoc 需要公共构造函数进行注册。而且我不知道这是否会帮助我解决问题。另外我没有告诉你的是 ViewModelLocator 仅在 xaml 中使用,所以我什至没有它的实例来清理这些东西。(我可能用错了,但我不知道应该怎么用)

问题是我不知道如何以及在哪里清理所有 ViewModel,因为它们是在我提到的许多地方创建的,其中一些可能保存 *.mdf 文件。

4

2 回答 2

2

如评论中所述,您将获得

警告 1 无法将“...\cookbook\Cookbook.Services\Database1.mdf”复制到“bin\Debug\Database1.mdf”。在 1000 毫秒内开始重试 1。

该进程无法访问文件“...\cookbook\Cookbook.Services\Database1.mdf”,因为它正被另一个进程使用。食谱.服务

在构建中来自编译器的警告(以及在充分重试错误之后)消息,因为为您正在运行/调试的应用程序创建的进程:

  1. 尚未完成,或
  2. 未关闭与数据库文件的所有连接。

所以当你再次构建它时,它的文件句柄仍然是打开的,你不能复制打开的文件。

很难从您在问题中发布的代码中确定造成这种情况的直接原因是什么,但是这一行:

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

显然是有问题的,因为它返回一个新实例,而不是容器中的单例生命周期实例。SimpleIoC虽然从适当的 DI 角度来看仍然很难看,但您可以将其更改为:

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

所以它不会创建你的新实例MainViewModel,而是从 IoC 容器返回一个。

此外,您可能希望确保您的数据库上下文已在您的容器中注册,并注入到需要它的视图模型中。说明这一点(假设您的数据库上下文/服务类被调用MyDbContext、实现IMyDbContext并将连接字符串作为其构造函数参数):

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

现在,您还必须确保在应用程序退出时执行适当的清理,以便在实例以及应用程序中需要处理的任何其他潜在资源Dispose上调用。IMyDbContext如果这还没有完成,通过 MVVM Light,你可以通过对你的Application.Exit事件Application做出反应来做到这一点:

于 2015-04-18T09:29:00.133 回答
0

Your problem is probably caused by the way you use your 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. 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. In such case you should always have your DbContext objects within using() to assure they are disposed. 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. 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. To avoid such situations I would recommend you to try to disable VS hosting process. You can set it in project properties -> Debug -> and uncheck Enable the Visual Studio hosting process. However this may lower down a bit time in which your application starts to run when you debug it.

于 2015-04-18T09:56:44.100 回答