Простое объяснение того, как очистить неуправляемые ресурсы в WPF

#c# #wpf

#c# #wpf

Вопрос:

У меня есть приложение, использующее MVVM Light, которое запускает другое приложение, которое мне нужно остановить, когда пользователь закрывает основное приложение.

Я создал метод Dispose (), который освобождает ресурсы, но чего я не понимаю, так это того, где я вызываю Dispose() .

Например, я заметил, что в определении класса приложения есть: public event ExitEventHandler Exit;

Могу ли я добавить что-то в свое приложение (см. Код ниже), которое запускается при завершении работы приложения?

(Я знаю, что есть много других вопросов по этой теме, но все они, похоже, предполагают больше знаний c #)

App.xaml.cs…

 namespace Module.Config
{
    public partial class App : Application
    {
        static App()
        {
            DispatcherHelper.Initialize();
        }    
    }
}
  

MainWindow.xaml…

 <Window x:Class="Module.Config.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:ignore="http://www.ignore.com"
        mc:Ignorable="d ignore"
        Height="640" MinHeight="600"
        Width="800" MinWidth="800"
        Title="Config"
        DataContext="{Binding Main, Source={StaticResource Locator}}"
        Closing="Window_Closing"
        >

    <Window.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="../Skins/MainSkin.xaml" />
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Window.Resources>

    <Grid x:Name="LayoutRoot" Margin="3">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="200"/>
            <ColumnDefinition Width="*"/>
        </Grid.ColumnDefinitions>
        <ContentControl Content="{Binding Side}" Grid.Column="0" />
        <ContentControl Content="{Binding SelectedModule}" Grid.Column="1" />
    </Grid>
</Window>
  

MainWindow.xaml.cs…

 namespace Module.Config
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            Closing  = (s, e) => ViewModelLocator.Cleanup();

            Messenger.Default.Register<DialogMessage>(
                this,
                msg =>
                {
                    var result = MessageBox.Show(
                        msg.Content,
                        msg.Caption,
                        msg.Button
                        );

                    msg.ProcessCallback(result);
                });

       . . . . . 


        private void Window_Closing(object sender, CancelEventArgs e)
        {
            /*
            I want to call Dispose() within AvigilonViewModel.cs 
            */
        }


    }
}
  

AvigilonView.xaml…

 <UserControl x:Class="Module.Config.Views.Modules.AvigilonView"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:sys="clr-namespace:System;assembly=mscorlib"
        xmlns:local="clr-namespace:Module.Config"
        xmlns:ignore="http://www.ignore.com"
        mc:Ignorable="d ignore"
        DataContext="{Binding Avigilon, Source={StaticResource Locator}}">

    <Grid>
    .....
  

AvigilonView.xaml.cs…

     namespace Module.Config.Views.Modules
    {
        public partial class AvigilonView : UserControl
        {
            public AvigilonView()
            {
                InitializeComponent();
            }
        }
    }
  

MainViewModel.cs……

 namespace Module.Config.ViewModel
{
    public class MainViewModel : ViewModelBase
    {
        private ViewModelBase m_selectedModule;

        public ViewModelBase Side
        {
            get { return ServiceLocator.Current.GetInstance<SideViewModel>(); }
        }

        public ViewModelBase SelectedModule
        {
            get { return m_selectedModule; }
            set
            {
                m_selectedModule = value;
                RaisePropertyChanged("SelectedModule");
            }
        }

        public MainViewModel()
        {
            Messenger.Default.Register<PropertyChangedMessage<object>>(this, (r) =>
            {
                if (r.PropertyName == "SelectedNode")
                {
                    if (r.NewValue is RedSensor)
                    {
                        SelectedModule = ServiceLocator.Current.GetInstance<SensorViewModel>();
                        (SelectedModule as SensorViewModel).Sensor = r.NewValue as RedSensor;
                    }
                    else
                    {
                        SelectedModule = r.NewValue as ViewModelBase;
                    }
                }
            });
        }

    }
}
  

AvigilonViewModel.cs….

 namespace Module.Config.ViewModel.Modules
{
    public class AvigilonViewModel : ViewModelBase
    {
    ....

        public Dispose(){
            /* code to get rid of unmanaged resources */
        }
    }
}
  

ViewModelLocator.cs…

 namespace Module.Config.ViewModel
{
    public class ViewModelLocator
    {
        static ViewModelLocator()
        {
            ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);

            if (ViewModelBase.IsInDesignModeStatic)
            {
                //SimpleIoc.Default.Register<IDataService, Design.DesignDataService>();
            }
            else
            {
                //SimpleIoc.Default.Register<IDataService, DataService>();
            }

            SimpleIoc.Default.Register<AppState>();
            SimpleIoc.Default.Register<MainViewModel>();
            SimpleIoc.Default.Register<SideViewModel>();
            SimpleIoc.Default.Register<AvigilonViewModel>();
        }


        /// <summary>
        /// Gets the Main property.
        /// </summary>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance",
            "CA1822:MarkMembersAsStatic",
            Justification = "This non-static member is needed for data binding purposes.")]
        public SideViewModel Side
        {
            get
            {
                return ServiceLocator.Current.GetInstance<SideViewModel>();
            }
        }


        /// <summary>
        /// Gets the Main property.
        /// </summary>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance",
            "CA1822:MarkMembersAsStatic",
            Justification = "This non-static member is needed for data binding purposes.")]
        public AvigilonViewModel Avigilon
        {
            get
            {
                return ServiceLocator.Current.GetInstance<AvigilonViewModel>();
            }
        }

    ....
  

Я также заметил строку Closing = (s, e) => ViewModelLocator.Cleanup(); в приведенном выше. Я попытался добавить метод с именем `Cleanup() в AvigilonView.xaml.cs и AvigilonViewModel.cs, но, похоже, он не вызывается.

Ответ №1:

Вы можете обработать Closing событие вашего MainWindow и выполнить обработку там.

XAML:

 <Window Closing="Window_Closing">
  

Код, лежащий в основе:

 private void Window_Closing(object sender, CancelEventArgs e)
{
   // Clean up your resources here.
}
  

Комментарии:

1. Большое спасибо. Однако я все еще могу понять, как ссылаться на мои ViewModels в методе Windows_Closing (для вызова Dispose), например. если у меня есть файл XAML, который запускается: <UserControl x:Class="Module.Config.Views.Modules.AvigilonView".... Как мне определить имя объекта для этого класса?

2. Если у вас есть экземпляр View, вы можете получить доступ к его ViewModel, обратившись к DataContext свойству View. eg — avigilonView.DataContext as AvigilonViewModel .

3. Спасибо, но что вы имеете в виду под instance of View ? Вы имеете в виду, что я должен создать экземпляр View? Я попробовал это, но получил: The type or namespace name 'View' could not be found (are you missing a using directive or an assembly reference?) Для avigilonView написано The name 'avigilonView' does not exist in the current context

4. Я не уверен, что вы задумали. Опубликуйте какой-нибудь релевантный код, о каком представлении вы говорите? Вы должны показать некоторый код. Прямо сейчас очень сложно комментировать, не видя вашего кода. (Вопрос касается только того, куда поместить очищающий код).

5.ок, наконец, разобрался. В Window_Closing() Я добавил var theAvililonViewModel = ServiceLocator.Current.GetInstance<AvigilonViewModel>(); theAvililonViewModel.Dispose();