No, this is not valid. The VM should not contain any UI code.
There are many different ways of doing what you want. I like to use a service class. Below is a basic (incomplete) service that you can use. You will need to update it for your needs.
public interface IWindowService
{
void ShowWindow<T>(T viewModel);
}
public class WindowService : IWindowService
{
public void ShowWindow<T>(T viewModel)
{
var window = Application.Current
.Windows
.OfType<WindowDialog>()
.FirstOrDefault(x => x.Content?.GetType() == viewModel.GetType());
if (window == null)
{
window = new WindowDialog { Content = viewModel };
window.Title = "This is a title";
window.Owner = Application.Current.Windows[0];
window.Show();
}
else
{
window.Activate();
}
}
}
Here is the
WindowDialog
Window to host the "Window Views":
<Window
x:Class="MvvmShowWindow.WindowDialog"
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"
mc:Ignorable="d"
WindowStyle="SingleBorderWindow" WindowStartupLocation="CenterOwner" SizeToContent="WidthAndHeight">
</Window>
Next we need a couple of test "Window Views":
<UserControl
x:Class="MvvmShowWindow.Window1View"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Height="300" Width="600">
<Grid>
<Viewbox>
<TextBlock Text="WINDOW 1"/>
</Viewbox>
</Grid>
</UserControl>
<UserControl
x:Class="MvvmShowWindow.Window2View"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Height="300" Width="600">
<Grid>
<Viewbox>
<TextBlock Text="WINDOW 2"/>
</Viewbox>
</Grid>
</UserControl>
And matching ViewModels for the "Window Views":
class Window1ViewModel : ViewModelBase
{
}
class Window2ViewModel : ViewModelBase
{
}
Next we need to associate the VMs with the Views. Here I do it in the App.Xaml:
<Application.Resources>
<DataTemplate DataType="{x:Type local:Window1ViewModel}">
<local:Window1View/>
</DataTemplate>
<DataTemplate DataType="{x:Type local:Window2ViewModel}">
<local:Window2View/>
</DataTemplate>
</Application.Resources>
Now we are ready to use the service in the MainViewModel:
public class MainViewModel : ViewModelBase
{
public MainViewModel()
{
ShowCommand = new RelayCommand<string>(CommandShow);
}
public ICommand ShowCommand { get; }
private IWindowService Service = new WindowService();
private void CommandShow(string msg)
{
switch (msg)
{
case "w1":
Service.ShowWindow(new Window1ViewModel());
break;
case "w2":
Service.ShowWindow(new Window2ViewModel());
break;
}
}
}
And the MainWindow to run the test:
<Window
x:Class="MvvmShowWindow.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:local="clr-namespace:MvvmShowWindow"
mc:Ignorable="d" WindowStartupLocation="CenterScreen"
Title="MVVM Windows" Height="350" Width="525" >
<Window.DataContext>
<local:MainViewModel/>
</Window.DataContext>
<Grid>
<StackPanel VerticalAlignment="Center" HorizontalAlignment="Center">
<Button Content="Window1" Margin="10 5" Padding="10,5"
Command="{Binding ShowCommand}" CommandParameter="w1"/>
<Button Content="Window2" Margin="10 5" Padding="10,5"
Command="{Binding ShowCommand}" CommandParameter="w2"/>
</StackPanel>
</Grid>
</Window>