"Closing WPF View from ViewModel in MVVM: Correct Approach and Implementation Help Needed"

fatih uyanık 225 Reputation points
2023-12-13T11:37:46.5566667+00:00

Hello,

I am developing an MVVM WPF C# project. In this project, on the ViewModel side, I want to close the relevant View window with a button. For instance, let's say the window name is "TestView" and the ViewModel name is "TestViewModel". In the ViewModel, I want to extract and find the View name according to the ViewModel from within the WPF window collection, and then close this window. Would this approach be correct according to the ViewModel rules? Can you assist me on how to do this?

Thank you.

Developer technologies Windows Presentation Foundation
Developer technologies C#
{count} votes

1 answer

Sort by: Most helpful
  1. Peter Fleischer (former MVP) 19,341 Reputation points
    2023-12-13T14:28:54.22+00:00

    Hi,
    try following demo:

    XAML MainWindow:

    <Window x:Class="WpfApp122.Window122"
            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:WpfApp122"
            mc:Ignorable="d"
            Title="fatih_uyanık_121213" Height="450" Width="800">
      <Window.DataContext>
        <local:ViewModelMain/>
      </Window.DataContext>
      <StackPanel>
        <Button Command="{Binding}" Content="Open new Window" Margin="10"/>
      </StackPanel>
    </Window>
    
    

    Code incl. ViewModel for MainWindow:

    using System;
    using System.Windows;
    using System.Windows.Input;
    
    namespace WpfApp122
    {
    	/// <summary>
    	/// Interaction logic for Window122.xaml
    	/// </summary>
    	public partial class Window122 : Window
    	{
    		public Window122()
    		{
    			InitializeComponent();
    		}
    	}
    
    	public class ViewModelMain : ICommand
    	{
    		public void Execute(object parameter) => (new Window122Sub()).Show();
    		public event EventHandler CanExecuteChanged;
    		public bool CanExecute(object parameter) => true;
    	}
    }
    

    XAML SubWindow:

    <Window x:Class="WpfApp122.Window122Sub"
            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:WpfApp122"
            mc:Ignorable="d"
            Title="Window122Sub" Height="450" Width="800"
            local:ViewModelSub.AttProp="True">
      <Window.DataContext>
        <local:ViewModelSub/>
      </Window.DataContext>
      <StackPanel>
        <Label Content = "Sub Window" Margin="20"/>
        <Button Command="{Binding}" Content="Close Window" Margin="10"/>
      </StackPanel>
    </Window>
    
    

    Code incl. ViewModel for SubWindow:

    using System;
    using System.Windows;
    using System.Windows.Input;
    
    namespace WpfApp122
    {
    	/// <summary>
    	/// Interaction logic for Window122Sub.xaml
    	/// </summary>
    	public partial class Window122Sub : Window
    	{
    		public Window122Sub()
    		{
    			InitializeComponent();
    		}
    	}
    
    	public class ViewModelSub : ICommand
    	{
    		public static readonly DependencyProperty AttPropProperty = DependencyProperty.Register("AttProp",
    			typeof(bool), typeof(Window), new UIPropertyMetadata(false, OnAttProp));
    		public static bool GetAttProp(DependencyObject obj) => (bool)obj.GetValue(AttPropProperty);
    		public static void SetAttProp(DependencyObject obj, bool value) => obj.SetValue(AttPropProperty, value);
    		private static void OnAttProp(DependencyObject depObj, DependencyPropertyChangedEventArgs e)
    		{
    			var wnd = depObj as Window;
    			if (wnd == null) return;
    			if ((e.NewValue is bool) && (bool)(e.NewValue))
    				wnd.Loaded += Wnd_Loaded;
    		}
    		private static void Wnd_Loaded(object sender, RoutedEventArgs e)
    		{
    			Window wnd = sender as Window;
    			if (wnd == null) return;
    			ViewModelSub dc = wnd.DataContext as ViewModelSub;
    			if (dc == null) return;
    			dc.SubWindow = wnd;
    		}
    
    		Window SubWindow { get; set; }
    
    		public void Execute(object parameter) => SubWindow.Close();
    		public event EventHandler CanExecuteChanged;
    		public bool CanExecute(object parameter) => true;
    	}
    }
    
    

    Result:

    x

    1 person found this answer helpful.

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.