C# MVVM灯光应用程序-如何正确清理ViewModels

C# MVVM灯光应用程序-如何正确清理ViewModels,c#,wpf,entity-framework,mvvm,viewmodellocator,C#,Wpf,Entity Framework,Mvvm,Viewmodellocator,我正在WPF中开发一个cookbook窗口应用程序,它由一个窗口和几个用户控件组成,这些控件使用MVVM Light中的消息用relayCommand相互替换 应用程序使用从entityFramework生成的DB。除第一次执行文件外,所有文件执行后出现的问题是程序显示了许多警告和错误,例如: Warning 1 Could not copy "...\cookbook\Cookbook.Services\Database1.mdf" to "bin\Debug\Database1.mdf"

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

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

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>();
}
公共ViewModelLocator() { ServiceLocator.SetLocatorProvider(()=>SimpleIoc.Default); SimpleIoc.Default.Register(); SimpleIoc.Default.Register(); SimpleIoc.Default.Register(); SimpleIoc.Default.Register(); SimpleIoc.Default.Register(); SimpleIoc.Default.Register(); SimpleIoc.Default.Register(); SimpleIoc.Default.Register(); } 此外,我用来切换用户控件的消息正在创建ViewModels的新实例,例如:

    BackToMainCommand = new RelayCommand(() =>
    {
        Messenger.Default.Send<ViewModelBase>(new MainViewModel());
    },
    () => true);
BackToMainCommand=newrelaycommand(()=>
{
Send(新的MainViewModel());
},
()=>正确);
我已经玩弄了ViewModels,使它们成为单副本,以确保系统中只有单副本,但SimpleIoc需要公共构造函数进行注册。而且我也不知道这是否对我的问题有帮助。我没有告诉你的是ViewModelLocator只在xaml中使用,所以我甚至没有它的实例来清理这些东西。(我可能用错了,但我不知道该怎么用)


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

如评论中所述,您得到的是

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

进程无法访问文件“…\cookbook\cookbook.Services\Database1.mdf”,因为另一个进程正在使用该文件。烹饪书,服务

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

  • 尚未完成,或
  • 未关闭与数据库文件的所有连接
  • 因此,当您再次构建它时,它的文件句柄仍处于打开状态,您无法复制打开的文件

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

    Messenger.Default.Send<ViewModelBase>(new MainViewModel());
    
    因此,它不会创建
    MainViewModel
    的新实例,而是从IoC容器中返回一个实例

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

    SimpleIoc.Default.Register(()=>newmydbcontext(GetMyConnectionString());
    

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

    做出反应来做到这一点。您的问题可能是由于您使用DbContext的方式造成的。你没有在你的问题中提出你是如何处理的,所以我将试着猜测你那边发生了什么。您应该始终确保在使用DbContext之后立即处理它。它不应在整个应用程序使用期间保存。我看不出您正在向IoC注册它,所以我假设您只是在ViewModels中的某个地方实例化了它。在这种情况下,您应该始终将DbContext对象放在using()中,以确保它们已被释放。如果您愿意,当您以普通方式关闭应用程序时,您肯定不应该打开任何与数据库的连接


    另一种情况是连接到VS中调试应用程序。默认情况下,VS宿主进程会完成调试,因此当您点击“停止调试”按钮时,不会释放已打开连接的DBContext,也不会终止VS宿主进程。为了避免这种情况,我建议您尝试禁用VS托管进程。您可以在项目属性->调试->中设置它,然后取消选中启用VisualStudio宿主进程。但是,这可能会减少调试应用程序时应用程序开始运行的时间。

    为正在运行/调试的应用程序创建的进程(1)尚未完成,或(2)未关闭与数据库文件的所有连接。因此,如果您再次构建它,它的文件句柄仍处于打开状态,您无法复制打开的文件。请注意,调试时,特别是使用“停止调试”按钮停止调试会话时,调试进程不会直接终止。退出VisualStudio并重新启动通常可以解决这个问题。好的,这些连接在一些使用DB服务的ViewModels中。我认为那些视图模型超出了定位器或消息的范围(如果我没有错的话)。我知道重新启动VisualStudio可以解决这个问题,但我需要修复它,这样即使我使用退出按钮或窗口中的十字退出应用程序,我也可以让应用程序正常工作。
    Messenger.Default.Send<ViewModelBase>(ServiceLocator.Current.GetInstance<MainViewModel>());
    
    SimpleIoc.Default.Register<IMyDbContext>(() => new MyDbContext(GetMyConnectionString()));