WPF编程-Prism
世有伯乐,然后有千里马。千里马常有,而伯乐不常有。
一、背景
Winform和WPF
1. WinForms和WPF
-
技术架构:
- WinForms是基于传统的窗体和控件的技术,使用的是类似于VB6时代的设计理念。
- WPF是基于XAML(可扩展应用程序标记语言)的技术,允许更灵活、高度可定制化的用户界面设计,支持更丰富的视觉效果和动画。
-
数据绑定:
- WPF具有强大的数据绑定功能,支持更复杂的绑定和更灵活的数据展示。
- WinForms的数据绑定相对简单,功能不如WPF强大。
-
UI设计:
- WPF提供了更丰富的UI设计功能,支持更灵活的布局和样式定义,使得界面设计更加现代化。
- WinForms相对来说UI设计较为传统,样式和布局定制性不如WPF。
-
3D支持:
- WPF具有内置的3D图形支持,可以更容易地实现3D效果。
- WinForms不支持直接的3D图形渲染。
总的来说,WPF相对于WinForms在用户界面设计、数据绑定、样式定制等方面更为强大和灵活,适合开发现代化、复杂的Windows应用程序。如果您想要开发具有现代化UI设计和丰富视觉效果的应用程序,可以考虑学习和使用WPF技术。
2. 生命周期
Application
- OnStartup:表示启动应用程序时
- OnActivated:表示激活应用程序时
- OnDeactivated:表示由激活状态变为非激活状态时
- OnExit:表示退出应用程序时
Window窗体
事件 | 含义 |
---|---|
SourceInitialized | 创建窗体源时引发此事件 |
Activated | 当前窗体成为前台窗体时引发此事件 |
Loaded | 当前窗体内部所有元素完成布局和呈现时引发此事件 |
ContentRendered | 当前窗体的内容呈现之后引发此事件 |
Closing | 当前窗体关闭之前引发此事件 |
Deactivated | 当前窗体成为后台窗体时引发此事件 |
Closed | 当前窗体关闭之后引发此事件 |
Unloaded | 当前窗体从元素树中删除时引发此事件 |
二、控件、样式、模板、主题
0. 基础控件
-
TextBox(文本框):TextBox 是用于接受用户输入文本的基本控件,允许用户在其中输入和编辑文本信息。
-
PasswordBox(密码框):PasswordBox 是用于接受用户输入密码的控件,其输入内容会被隐藏为密码符号,保护用户输入的隐私信息。
-
Button(按钮):Button 允许用户执行某个操作或触发某个事件,是常用的交互控件之一。
-
CheckBox(复选框):CheckBox 允许用户在多个选项中进行选择,表示一个布尔值的状态。
-
RadioButton(单选按钮):RadioButton 允许用户在多个选项中进行单一选择,通常用于互斥选项。
-
ComboBox(下拉框):ComboBox 允许用户从预定义的选项列表中进行选择,提供了下拉菜单的功能。
-
ListBox(列表框):ListBox 显示一个列表,用户可以从中选择一个或多个项目。
-
DatePicker(日期选择器):DatePicker 允许用户选择日期,提供了日期选择的功能。
-
Slider(滑块):Slider 允许用户通过拖动滑块来选择一个值,通常用于调整数值范围。
1. 布局控件
在 WPF 中,布局控件用于帮助您设计和排列界面元素,以便在窗口中以一种有组织的方式显示它们。以下是一些常用的 WPF 布局控件的介绍:
-
Grid(网格):
-
Grid
是一个灵活的布局控件,允许您将界面元素放置在行和列的网格中。您可以定义行和列的大小、对齐方式以及元素的位置。 -
Grid.ColumnSpan
是用于指定一个元素横跨的列数的属性。当您将一个元素放置在Grid
控件中时,可以使用Grid.ColumnSpan
来控制该元素横跨的列数,从而实现跨列布局的效果。举个例子,如果您有一个
Grid
控件,其中有三列,您可以将一个元素设置为横跨前两列的效果,示例如下:<Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="Auto"/> <!-- 第一列 --> <ColumnDefinition Width="Auto"/> <!-- 第二列 --> <ColumnDefinition Width="Auto"/> <!-- 第三列 --> </Grid.ColumnDefinitions> <Button Content="Spanning Two Columns" Grid.Column="0" Grid.ColumnSpan="2"/> </Grid>
在上面的示例中,
Button
元素被放置在第一列,并且通过Grid.ColumnSpan="2"
属性指定横跨两列。这样,该按钮元素将占据第一列和第二列的空间,实现了跨列布局的效果。Grid.ColumnSpan
属性可以帮助您更灵活地控制元素在Grid
中的布局。
-
-
StackPanel(堆栈面板):
StackPanel
允许您将界面元素按照水平或垂直方向进行堆叠。元素会依次排列在一条直线上,适合简单的布局需求。Orientation
枚举属性,用于设置子控件在StackPanel内部的排列方式,分别是水平排列(Horizontal
)和垂直排列(Vertical
)。默认值是垂直排列(Vertical)。
-
DockPanel(停靠面板):
DockPanel
允许您将界面元素停靠在面板的边缘,可以设置元素停靠的位置(上、下、左、右或填充)。LastChildFill
是 DockPanel 控件的一个属性,用于指定最后一个子元素是否填充剩余的空间。当LastChildFill
属性设置为true
时,最后一个添加到 DockPanel 中的子元素将填充剩余的空间,而其他子元素将根据其停靠的位置进行布局。
-
WrapPanel(换行面板):
WrapPanel
允许您按照水平或垂直方向排列元素,当空间不足时会自动换行显示元素。
-
Canvas(画布):
Canvas
允许您在一个绝对定位的坐标系统中放置元素,可以精确地控制元素的位置。
-
UniformGrid(均匀网格):
UniformGrid
将子元素等分为固定数量的行和列,使它们在网格中均匀分布。
-
GridSplitter(网格分隔器):
GridSplitter
允许用户通过拖动来调整Grid
控件中行或列的大小,提供了用户界面的灵活性。
2. 样式Style
在 WPF 中,样式(Style)是一种用于定义控件外观和行为的重要机制。通过样式,您可以统一定义控件的外观属性,如背景色、字体样式、边框等,以及行为属性,如触发器、动画等。这样可以实现界面的一致性和可维护性。
以下是一个简单的示例,展示如何在 WPF 中定义和应用样式:
定义样式:
<Window.Resources>
<Style x:Key="MyButtonStyle" TargetType="Button">
<Setter Property="Background" Value="LightBlue"/>
<Setter Property="Foreground" Value="White"/>
<Setter Property="FontSize" Value="14"/>
</Style>
</Window.Resources>
应用样式:
<Button Content="Click Me" Style="{StaticResource MyButtonStyle}"/>
在上面的示例中,我们定义了一个名为 MyButtonStyle
的样式,目标类型为 Button
。在样式中,我们设置了按钮的背景色为浅蓝色、前景色为白色、字体大小为14。然后,通过 Style
属性将这个样式应用到一个按钮上。
通过样式的使用,您可以轻松地统一控件的外观和行为,提高开发效率并实现界面的统一风格。您还可以使用触发器、动画等功能扩展样式的功能,以满足更复杂的界面设计需求。
BasedOn
是样式(Style)中的一个属性,用于指定一个样式基于另一个样式进行继承和扩展。通过使用 BasedOn
属性,您可以创建一个新的样式,该样式会继承基础样式的属性,并可以在此基础上进行进一步的定制。
下面是一个示例,展示如何在 WPF 样式中使用 BasedOn
属性:
定义基础样式:
<Window.Resources>
<Style x:Key="BaseButtonStyle" TargetType="Button">
<Setter Property="Background" Value="LightBlue"/>
<Setter Property="Foreground" Value="White"/>
<Setter Property="FontSize" Value="14"/>
</Style>
</Window.Resources>
定义基于基础样式的新样式:
<Style x:Key="CustomButtonStyle" TargetType="Button" BasedOn="{StaticResource BaseButtonStyle}">
<Setter Property="BorderBrush" Value="Transparent"/>
<Setter Property="BorderThickness" Value="0"/>
</Style>
在上面的示例中,我们首先定义了一个名为 BaseButtonStyle
的基础按钮样式,设置了背景色、前景色和字体大小。然后,我们定义了一个名为 CustomButtonStyle
的新样式,通过 BasedOn="{StaticResource BaseButtonStyle}"
指定该样式基于 BaseButtonStyle
进行继承。
在 CustomButtonStyle
中,我们进一步设置了按钮的边框为透明,实现了对基础样式的扩展。这样,新样式将继承基础样式的属性,并可以根据需要进行定制。
3. 控件模板Control Template
在 WPF 中,控件模板(Control Template)用于定义控件的外观和结构,允许您完全自定义控件的外观。通过控件模板,您可以重新定义控件的视觉结构、样式和交互方式,使其符合您的设计需求。
以下是一个简单的示例,展示如何在 WPF 中创建一个自定义按钮控件模板:
<Window.Resources>
<ControlTemplate x:Key="CustomButtonTemplate" TargetType="Button">
<Border Background="LightBlue" CornerRadius="5">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
</ControlTemplate>
</Window.Resources>
<Button Content="Click Me" Template="{StaticResource CustomButtonTemplate}"/>
在上面的示例中,我们定义了一个名为 CustomButtonTemplate
的按钮控件模板,其中:
- 外部是一个带有圆角的蓝色边框(
Border
)。 - 内部包含一个内容呈现器(
ContentPresenter
),用于显示按钮的内容。
然后,我们将这个自定义按钮模板应用到一个按钮上,通过 Template
属性指定使用我们定义的模板。
通过控件模板,您可以完全自定义控件的外观和行为,使其与应用程序的整体设计风格一致。您可以根据需要添加更多的元素、样式和交互效果来定制您的控件模板。
4. 数据模板 DateTemplate
在 WPF 中,DataTemplate
(数据模板)用于定义数据对象在界面上的呈现方式。通过数据模板,您可以指定如何显示数据对象的属性和内容,以便在界面中展示数据的特定视觉布局。
以下是一个简单的示例,展示如何在 WPF 中创建一个简单的数据模板来呈现数据对象:
XAML 中定义数据模板:
<Window.Resources>
<DataTemplate x:Key="PersonTemplate">
<StackPanel>
<TextBlock Text="{Binding Name}" FontWeight="Bold"/>
<TextBlock Text="{Binding Age}"/>
<TextBlock Text="{Binding Occupation}"/>
</StackPanel>
</DataTemplate>
</Window.Resources>
在上面的示例中,我们定义了一个名为 PersonTemplate
的数据模板,其中:
- 使用
StackPanel
布局控件来垂直排列数据内容。 - 使用三个 UI端的
TextBlock
控件来显示Code端数据对象的属性:Name
、Age
和Occupation
。
在界面中应用数据模板:
<ListBox ItemsSource="{Binding People}" ItemTemplate="{StaticResource PersonTemplate}"/>
在上面的示例中,我们将数据模板应用到一个 ListBox
控件中,通过 ItemTemplate
属性指定使用我们定义的 PersonTemplate
。这样,每个数据对象在 ListBox
中都会按照我们定义的数据模板进行呈现。
通过数据模板,您可以灵活地定义数据对象在界面中的展示方式,使界面更具可读性和吸引力。您还可以根据需要使用触发器、转换器等功能来进一步定制数据模板以满足特定需求。
三、数据绑定
在 WPF 中,数据绑定(Data Binding)是一种机制,用于在界面元素(如控件、属性)和数据源之间建立关联,使数据的变化能够自动更新到界面上,实现数据和界面的同步显示。
通过数据绑定,您可以将界面元素的属性(如文本框的文本内容、按钮的可见性等)绑定到数据源(如对象、集合、属性等),或从邦定源转到绑定目标,从而实现动态数据展示和交互。数据绑定大大简化了界面开发过程,减少了手动更新界面的工作量,提高了代码的可维护性和灵活性。
1、Data Binding Modes
- OneWay: 从源到目标。
- TwoWay: 双向,源和目标相互复制。
- OneTime: 属性初始值会被设置,对源的更新不会复制目标。
- OneWayToSource: 和OneWay相反,从目标到源。
image-20240418150440689
不同的绑定模式:
<Grid>
<StackPanel>
<Slider x:Name="Slider" Value="50" Maximum="100" Minimum="0"></Slider>
<TextBox Text="{Binding ElementName=Slider, Path=Value, Mode=OneWay}" x:Name="OneWayTB" ></TextBox>
<TextBox Text="{Binding ElementName=Slider, Path=Value, Mode=TwoWay}" x:Name="TwoWayTB"></TextBox>
<TextBox Text="{Binding ElementName=Slider, Path=Value, Mode=OneTime}" x:Name="OneTimeTB"></TextBox>
<TextBox Text="{Binding ElementName=Slider, Path=Value, Mode=OneWayToSource}" x:Name="OneWayToSourceTB"></TextBox>
</StackPanel>
</Grid>
以下是一个简单的示例,展示如何在 WPF 中进行数据绑定:
XAML 中的数据绑定:
<Window x:Class="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">
<Grid>
<TextBlock Text="{Binding UserName}" />
<Button Content="Click Me" IsEnabled="{Binding IsButtonEnabled}" />
</Grid>
</Window>
在上面的示例中,我们通过 {Binding}
语法将界面元素(TextBlock
和 Button
)的属性绑定到数据源的属性:
TextBlock
的Text
属性绑定到数据源的UserName
属性,用于显示用户名。Button
的IsEnabled
属性绑定到数据源的IsButtonEnabled
属性,控制按钮的可用状态。
在代码中设置数据源:
public partial class MainWindow : Window
{
public string UserName { get; set; }
public bool IsButtonEnabled { get; set; }
public MainWindow()
{
InitializeComponent();
this.DataContext = this; // 设置窗口的数据上下文为当前窗口实例
this.UserName = "John Doe";
this.IsButtonEnabled = true;
}
}
在代码中,我们设置窗口的数据上下文为当前窗口实例,并初始化 UserName
和 IsButtonEnabled
属性的值。这样,界面元素与数据源之间的绑定关系就建立起来了。
通过数据绑定,您可以实现界面和数据之间的实时同步,无需手动操作界面元素来更新显示。这种方式使得界面开发更加高效和灵活。
四、命令Command
在 WPF 中,命令(Command)是一种用于实现应用程序逻辑与用户界面元素交互的机制。通过命令,您可以在不直接绑定事件处理程序的情况下,将用户操作(如按钮点击、菜单选择等)与特定操作或逻辑关联起来,实现解耦合和重用性。
以下是一些关于 WPF 中命令的重要概念:
-
内置命令:WPF 提供了一些内置的命令,如
ApplicationCommands
、ComponentCommands
、NavigationCommands
等,用于处理常见的用户操作。 -
自定义命令:您可以创建自定义的命令(实现
ICommand
接口),以便在应用程序中定义和处理特定的用户操作。 -
命令绑定:通过命令绑定(Command Binding),您可以将命令与界面元素(如按钮、菜单项)关联起来,使用户操作能够触发相应的命令逻辑。
-
RoutedCommand:
RoutedCommand
是一种特殊类型的命令,具有路由事件处理的能力,可以在整个元素树中传播并执行。 -
RelayCommand:
RelayCommand
是一种常用的自定义命令实现,它允许将委托(Delegate)直接绑定到命令逻辑,简化了命令的使用。
通过使用命令,您可以将用户界面元素的操作与应用程序逻辑解耦合,提高代码的可维护性和重用性。命令还可以帮助您实现一致性的用户交互体验,并更好地组织和管理应用程序中的功能。
示例:
- 内置命令示例 -
ApplicationCommands
:
<Button Content="Copy" Command="ApplicationCommands.Copy"/>
<Button Content="Paste" Command="ApplicationCommands.Paste"/>
<Button Content="Cut" Command="ApplicationCommands.Cut"/>
- 自定义命令示例:
public class CustomCommand : ICommand
{
public event EventHandler CanExecuteChanged;
public bool CanExecute(object parameter)
{
return true; // 可执行逻辑
}
public void Execute(object parameter)
{
// 执行逻辑
}
}
- 命令绑定示例:
<Button Content="Save" Command="{Binding SaveCommand}"/>
RoutedCommand
示例:
public static RoutedCommand CustomCommand = new RoutedCommand();
// 在初始化时绑定命令
this.CommandBindings.Add(new CommandBinding(CustomCommand, CustomCommand_Executed, CustomCommand_CanExecute));
private void CustomCommand_Executed(object sender, ExecutedRoutedEventArgs e)
{
// 执行逻辑
}
private void CustomCommand_CanExecute(object sender, CanExecuteRoutedEventArgs e)
{
e.CanExecute = true; // 可执行逻辑
}
RelayCommand
示例(通常需要使用第三方库,如 Prism):
public class RelayCommand : ICommand
{
private Action<object> _execute;
private Func<object, bool> _canExecute;
public RelayCommand(Action<object> execute, Func<object, bool> canExecute)
{
_execute = execute;
_canExecute = canExecute;
}
public event EventHandler CanExecuteChanged;
public bool CanExecute(object parameter)
{
return _canExecute == null || _canExecute(parameter);
}
public void Execute(object parameter)
{
_execute(parameter);
}
}
以上示例展示了在 WPF 中使用内置命令、自定义命令、命令绑定、RoutedCommand
和 RelayCommand
的基本用法。这些示例可以帮助您理解命令在 WPF 中的应用和实现方式。
五、动画Animation
在 WPF 中,动画(Animation)是一种用于创建界面元素动态效果的强大工具,可以使应用程序的用户界面更加生动和吸引人。WPF 提供了丰富的动画功能,包括属性动画、关键帧动画、路径动画等,可以实现元素的平移、缩放、旋转、透明度变化等各种动态效果。
以下是 WPF 中常用的动画类型和示例:
- 属性动画(Property Animation):
- 通过更改界面元素的属性值来创建动画效果。例如,通过更改
Opacity
属性实现淡入淡出效果。
- 通过更改界面元素的属性值来创建动画效果。例如,通过更改
<DoubleAnimation Storyboard.TargetProperty="Opacity" To="0" Duration="0:0:1"/>
- 关键帧动画(Keyframe Animation):
- 通过定义关键帧来控制元素在不同时间点的状态,实现更复杂的动画效果。
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="Width">
<LinearDoubleKeyFrame KeyTime="0:0:0" Value="100"/>
<LinearDoubleKeyFrame KeyTime="0:0:1" Value="200"/>
</DoubleAnimationUsingKeyFrames>
- 路径动画(Path Animation):
- 将元素沿着指定路径进行移动,实现曲线运动等效果。
<PathGeometry x:Key="PathData">
<PathFigure StartPoint="0,0">
<PolyBezierSegment Points="50,0 50,50 100,100"/>
</PathFigure>
</PathGeometry>
<PathAnimationUsingPath Storyboard.TargetProperty="Canvas.Left" PathGeometry="{StaticResource PathData}" Duration="0:0:1"/>
- 触发器动画(Trigger Animation):
- 根据事件触发动画效果,如鼠标悬停、按钮点击等。
<Style.Triggers>
<EventTrigger RoutedEvent="Button.Click">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="Width" To="200" Duration="0:0:1"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Style.Triggers>
通过使用这些不同类型的动画,在 WPF 应用程序中可以轻松实现各种各样的动态效果,提升用户体验和界面交互性。
六、Prism
简介
Prism(也称为 Prism Library for WPF)是一个由微软模式和实践团队开发的开源框架,旨在帮助开发人员构建模块化、可扩展和易于维护的 WPF 和 UWP 应用程序。Prism 提供了一套工具和库,支持开发人员遵循 MVVM(Model-View-ViewModel)设计模式,实现松耦合的应用程序架构。
以下是 Prism 框架的一些主要特点和功能:
-
模块化设计:
- Prism 支持将应用程序拆分为独立的模块,每个模块都可以包含自己的视图、视图模型和服务,从而实现更好的代码组织和可扩展性。
-
MVVM 支持:
- Prism 鼓励使用 MVVM 模式来分离应用程序的业务逻辑和界面呈现,通过绑定和命令来实现视图与视图模型之间的通信。
-
导航和区域管理:
- Prism 提供了强大的导航和区域管理功能,允许开发人员动态加载和切换视图,实现更灵活的用户界面。
-
命令管理:
- Prism 支持命令模式,包括委托命令(DelegateCommand)和复合命令(CompositeCommand),用于处理用户交互和操作。
-
事件聚合器:
- Prism 的事件聚合器允许不同模块之间进行松耦合的通信,实现模块之间的解耦和消息传递。
-
状态管理:
- Prism 提供了状态管理机制,帮助开发人员管理应用程序的状态和数据,确保应用程序的一致性和可维护性。
通过使用 Prism 框架,开发人员可以更加高效地构建现代化的 WPF 和 UWP 应用程序,实现良好的代码组织、可测试性和可扩展性。Prism 的设计理念和功能使得开发人员能够专注于业务逻辑的实现,同时提高了应用程序的质量和可维护性。
区域管理
在 Prism 中,区域管理(Region Management)是一种重要的机制,用于帮助开发人员在 WPF 或 UWP 应用程序中动态加载、显示和管理视图(Views)。通过区域管理,开发人员可以将界面分割成不同的区域,每个区域可以容纳不同的视图,实现模块化设计和灵活的界面布局。
以下是 Prism 中区域管理的一些关键概念和作用:
-
定义区域:
- 在 XAML 中可以使用
prism:RegionManager.RegionName
属性来定义一个区域,指定一个容器(如ContentControl
)作为一个区域,用于显示动态加载的视图。
- 在 XAML 中可以使用
-
注册视图到区域:
- 在模块初始化时,可以使用
IRegionManager.RegisterViewWithRegion
方法将特定的视图注册到指定的区域中,实现视图与区域的关联。
- 在模块初始化时,可以使用
-
动态加载视图:
- 通过区域管理器,开发人员可以动态加载视图到指定的区域中,实现按需显示不同的视图内容,从而实现界面的动态性和灵活性。
-
区域通信:
- 区域管理也提供了一种机制来实现不同区域之间的通信和交互,使得模块之间可以进行解耦合的通信和数据传递。
-
区域适配器:
- Prism 还提供了一系列的区域适配器(Region Adapter),用于将不同类型的容器(如
ContentControl
、ItemsControl
)与区域进行关联,确保视图正确地显示在区域中。
- Prism 还提供了一系列的区域适配器(Region Adapter),用于将不同类型的容器(如
以下是一个简单的示例代码,展示了在 Prism 中如何使用区域管理器(RegionManager)来管理区域(Region):
XAML 中定义区域:
<!-- 在 XAML 中定义一个名为 "MainRegion" 的区域 -->
<ContentControl prism:RegionManager.RegionName="MainRegion"/>
在模块中注册视图到区域:
// 在模块的初始化方法中注册视图到区域
public class MyModule : IModule
{
private readonly IRegionManager _regionManager;
public MyModule(IRegionManager regionManager)
{
_regionManager = regionManager;
}
public void Initialize()
{
// 注册视图到名为 "MainRegion" 的区域
_regionManager.RegisterViewWithRegion("MainRegion", typeof(MyView));
}
}
在视图中使用区域:
public partial class MyView : UserControl
{
public MyView()
{
InitializeComponent();
// 在视图中通过 RegionManager 获取区域并添加视图
IRegion region = RegionManager.GetObservableRegion("MainRegion");
region.Add(this);
}
}
通过以上示例,您可以了解如何在 Prism 中定义和使用区域管理器来管理区域。区域管理器允许您动态地加载和管理视图,将视图与特定的区域关联起来,实现模块化设计和界面集成。这种方式使得应用程序的界面布局更加灵活和可扩展。
模块Modules
简介
在 Prism 中,Modules 功能允许开发人员将应用程序分解为独立的模块,每个模块负责实现特定的功能或业务逻辑。通过 Modules,开发人员可以实现应用程序的模块化设计,提高代码的组织性、可维护性和可扩展性。
Modules 功能特点:
-
模块定义:
- 每个模块通常由一个独立的项目或程序集表示,包含了视图、视图模型、服务和必要的资源。
-
模块加载:
- Prism 提供了机制来动态加载模块,允许应用程序在需要时按需加载模块,从而减少启动时间和内存占用。
-
模块初始化:
- 每个模块可以实现
IModule
接口,并在初始化时执行必要的操作,如注册服务、注册视图、设置导航等。
- 每个模块可以实现
-
依赖注入:
- 模块可以通过依赖注入容器(如 Prism 提供的 Unity 容器)来解决依赖关系,实现组件之间的松耦合。
-
区域管理:
- 模块可以定义自己的区域(Region),并在区域中动态加载和管理视图,实现不同模块之间的界面集成和交互。
Modules 示例:
模块定义:
public class MyModule : IModule
{
private readonly IRegionManager _regionManager;
public MyModule(IRegionManager regionManager)
{
_regionManager = regionManager;
}
public void Initialize()
{
_regionManager.RegisterViewWithRegion("MainRegion", typeof(MyView));
}
}
模块加载:
protected override void ConfigureModuleCatalog(IModuleCatalog moduleCatalog)
{
moduleCatalog.AddModule<MyModule>();
}
通过 Modules 功能,开发人员可以将应用程序拆分为独立的功能单元,实现代码的分离、组织和重用,从而提高了应用程序的可维护性和扩展性。
模块注册
在 Prism 中,有几种常见的方式可以用来注册模块:
-
在代码中直接注册模块:
- 通过在应用程序的启动代码中直接注册模块,可以使用
ModuleCatalog.AddModule
方法将模块添加到模块目录中。
- 通过在应用程序的启动代码中直接注册模块,可以使用
-
使用配置文件注册模块:
- Prism 支持使用配置文件(如 app.config 或者 appsettings.json)来定义模块的信息,可以通过
ConfigurationModuleCatalog
类来加载配置文件中定义的模块信息。
- Prism 支持使用配置文件(如 app.config 或者 appsettings.json)来定义模块的信息,可以通过
-
使用目录模块目录注册模块:
- 使用
DirectoryModuleCatalog
类可以从指定的目录加载模块,将目录中的模块自动注册到模块目录中。
- 使用
-
使用 XAML 注册模块:
- 在 XAML 中使用
ModuleCatalog
标记来定义和注册模块。
- 在 XAML 中使用
-
通过依赖注入容器注册模块:
- 可以通过依赖注入容器(如 Unity 容器)来注册模块,将模块作为服务进行注册,然后在需要时进行解析和初始化。
-
在代码中直接注册模块:
protected override void RegisterTypes(IContainerRegistry containerRegistry)
{
containerRegistry.Register<IMyService, MyService>();
}
protected override void ConfigureModuleCatalog(IModuleCatalog moduleCatalog)
{
moduleCatalog.AddModule<MyModule>();
}
- 使用配置文件注册模块:
protected override void ConfigureModuleCatalog(IModuleCatalog moduleCatalog)
{
var configurationModuleCatalog = new ConfigurationModuleCatalog();
moduleCatalog.AddCatalog(configurationModuleCatalog);
}
- 使用目录模块目录注册模块:
protected override IModuleCatalog CreateModuleCatalog()
{
var directoryCatalog = new DirectoryModuleCatalog() { ModulePath = @".\Modules" };
return directoryCatalog;
}
- 使用 XAML 注册模块:
<prism:PrismApplication xmlns:prism="http://prismlibrary.com/">
<prism:PrismApplication.Resources>
<prism:ModuleCatalog>
<prism:ModuleInfo Ref="ModuleA.dll" />
<prism:ModuleInfo Ref="ModuleB.dll" />
</prism:ModuleCatalog>
</prism:PrismApplication.Resources>
</prism:PrismApplication>
- 通过依赖注入容器注册模块:
public class Bootstrapper : PrismApplication
{
protected override void RegisterTypes(IContainerRegistry containerRegistry)
{
containerRegistry.Register<IMyService, MyService>();
}
protected override void InitializeModules()
{
var myModule = Container.Resolve<MyModule>();
myModule.Initialize();
}
}
导航Navigation
简介
Prism 中的导航管理是指一种机制,用于管理应用程序中不同视图(Views)之间的导航和页面跳转。通过 Prism 的导航管理,开发人员可以实现在应用程序中动态加载、显示和切换不同的视图,实现复杂的页面导航逻辑和用户交互体验。
以下是 Prism 中导航管理的一些关键特点和作用:
-
视图导航:
- Prism 提供了一系列的导航方法,如
NavigateAsync
、GoBackAsync
等,用于在不同视图之间进行导航和页面跳转。
- Prism 提供了一系列的导航方法,如
-
参数传递:
- 可以通过导航参数来向目标视图传递数据,实现页面间的数据交互和传递。
-
ViewModel 导航:
- Prism 的导航管理支持 ViewModel 导航,即可以通过 ViewModel 来触发导航操作,实现视图和视图模型之间的解耦合。
-
导航回退:
- Prism 提供了回退导航的功能,允许用户返回到上一个页面或者指定的页面。
-
页面堆栈管理:
- Prism 中的导航管理会维护一个页面堆栈,用于记录用户导航的历史记录,方便用户在需要时进行回退操作。
-
事件通知:
- Prism 的导航管理器会触发一系列的事件,如
Navigated
、NavigatingTo
等,可以在这些事件中执行特定的操作。
- Prism 的导航管理器会触发一系列的事件,如
示例
首先,您需要一个实现了 INavigationAware
接口的视图模型。这个接口定义了一些方法,用于响应导航事件。
using Prism.Mvvm;
using Prism.Regions;
using System;
public class ViewAViewModel : BindableBase, INavigationAware
{
public bool IsNavigationTarget(NavigationContext navigationContext)
{
// 实现该方法以适应不同的导航目标
}
public void OnNavigatedFrom(NavigationContext navigationContext)
{
// 处理视图离开时的逻辑
}
public void OnNavigatedTo(NavigationContext navigationContext)
{
// 处理视图到达时的逻辑
}
}
然后,在您的视图中,您可以使用 INavigationService
接口来触发导航操作。
using Prism.Mvvm;
using Prism.Regions;
using System;
using System.Windows;
using System.Windows.Controls;
public class ViewA : UserControl, INavigationAware
{
private readonly INavigationService _navigationService;
public ViewA(INavigationService navigationService)
{
_navigationService = navigationService;
}
public void OnNavigatedFrom(NavigationContext navigationContext)
{
// 处理视图离开时的逻辑
}
public bool IsNavigationTarget(NavigationContext navigationContext)
{
// 实现该方法以适应不同的导航目标
}
public void OnNavigatedTo(NavigationContext navigationContext)
{
// 处理视图到达时的逻辑
}
private void NavigateToViewB()
{
_navigationService.RequestNavigate("MainRegion", "ViewB");
}
}
NavigationParameters
NavigationParameters
是 Prism 框架中用于在视图导航中传递参数的类。通过 NavigationParameters
,开发人员可以在导航不同视图之间传递数据和信息,实现页面间的数据交互和传递。
主要作用:
- 传递导航参数:
NavigationParameters
允许开发人员在视图导航时携带和传递参数,从而实现页面间数据的传递和共享。
示例用法:
// 创建一个 NavigationParameters 实例,并添加参数
var parameters = new NavigationParameters();
parameters.Add("key", "value");
// 在导航时传递参数
_navigationService.NavigateAsync("Page2", parameters);
在上面的示例中,首先创建了一个 NavigationParameters
实例,并通过 Add
方法向其中添加了一个键值对参数。随后,在导航时将这个 NavigationParameters
实例传递给 _navigationService.NavigateAsync
方法,从而在页面导航过程中传递参数。
通过使用 NavigationParameters
,开发人员可以方便地在 Prism 应用程序中实现不同视图间的数据传递,帮助实现页面间的解耦合和数据交互。
BindableBase
BindableBase
是 Prism 框架中提供的一个基类,用于实现属性更改通知(Property Change Notification)。在 MVVM 模式中,视图模型(ViewModel)通常需要通知视图(View)在属性值发生变化时进行更新,而 BindableBase
提供了便捷的方式来实现这一功能。
- 属性更改通知:
BindableBase
中包含了实现INotifyPropertyChanged
接口的代码,使得继承自BindableBase
的类可以轻松地通知视图层属性值的变化。
示例用法:
public class MyViewModel : BindableBase
{
private string _name;
public string Name
{
get { return _name; }
set { SetProperty(ref _name, value); }
}
}
在上面的示例中,MyViewModel
类继承自 BindableBase
,通过调用 SetProperty
方法来设置属性值,并在值发生变化时自动触发属性更改通知。这样可以确保视图能够及时更新显示的数据。
IConfirmNavigationRequest
IConfirmNavigationRequest
是 Prism 框架中的一个接口,用于在导航发生之前进行确认操作。当视图(View)实现了 IConfirmNavigationRequest
接口时,Prism 在导航到该视图之前会调用视图的 ConfirmNavigationRequest
方法,以便视图可以执行必要的确认逻辑。
主要作用:
- 确认导航请求:允许视图在导航到其他页面之前执行确认操作,例如提示用户保存未保存的更改或验证导航的条件。
示例代码:
public class MyViewModel : BindableBase, IConfirmNavigationRequest
{
public void ConfirmNavigationRequest(NavigationContext navigationContext, Action<bool> continuationCallback)
{
// 执行确认逻辑
bool canNavigate = CheckIfCanNavigate(); // 检查是否可以导航
// 调用 continuationCallback 通知 Prism 是否继续导航
continuationCallback(canNavigate);
}
}
在上面的示例中,MyViewModel
实现了 IConfirmNavigationRequest
接口,并在 ConfirmNavigationRequest
方法中执行了确认逻辑。通过调用 continuationCallback
来通知 Prism 是否继续导航。如果 canNavigate
为 true
,则继续导航;如果为 false
,则取消导航操作。
通过实现 IConfirmNavigationRequest
接口,开发人员可以在视图导航发生之前进行必要的确认操作,从而控制导航的流程和逻辑。
IRegionNavigationJournal
IRegionNavigationJournal
接口是 Prism 中用于管理区域导航历史记录的接口。通过 IRegionNavigationJournal
,开发人员可以跟踪和管理特定区域(Region)中视图导航的历史记录,包括导航前进、后退、清除等操作。
主要作用:
- 导航历史记录:
IRegionNavigationJournal
接口定义了一系列方法和属性,用于管理区域中视图导航的历史记录,允许开发人员控制和操作导航历史。
一些常用方法和属性:
GoBack()
:导航到上一个视图。GoForward()
:导航到下一个视图。Clear()
:清除导航历史记录。CanGoBack
:获取一个值,指示是否可以执行导航到上一个视图的操作。CanGoForward
:获取一个值,指示是否可以执行导航到下一个视图的操作。
示例用法:
// 在 ViewModel 中通过注入或赋值获得 IRegionNavigationJournal 实例
private IRegionNavigationJournal _journal;
// 后退到上一个视图
_journal.GoBack();
// 清除导航历史记录
_journal.Clear();
通过使用 IRegionNavigationJournal
接口,开发人员可以在 Prism 应用程序中更加灵活和精确地管理区域中的导航历史记录,实现定制化的导航控制和用户体验。
七、对话Dialog
简介
在 Prism 中,对话服务(Dialog Service)是一种用于管理对话框和弹出窗口的服务,用于实现应用程序中的模态对话框和非模态对话框。通过对话服务,开发人员可以方便地显示各种类型的对话框,并与用户进行交互。
在软件开发中,模态对话框(Modal Dialog)和非模态对话框(Modeless Dialog)是两种常见的对话框类型,用于与用户进行交互和展示信息。它们之间的主要区别在于对话框的行为和用户交互方式。
- 模态对话框示例:确认对话框、警告框、输入框等需要用户立即响应或提供信息的情况。
- 非模态对话框示例:工具栏、侧边栏、状态栏等可以在用户继续操作应用程序的同时提供额外功能或信息的情况。
主要功能和特点:
-
显示对话框:对话服务提供了方法来显示各种类型的对话框,包括模态对话框和非模态对话框。
-
参数传递:开发人员可以通过对话服务向对话框传递参数,以便在对话框中使用。
-
异步操作:对话服务通常支持异步操作,允许开发人员等待用户对对话框的响应。
-
灵活定制:开发人员可以根据需求定制对话框的外观和行为,以满足特定的应用程序需求。
-
解耦合:通过使用对话服务,可以实现视图层和业务逻辑层的解耦合,使得对话框的显示和交互逻辑与具体视图分离。
示例用法:
以下是一个简单的示例,展示了如何在 Prism 中使用对话服务(Dialog Service)显示模态对话框和非模态对话框:
模态对话框视图 DialogView.xaml:
<StackPanel>
<TextBlock Text="{Binding Message}" />
<Button Content="OK" Command="{Binding CloseDialogCommand}" />
</StackPanel>
模态对话框视图模型 DialogViewModel.cs:
public class DialogViewModel : BindableBase, IDialogAware
{
public string Message { get; set; }
public DelegateCommand CloseDialogCommand { get; }
public event Action<IDialogResult> RequestClose;
public DialogViewModel()
{
CloseDialogCommand = new DelegateCommand(CloseDialog);
}
private void CloseDialog()
{
RequestClose?.Invoke(new DialogResult(ButtonResult.OK));
}
// 实现 IDialogAware 接口的方法
}
使用对话服务显示模态对话框:
_dialogService.ShowDialog("DialogView", new DialogParameters { { "Message", "Hello, this is a modal dialog!" } }, result =>
{
if (result.Result == ButtonResult.OK)
{
// 处理对话框返回结果
}
});
使用对话服务显示非模态对话框:
_dialogService.Show("NotificationView", new DialogParameters { { "Message", "Hello, this is a notification!" });
通过使用 Prism 中的对话服务,开发人员可以轻松地实现应用程序中的各种对话框和弹出窗口,提供更好的用户体验和交互。
IDialogAware
IDialogAware
是 Prism 框架中定义的一个接口,用于实现对话框(Dialog)的交互逻辑。在 Prism 中,对话框通常用于显示模态或非模态的弹出窗口,而实现 IDialogAware
接口的类可以定义对话框的行为和响应。
主要作用:
- 对话框交互:
IDialogAware
接口定义了一系列方法,用于控制对话框的显示、关闭以及与对话框交互的逻辑。
示例代码:
public class MyDialogViewModel : BindableBase, IDialogAware
{
public string Title => "My Dialog";
public event Action<IDialogResult> RequestClose;
public bool CanCloseDialog()
{
return true; // 可以关闭对话框
}
public void OnDialogClosed()
{
// 对话框关闭时执行操作
}
public void OnDialogOpened(IDialogParameters parameters)
{
// 对话框打开时执行操作,可以处理传入的参数
}
}
在上面的示例中,MyDialogViewModel
类实现了 IDialogAware
接口,并提供了 CanCloseDialog
、OnDialogClosed
和 OnDialogOpened
方法来控制对话框的行为。通过实现这些方法,可以定义对话框打开、关闭和交互时的逻辑。
八、订阅EventAggergator
在 Prism 中,订阅是一种常见的事件处理机制,用于实现模块之间的通信和解耦。Prism 提供了事件聚合器(Event Aggregator)来实现事件的订阅和发布,允许模块之间进行松耦合的通信。
主要作用:
- 解耦合:通过事件订阅和发布,模块之间可以实现解耦合,避免直接依赖于彼此的实现细节。
示例用法:
- 定义事件类:
public class MyEvent : PubSubEvent<string> { }
- 订阅事件:
_eventAggregator.GetEvent<MyEvent>().Subscribe(OnMyEventReceived);
- 处理事件:
private void OnMyEventReceived(string message)
{
// 处理接收到的事件
}
- 发布事件:
_eventAggregator.GetEvent<MyEvent>().Publish("Hello, Prism!");
- 解约事件:
_eventAggregator.GetEvent<MyEvent>().Unsubscribe(OnMyEventReceived);
在上面的示例中,通过定义一个 MyEvent
类继承自 PubSubEvent
,表示一个特定的事件。然后在需要订阅该事件的地方,使用 Subscribe
方法订阅事件,并在回调方法中处理接收到的事件。最后,通过 Publish
方法发布事件,通知所有订阅者。
通过使用 Prism 中的事件聚合器,开发人员可以实现模块之间的松耦合通信,提高代码的可维护性和灵活性。
标签:对话框,示例,视图,Prism,模块,WPF,public From: https://www.cnblogs.com/Firepad-magic/p/18162209