How to open child window in mainwindow in MMVM WPF

2019-05-31 23:20发布

问题:

I have 3 screens

Mainwindow.xaml

<Window x:Class="PatientAdminTool.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         >
    <Window.DataContext>
        <vm:MainViewModel></vm:MainViewModel>    
    </Window.DataContext>
    <WindowChrome.WindowChrome>
        <WindowChrome 
        CaptionHeight="0"/>
    </WindowChrome.WindowChrome>
    <ContentControl >
        <v:PatientWindow DataContext="{Binding PatientVM}"/>
    </ContentControl>
</Window>

PatientWindow.xaml

<UserControl x:Class="PatientAdminTool.View.PatientWindow"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:vm="clr-namespace:PatientAdminTool.ViewModel"
         xmlns:v="clr-namespace:PatientAdminTool.View"
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300" >
    <UserControl.DataContext>
        <vm:PatientSelectorVM/>
    </UserControl.DataContext>
    <Grid >
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>

            <DockPanel Grid.Row="0" LastChildFill="True" Height="40" Background="#646161" >
                <StackPanel DockPanel.Dock="Left" Orientation="Horizontal">
                    <TextBlock Margin=" 10,5,0,0" HorizontalAlignment="Center" Text="Patients" FontSize="16"  TextAlignment="Center" VerticalAlignment="Center" Foreground="#FFFFFF"/>
                </StackPanel>
                <StackPanel Margin="10,10,0,0" DockPanel.Dock="Right" Background="Transparent"  Orientation="Vertical" HorizontalAlignment="Right" VerticalAlignment="Top" Width="50" >
                    <StackPanel Background="Transparent"  Orientation="Horizontal" HorizontalAlignment="Right">
                        <Button Focusable="False" ToolTip="Close" VerticalAlignment="Center" Background="#646161" BorderThickness="0" BorderBrush="Transparent" Padding="-4" Command="{Binding CloseCommand,Mode=TwoWay}">
                            <Button.Content>
                                <Grid Width="45" Height="23">
                                    <TextBlock Foreground="White"   Text="r" FontFamily="Marlett" FontSize="20" VerticalAlignment="Center" HorizontalAlignment="Center"/>
                                </Grid>
                            </Button.Content>
                            <Button.Template>
                                <ControlTemplate TargetType="Button">
                                    <ContentPresenter Content="{TemplateBinding Content}"/>
                                </ControlTemplate>
                            </Button.Template>
                        </Button>
                    </StackPanel>
                </StackPanel>
            </DockPanel>
        <ContentControl Grid.Row="1" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" >
            <v:PatientSelector DataContext="{Binding PatientSelectorVM}" />
        </ContentControl>
    </Grid>
</UserControl>

Result should be as per the below image

I need to show the child window by using corresponding view model. I am not getting how to do this?

回答1:

You can't access UI elements (including windows) in ViewModels directly.

Just make abstraction of the functionality "Open Window". The easiest way is to use interface:

interface IDialogService 
{
    public void OpenWindow(BaseViewModel windowViewModel);
}

//in viewmodel:
void OpenPatientWindow_CommandExecuted()
{
     var patientWindowVM = new PatientWindowViewModel())
     patientWindowVM.Parameter = "This way you can pass parameters";
    _dialogService.OpenWindow(patientWindowVM);
}

go here for more inspiration: Handling Dialogs in WPF with MVVM



回答2:

Bind the Content property of ContentPresenter to the PatientVM property of the MainViewModel in MainWindow.xaml and use define a DataTemplate per child view/view model type:

<ContentControl Content="{Binding PatientVM}">
    <ContentControl.Resources>
        <DataTemplate DataType="local:PatientSelectorVM">
            <v:PatientWindow />
        </DataTemplate>
        <DataTemplate DataType="local:ThirdScreenType">
            <v:ThirdScreenView />
        </DataTemplate>
    </ContentControl.Resources>
</ContentControl>

You then set the PatientVM property of the MainViewModel to a PatientSelectorVM object to display the PatientWindow view and to a ThirdScreenType object (or whatever your class is actually called) to display the other view in the ContentControl.

Make sure that the MainViewModel implements the INotifyPropertyChanged interface and raise the PropertyChanged event in the setter of the PatientVM property:

public BaseViewModel PatientVM
{
    get { return _patientVM; }
    set
    {
        patientVM = value;
        OnPropertyChanged();
    }
}

For you to be able to set the property to both a PatientSelectorVM object and the other type of objects, these classes should derive from the same base class or implement the same interface.



标签: c# wpf mvvm