I want to create a Interface to control all windows. I used Microsoft.Extensions.DependencyInjection
.
Interface IWindowManager and class WindowManager as:
public interface IWindowManager
{
void OpenWindow<TWindow>() where TWindow : Window;
void CloseWindow<TWindow>() where TWindow : Window;
}
public class WindowManager : IWindowManager
{
private readonly IServiceProvider _serviceProvider;
public WindowManager(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
public void OpenWindow<TWindow>() where TWindow : Window
{
var window = _serviceProvider.GetRequiredService<TWindow>();
window.Show();
}
public void CloseWindow<TWindow>() where TWindow : Window
{
var window = _serviceProvider.GetRequiredService<TWindow>();
window.Close();
}
}
In App.xaml.cs, i create IoC container, it's the same as the code of Microsoft Commuinty document https://learn.microsoft.com/en-us/dotnet/communitytoolkit/mvvm/ioc
public partial class App : Application
{
public App()
{
Services = ConfigureServices();
}
public new static App Current => (App)Application.Current;
public IServiceProvider Services { get; }
private static IServiceProvider ConfigureServices()
{
var services = new ServiceCollection();
services.AddSingleton<IWindowManager, WindowManager>();
services.AddTransient<MainWindowViewModel>();
services.AddTransient<MainWindow>(
sp => new MainWindow
{ DataContext = sp.GetService<MainWindowViewModel>() });
services.AddTransient<TaskWindowViewModel>();
services.AddTransient<TaskWindow>(
sp => new TaskWindow
{ DataContext = sp.GetService<TaskWindowViewModel>() });
return services.BuildServiceProvider();
}
private void Application_Startup(object sender, StartupEventArgs e)
{
var MW = Services.GetService<MainWindow>();
MW!.Show();
}
}
In MainWindowViewModel.cs, i create two RelayCommand method by CommunityToolkit.Mvvm, and binding with button in Xaml:
public partial class MainWindowViewModel : ObservableObject
{
private readonly IWindowManager _windowManager;
#region Windows Manager
[RelayCommand]
private void OpenTaskWindow()
{
_windowManager.OpenWindow<TaskWindow>();
}
[RelayCommand]
private void CloseMainWindow()
{
_windowManager.CloseWindow<MainWindow>();
}
#endregion
public MainWindowViewModel( IWindowManager windowManager)
{
_windowManager = windowManager;
}
}
I tried the method of OpenTaskWindow workes, but CloseMainWindow does't work. I don't know what's wrong.Please help me, thank you.
I resolved it. Add a dictionary viewModelWindowMapping
to save types of windows and viewModels.
private Dictionary<object, Window> windowList = new();
private Dictionary<Type, Type> viewModelWindowMapping = new()
{
{ typeof(MainWindowViewModel),typeof(MainWindow)},
{ typeof(TaskWindowViewModel),typeof(TaskWindow)}
};
public WindowManager(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
public void OpenWindow(object viewModel)
{
if (viewModel == null)
{
throw new ArgumentNullException(nameof(viewModel));
}
if (windowList.ContainsKey(viewModel))
{
return;
}
Window window = GetWindowForViewModel(viewModel);
windowList[viewModel] = window;
window.Show();
}
public void CloseWindow(object viewModel)
{
if (viewModel == null)
{
throw new ArgumentNullException(nameof(viewModel));
}
if (!windowList.ContainsKey(viewModel))
{
return;
}
Window window = windowList[viewModel];
window.Close();
windowList.Remove(viewModel);
}
private Window GetWindowForViewModel(object viewModel)
{
var windowType = GetWindowTypeForViewModel(viewModel.GetType());
return (Window)_serviceProvider.GetRequiredService(windowType);
}
private Type GetWindowTypeForViewModel(Type viewModelType)
{
if (viewModelWindowMapping.TryGetValue(viewModelType, out var windowType))
{
return windowType;
}
throw new Exception($"No window type is mapped for the view model type {viewModelType.FullName}");
}
Like this, when i want to add another window. I just need add one mapping in viewModelWindowMapping