WPF編程-Prism
世有伯樂,然後有千里馬。千里馬常有,而伯樂不常有。
一、背景
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相反,從目標到源。
不同的綁定模式:
<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 中的事件聚合器,開發人員可以實現模塊之間的松耦合通信,提高代碼的可維護性和靈活性。