WPF 使用UserControl / ContentControl显示子界面

想把一个东西很多的界面拆分一下,拆成几个小界面再拼接起来,脑袋里有UserControl / ContentControl这些概念,但是不知道具体怎么实现,记录一下两种方法:

法一:UserControl实现

主界面View:

XML 复制代码
<Page x:Class="Lithography.View.MainPage"
      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:telerik="http://schemas.telerik.com/2008/xaml/presentation"
      xmlns:lc="clr-namespace:FluentVision.Controls;assembly=FluentVision.Controls"
      xmlns:sonPage="clr-namespace:Lithography.View.SonPage"
      d:DesignHeight="600"
      d:DesignWidth="800"
      mc:Ignorable="d">
    
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition Width="*"/>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="*"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>

        <!-- 平台运动控制模块 -->
        <sonPage:PlatformMovementControlPage 
            Grid.Row="0" Grid.Column="0"
            DataContext="{Binding PlatformMovement}"
            Margin="5"/>

        <!-- 真空控制模块 -->
        <sonPage:VacuumControlPage 
            Grid.Row="0" Grid.Column="1"
            DataContext="{Binding VacuumControl}"
            Margin="5"/>

        <!-- IO状态显示模块 -->
        <sonPage:IoStatusPage 
            Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2"
            DataContext="{Binding IoStatus}"
            Margin="5"/>
    </Grid>
</Page>

主界面ViewModel

cs 复制代码
using ReactiveUI;

namespace Lithography.ViewModel
{
    public class MainViewModel : ReactiveObject
    {
        public PlatformMovementControlViewModel PlatformMovement { get; }
        public VacuumControlViewModel VacuumControl { get; }
        public IoStatusViewModel IoStatus { get; }

        public MainViewModel()
        {
            PlatformMovement = new PlatformMovementControlViewModel();
            VacuumControl = new VacuumControlViewModel();
            IoStatus = new IoStatusViewModel();
        }
    }
}

主界面声明这些子对象是为了给子界面提供数据源(DataContext绑定),也可以直接在子界面窗体构造函数中指定数据源:

当然还要集合具体使用的MVVM框架,寻求更好实现;

法二:ContentControl + DataTemplate

主界面View:

XML 复制代码
<Page x:Class="Lithography.View.MainPage"
      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:telerik="http://schemas.telerik.com/2008/xaml/presentation"
      xmlns:viewModels="clr-namespace:Lithography.ViewModel.SonPage"
      d:DesignHeight="600"
      d:DesignWidth="800"
      mc:Ignorable="d">
    
    <Page.Resources>
        <!-- 定义 ViewModel 到 View 的映射 -->
        <DataTemplate DataType="{x:Type viewModels:PlatformMovementControlViewModel}">
            <sonPage:PlatformMovementControlPage/>
        </DataTemplate>
        
        <DataTemplate DataType="{x:Type viewModels:VacuumControlViewModel}">
            <sonPage:VacuumControlPage/>
        </DataTemplate>
        
        <DataTemplate DataType="{x:Type viewModels:IoStatusViewModel}">
            <sonPage:IoStatusPage/>
        </DataTemplate>
    </Page.Resources>
    
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition Width="*"/>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="*"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>

        <!-- 使用 ContentControl 自动选择模板 -->
        <ContentControl 
            Grid.Row="0" Grid.Column="0"
            Content="{Binding PlatformMovement}"
            Margin="5"/>
            
        <ContentControl 
            Grid.Row="0" Grid.Column="1"
            Content="{Binding VacuumControl}"
            Margin="5"/>
            
        <ContentControl 
            Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2"
            Content="{Binding IoStatus}"
            Margin="5"/>
    </Grid>
</Page>

主界面ViewModel:

cs 复制代码
 public class MainViewModel : ReactiveObject
    {
        public PlatformMovementControlViewModel PlatformMovement { get; }
        public VacuumControlViewModel VacuumControl { get; }
        public IoStatusViewModel IoStatus { get; }

        public MainViewModel()
        {
            PlatformMovement = new PlatformMovementControlViewModel();
            VacuumControl = new VacuumControlViewModel();
            IoStatus = new IoStatusViewModel();
        }
    }

ContentControl严格上来说也是一个控件,是常见的Button、ScrollViewer的基类:

ContentControl 的 Content 属性的类型为 Object(同样Button的Content也是,只不过常用来显示文本,也可以显示图片和其他布局控件等等),这里在主界面把 ContentControl 的Content 绑定上后台子界面ViewModel,然后设置了ContentControl的ContentTemplate属性,ContentTemplate是DataTemplate类型,注意上方xaml 窗体资源中定义的DataTemplate就是变相指定了ContentControl的ContentTemplate属性,还可以下面这样写:

cs 复制代码
<Window x:Class="_11_4.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Window.Resources>
        <DataTemplate x:Key="datatemplate1">
            <StackPanel Orientation="Horizontal">
                <CheckBox/>
                <TextBlock Text=" Hello World"/>
            </StackPanel>
        </DataTemplate>
    </Window.Resources>
    <Grid>
        <Button Content="Button" Height="23" HorizontalAlignment="Left" Margin="153,26,0,0" Name="button1" VerticalAlignment="Top" Width="130" 
                ContentTemplate="{StaticResource datatemplate1}"/>
        <Label Content="Label" Height="28" HorizontalAlignment="Left" Margin="153,68,0,0" Name="label1" VerticalAlignment="Top" Width="130" 
               ContentTemplate="{StaticResource datatemplate1}"/>
        <ScrollViewer Height="23" HorizontalAlignment="Left" Margin="153,127,0,0" Name="scrollViewer1" VerticalAlignment="Top" Width="120" 
                ContentTemplate="{StaticResource datatemplate1}"/>
        
    </Grid>
</Window>

或者:

XML 复制代码
<Button>
    <Button.ContentTemplate>
        <DataTemplate>
            <StackPanel Orientation="Horizontal">
                <Image Source="/Icons/settings.png" Width="16" Height="16" Margin="0,0,5,0"/>
                <TextBlock Text="设置" VerticalAlignment="Center"/>
            </StackPanel>
        </DataTemplate>
    </Button.ContentTemplate>
</Button>

...很多种写法,想了解的话可以问一下AI,我就不愿意列举了。

部分代码引用自:https://blog.csdn.net/lzhui1987/article/details/51878861?fromshare=blogdetail&sharetype=blogdetail&sharerId=51878861&sharerefer=PC&sharesource=qq_59062726&sharefrom=from_link

相关推荐
wangnaisheng5 小时前
【WPF】WrapPanel的用法
wpf
源之缘-OFD先行者17 小时前
10 万雷达点迹零卡顿回放:WPF + Vortice.Direct2D 多线程渲染实战
wpf
猫林老师1 天前
Flutter for HarmonyOS开发指南(九):测试、调试与质量保障体系
flutter·wpf·harmonyos
LateFrames1 天前
做【秒开】的程序:WPF / WinForm / WinUI3 / Electron
electron·c#·wpf·winform·winui3·claude code
beyond谚语2 天前
第四章 依赖项属性
wpf
国服第二切图仔2 天前
鸿蒙应用开发之实现键值型数据库跨设备数据同步
数据库·wpf·harmonyos
玖笙&2 天前
✨WPF编程进阶【7.1】动画基础
c++·c#·wpf·visual studio
专注VB编程开发20年2 天前
探讨vs2022在net6框架wpf界面下使用winform控件
framework·.net·wpf·winform·cefsharp·miniblink·geckofx45
刘一说2 天前
Spring Boot 中的定时任务:从基础调度到高可用实践
spring boot·后端·wpf