Как использовать одноразовые модели просмотра в WPF?

Как обеспечить, чтобы модели представления были правильно удалены, если они ссылаются на неуправляемые ресурсы или имеют обработчики событий, такие как обработка, прошедшая по таймеру диспетчера. В первом случае финалист - это вариант, хотя и не идеальный, но во втором он никогда не будет вызван. Как мы можем сказать, что больше нет представления, прикрепленного к модели представления.

Ответ 1

Одно возможное, хотя и не идеальное решение:

Внедрить IDisposable в Model View, затем использовать этот метод расширения в конструкторе представления.

    public static void HandleDisposableViewModel(this FrameworkElement Element)
    {
        Action Dispose = () =>
            {
                var DataContext = Element.DataContext as IDisposable;
                if (DataContext != null)
                {
                    DataContext.Dispose();
                }
            };
        Element.Unloaded += (s, ea) => Dispose();
        Element.Dispatcher.ShutdownStarted += (s, ea) => Dispose();
    }

Ответ 2

Я выполнил это, выполнив следующие действия:

  • Удаление свойства StartupUri из App.xaml.
  • Определение класса App следующим образом:

    public partial class App : Application
    {
        public App()
        {
            IDisposable disposableViewModel = null;
    
            //Create and show window while storing datacontext
            this.Startup += (sender, args) =>
            {
                MainWindow = new MainWindow();
                disposableViewModel = MainWindow.DataContext as IDisposable;
    
                MainWindow.Show();
            };
    
            //Dispose on unhandled exception
            this.DispatcherUnhandledException += (sender, args) => 
            { 
                if (disposableViewModel != null) disposableViewModel.Dispose(); 
            };
    
            //Dispose on exit
            this.Exit += (sender, args) =>
            { 
                if (disposableViewModel != null) disposableViewModel.Dispose(); 
            };
        }
    }