Correct management of several windows and closing them in MVVM

Elad Yehuda

Member
Joined
Jul 3, 2023
Messages
10
Programming Experience
3-5
Hello I am developing a WPF app with Core with Toolkit's MVVM,
The advantages of using their MVVM is the ease with which variables can be wrapped with special attributes ObservableProperty and RelayCommand
for events related to the command and more (besides the advantages that MVVM brings with it).
The application generally has several windows, a main window and 2 additional windows. The main window can access the two secondary windows, and
the two actual secondary windows can only access the main window, but before closing them (whether I return to the main window or whether I actually
close them with the X button on the window bar) I am supposed to perform an action such as writing to a certain file. My problem is this, I have the following code in which I implement the principle and management of IoC towards all the ViewModels present in the application, first thing I don't know if the way I implemented it is the right way, secondly it means that I don't know how to actually "take"
the closing event of every window that closes,
Needless to say, I checked how the event can actually be received with command, but this means that I am forced to write a behavior as a separate class, and what is wrong to do is to use a toolkit

The full code (only two actual windows do not load the code)
C#:
 //App.cs
public partial class App : Application
{
    private IServiceProvider _serviceProvider;

    protected override void OnStartup(StartupEventArgs e)
    {
        var host = Host.CreateDefaultBuilder().ConfigureServices((context, services) =>
        {
                    services.AddSingleton<INavigationService, NavigationService>();
                    services.AddTransient<MainViewModel>();
                    services.AddTransient<MainWindow>();
                    services.AddTransient<ViewModelWindow2>();
                    services.AddTransient<Window2>();
         }).Build();
        _serviceProvider = host.Services;
        var navigationService = _serviceProvider.GetRequiredService<INavigationService>();
        navigationService.OpenWindow<MainViewModel>();
        base.OnStartup(e);
       }
    }
C#:
 //INavigationService.cs
// interface to navigation to viewmodels and windows
public interface INavigationService
{
     //A generic function that should open a window according to the ViewModel it belongs to
    void OpenWindow<TViewModel>() where TViewModel : class;
}

public class NavigationService : INavigationService
{
        private readonly IServiceProvider _serviceProvider;

        public NavigationService(IServiceProvider serviceProvider)
        {
            _serviceProvider = serviceProvider;
        }

        public void OpenWindow<TViewModel>() where TViewModel : class
        {

            Window window = new Window();
            if (typeof(TViewModel) == typeof(MainViewModel))
            {
                window = _serviceProvider.GetRequiredService<MainWindow>();
            }
            else if (typeof(TViewModel) == typeof(ViewModelWindow2))
            {
                window = _serviceProvider.GetRequiredService<Window2>();
            }

            window.DataContext = _serviceProvider.GetRequiredService<TViewModel>();
            // or use with ShowDialog to
            window.Show();
        }
}
C#:
 //ViewModels
public class ViewModelBase : ObservableObject
{
     protected readonly INavigationService _navigationService;
     public ViewModelBase(INavigationService navigationService)
     {
         _navigationService = navigationService;
     }
}
public partial class MainViewModel: ViewModelBase
{
        public MainViewModel(INavigationService navigationService) : base(navigationService)
        {
        }

        [ObservableProperty]
        private int x;

        [RelayCommand]
        private void OpenWindow2()
        {
            X++;
           _navigationService.OpenWindow<ViewModelWindow2>();
        }
}
public partial class ViewModelWindow2: ViewModelBase
{
        public ViewModelWindow2(INavigationService navigationService) : base(navigationService)
        {
        }

        [ObservableProperty]
        private int y;


        [RelayCommand]
        private void OpenWindow2()
        {
            Y++;
            _navigationService.OpenWindow<MainViewModel>();
        }
}
C#:
// Views

//MainWindow
public partial class MainWindow : Window
{
     public MainWindow()
     {
       InitializeComponent();
     }
}

<Window x:Class="VSM.Views.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:i="http://schemas.microsoft.com/expression/2010/interactivity"
        xmlns:local="clr-namespace:VSM.Views"
        mc:Ignorable="d"
        Title="MainWindow"  Height="450" Width="800">
    <StackPanel>
        <StackPanel>
            <TextBlock Text="{Binding X, Mode=TwoWay}" FontSize="24" Foreground="White" Background="Red"/>
        </StackPanel>
        <StackPanel Background="Gold">
            <Button Command="{Binding OpenWindow2Command}"  Content="Click Me!" HorizontalAlignment="Center" Width="250" Height="35" VerticalAlignment="Center"/>
        </StackPanel>
    </StackPanel>
</Window>

// window2
public partial class Window2 : Window
{
      public Window2()
      {
         InitializeComponent();
      }
}
<Window x:Class="VSM.Views.Window2"
        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:local="clr-namespace:VSM.Views"
        mc:Ignorable="d"
        Title="Window2" Height="450" Width="800">
    <Grid>
        <StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
            <Button Command="{Binding OpenWindow2Command}"  Content="Click Me! Window2"  Width="250" Height="35" />
        </StackPanel>
    </Grid>
</Window>

I would be very happy if someone could direct me, how to open the windows more correctly than the implementation I did and close them (as I mentioned above, the second window if it is by a button that I will add to the user, whether by adding a button through which you can go to the main window or whether by me the window closes on By the X button on the toolbar, I need to "catch" the close event itself, perform an action such as writing to a txt file, close the current window (using the event itself)).
 
Last edited:

Latest posts

Back
Top Bottom