【问题标题】:How to load usercontrol in Mainwindow in MVVM WPF?如何在 MVVM WPF 的主窗口中加载用户控件?
【发布时间】:2017-01-16 18:13:28
【问题描述】:

我有一个MainWindow.Xaml 文件。还有一个用户控件PatientWindow.Xaml。如何在 MVVM 架构的主窗口中加载患者窗口?

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"
         xmlns:vm="clr-namespace:PatientAdminTool.ViewModel"
         xmlns:v="clr-namespace:PatientAdminTool.View"
        xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
        ResizeMode="CanResizeWithGrip" 
        WindowStyle="None"  
        WindowState="Normal"  
        Title="PatientAdmin Tools"           
        Height="750"
        Width="1400"
        AllowsTransparency="True" MouseLeftButtonDown="OnMouseLeftButtonDown" BorderThickness="1"  BorderBrush="#555252"  >  
    <WindowChrome.WindowChrome>
        <WindowChrome 
        CaptionHeight="0"     
          />
    </WindowChrome.WindowChrome>
</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" >

    <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" Click="Button_Click" >
                        <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>
    </Grid>
</UserControl>

所以我需要使用 MVVM 加载主窗口上方的患者窗口。这里我需要在对应的 View Model 中编写加载事件。请帮我做这件事。

【问题讨论】:

  • 你想在窗口中显示 UserControl?
  • 是的。在运行项目时,我需要看到上面的 meainwindow,我的用户控件需要显示。
  • 在同一个窗口,还是新窗口?
  • 是同一个窗口
  • 如果您使用的是 MVVM,那么您可能应该使用模板而不是用户控件,仅当您需要代码隐藏文件时才需要用户控件

标签: c# wpf mvvm


【解决方案1】:

只需在 MainWindow 中添加 ControlPresenter

<ContentPresenter Content="{Binding YouTypeHere}">
             <ContentPresenter.Resources>
                 <DataTemplate DataType="{x:Type fristViewModel1Type}">
                     <youControlForViewModel1 />
                 </DataTemplate>
                 <DataTemplate DataType="{x:Type secondViewModel2Type}">
                     <youControlForViewModel2 />
                 </DataTemplate>
            </ContentPresenter.Resources>
         </ContentPresenter>

您可以通过将不同的虚拟机绑定到 ContentPresenter 来更改视图。

【讨论】:

  • 我需要提到的绑定属性“youtypehere”和“”。
  • @Shri 是的,只是一些伪代码,忘记描述:(,'youtypehere' 是主视图模型的属性,必须是'firstViewModelType' 或'secondViewModelType' 类型。
【解决方案2】:

所以您想使用 MVVM 打开一个新的子窗口?我假设你会从 MainWindowViewModel 打开它。

解决方案 1:没有严格的 MVVM

有时可以从 ViewModel 直接打开

private void OnOpenPatientWindowCommandExecute()
{
    var o = new PatientWindow();
    o.ShowDialog(); 
}

为此,您必须将 PatientWindowUserControl 更改为 Window

解决方案 2:严格的 MVVM

遵循严格的 MVVM 的解决方案稍微复杂一些。在我在这里编写的解决方案中,您必须使用 Service,将其添加到您的 MainWindowViewModel 并将视图中的控件绑定到 Command在视图模型中。此外,它的编写就像您使用依赖注入一样,这就是为什么您会在构造函数中看到服务注入的原因。您可以通过在构造函数中实例化服务来避免这种情况。

MainWindowViewModel.cs

using Prism.Wpf.Commands; // For easy commands
using PatientAdminTool.Services; // Where you put your new service

public class MainWindowViewModel
{
   private IShowDialogService _ShowDialogService;

   public MainWindowViewModel(IShowDialogService showDialogService)
   {
       _ShowDialogService = showDialogService;

       // Or do: _ShowDialogService = new ShowDialogService();
       // But that's not a good practice and won't let you test
       // this ViewModel properly.

       OpenPatientWindowCommand = new DelegateCommand(OnOpenPatientWindowCommandExecute);
   }

   public ICommand OpenPatientWindowCommand { get; private set; }

   private void OnOpenPatientWindowCommandExecute()
   {
       _ShowDialogService.ShowPatientWindow();
   }
}

服务\IShowDialogService.cs

public interface IShowDialogService
{
    void ShowPatientWindow();

    void ShowOtherWindow();

    // ...
}

服务\ShowDialogService.cs

public class ShowDialogService : IShowDialogService
{
    public void ShowPatientWindow()
    {
        var patientWindowViewModel = new PatientWindowViewModel();
        var patientWindow = new PatientWindow();

        patientWindow.DataContext = patientWindowViewModel;

        patientWindow.ShowDialog();
    }

    public void ShowOtherWindow()
    {
        // Other window ...
    }
}

最后,像这样在视图中建立连接:

MainWindow.xaml

<Window
    xmlns:vm="clr-namespace:PatientAdminTool.ViewModel">
    <Window.DataContext>
        <vm:MainWindowViewModel/>
    </Window.DataContext>
    <Grid>
        <Button Command="{Binding OpenPatientCommand}">Open Patient</Button>
    </Grid>
</Window>

还没有在 Visual Studio 中尝试过,但就是这样。

【讨论】:

    【解决方案3】:

    如果这是您将要在同一个窗口中显示的唯一内容,只需将您的视图像任何其他控件一样放在那里:

    <Window x:Class="PatientAdminTool.MainWindow"
            xmlns:v="clr-namespace:PatientAdminTool.View"... >  
        <WindowChrome.WindowChrome>
            <WindowChrome 
            CaptionHeight="0"/>
        </WindowChrome.WindowChrome>
        <v:PatientWindow/>
    </Window>
    

    您的窗口有根 ViewModel 吗?如果是这样,您可以绑定到 PatientViewModel:

    <v:PatientWindow DataContext="{Binding PatientViewModel}"/>
    

    如果不是,通常在代码隐藏中将第一个 DataContext 设置为 ViewModel,如下所示:

    <v:PatientWindow Name="PatientWindowView"/>
    

    和:

    public partial class Window
    {
        public MainWindow()
        {
            InitializeComponent();
            PatientWindowView.DataContext = new PatientWindowViewModel();
    
        }
    }
    

    如果您想显示多个视图,请使用 Shakra 已回答的 ContentPresenter。

    如果您想打开一个新窗口,请使用 Alberto Cardona López 的建议。

    【讨论】:

    • 很好的答案,但您错过了一些内容,例如模板化和添加命名空间
    • 模板是什么意思?类似于@Shakra 的回答?如果是这样,我在答案中提到了这一点。如果您只有一个视图,则不确定是否需要模板,这似乎比提问者想要的要复杂。我没有说如何添加命名空间,因为问题包含它 - 但我已经添加它以防其他人偶然发现并感到困惑。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-06-27
    相关资源
    最近更新 更多