【6月日新计划21】WPF入门-Region And Transitioner
在prism當中,我們可以讓一個頁面不在顯示固定的內容,而這種概念就變成了區域。將頁面的顯示部分分成幾個區域,每個區域都可以動態顯示一些功能。
1. Prism
1.NuGet Install
2.Import
xmlns:prism="http://prismlibrary.com/"
2. Region
1.創建region,通過導航欄按鈕,區域內顯示不同的內容
<DockPanel>
<ListBox x:Name="MenuBar"
Margin="0,16,0,16"
AutomationProperties.Name="DemoPagesListBox"
ItemsSource="{Binding MenuBars}"
Style="{StaticResource MaterialDesignNavigationPrimaryListBox}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<i:InvokeCommandAction Command="{Binding NavigateCommand}"
CommandParameter="{Binding ElementName=MenuBar, Path=SelectedItem}" />
</i:EventTrigger>
</i:Interaction.Triggers>
<ListBox.Resources>
<Style BasedOn="{StaticResource MaterialDesignScrollBarMinimal}"
TargetType="ScrollBar" />
</ListBox.Resources>
<ListBox.ItemTemplate>
<DataTemplate DataType="domain:DemoItem">
<StackPanel Orientation="Horizontal">
<materialDesign:PackIcon Width="20"
Height="20"
Margin="10,4,0,4"
Kind="{Binding Icon}" />
<TextBlock Margin="10,5,0,4"
AutomationProperties.AutomationId="DemoItemPage"
FontSize="15"
Text="{Binding Title}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<StackPanel>
<ContentControl prism:RegionManager.RegionName="{x:Static exe:PrismManager.MainWindowRegionName}" />
</StackPanel>
</DockPanel>
2.便於維護,所有region統一管理
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace BlankApp1.Extensions
{
public static class PrismManager
{
public static readonly string MainWindowRegionName = "MainWindowRegion";
public static readonly string SettingWindowRegionName = "SettingWindowRegion";
}
}
3.將顯示的view進行註冊
現在app.xaml.cs中將view和viewmodel進行綁定
protected override void RegisterTypes(IContainerRegistry containerRegistry)
{
//將host進行註冊
containerRegistry.GetContainer().Register<HttpRestClient>(made: Parameters.Of.Type<string>(serviceKey: "url"));
containerRegistry.GetContainer().RegisterInstance(@"https://api.openweathermap.org/", serviceKey: "url");
//將呼叫方法的service進行註冊
containerRegistry.Register<IWeatherService, WeatherService>();
//將view和viewModel捆綁,已經註冊。
containerRegistry.RegisterForNavigation<ToDoView,ToDoViewModel>();
containerRegistry.RegisterForNavigation<OlkView,OLKViewModel>();
containerRegistry.RegisterForNavigation<IndexView,IndexViewModel>();
containerRegistry.RegisterForNavigation<ConfigView,ConfigViewModel>();
}
4.MainWindowViewModel裡面實現方法
using BlankApp1.Common.Models;
using BlankApp1.Extensions;
using Prism.Commands;
using Prism.Mvvm;
using Prism.Regions;
using Prism.Services.Dialogs;
using System;
using System.Collections.ObjectModel;
namespace BlankApp1.ViewModels
{
public class MainWindowViewModel : BindableBase
{
private readonly IRegionManager _regionManager;
private IRegionNavigationJournal journal;
private ObservableCollection<MenuBar> menuBars;
public ObservableCollection<MenuBar> MenuBars
{
get { return menuBars; }
set { menuBars = value; RaisePropertyChanged(); }
}
public DelegateCommand<MenuBar> NavigateCommand { get; set; }
public DelegateCommand BackCommand { get; set; }
public DelegateCommand ForwardCommand { get; set; }
public MainWindowViewModel(IRegionManager regionManager)
{
_regionManager = regionManager;
MenuBars = new ObservableCollection<MenuBar>();
CreateMenuBars();
NavigateCommand = new DelegateCommand<MenuBar>(Navigate);
BackCommand = new DelegateCommand(() =>
{
if (journal!= null && journal.CanGoBack) {
journal.GoBack();
}
});
ForwardCommand = new DelegateCommand(() =>
{
if(journal != null && journal.CanGoForward) {
journal.GoForward();
}
});
}
private void Navigate(MenuBar menuBar)
{
if (menuBar == null || string.IsNullOrEmpty(menuBar.NameSpaces))
{
return;
}
_regionManager.Regions[PrismManager.MainWindowRegionName].RequestNavigate(menuBar.NameSpaces, back =>
{
journal = back.Context.NavigationService.Journal;
});
}
void CreateMenuBars()
{
MenuBars.Add(new MenuBar() { Icon = "Home", Title = "Home", NameSpaces = "IndexView" });
MenuBars.Add(new MenuBar() { Icon = "NotebookOutline", Title = "ToDoList", NameSpaces = "ToDoView" });
MenuBars.Add(new MenuBar() { Icon = "NotebookEditOutline", Title = "OLK", NameSpaces = "OlkView" });
MenuBars.Add(new MenuBar() { Icon = "WeatherFlash", Title = "Weather", NameSpaces = "WeatherView" });
MenuBars.Add(new MenuBar() { Icon = "Cog", Title = "Config", NameSpaces = "ConfigView" });
}
}
}
3. Transitioner
xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
xmlns:md="http://materialdesigninxaml.net/winfx/xaml/themes"
1.比如登錄和註冊就可以使用Transitioner
//用來提示密碼錯誤,登錄失敗的信息
<md:Snackbar
x:Name="LoginSnakeBar"
Grid.ColumnSpan="2"
Panel.ZIndex="1"
MessageQueue="{md:MessageQueue}" />
<md:Transitioner Grid.Column="1" SelectedIndex="{Binding SelectIndex, FallbackValue=0}">
<md:TransitionerSlide>
<DockPanel Margin="15" VerticalAlignment="Center">
<TextBlock
Margin="0,10"
DockPanel.Dock="Top"
FontSize="22"
FontWeight="Bold"
Text="欢迎使用" />
<TextBox
Margin="0,10"
md:HintAssist.Hint="请输入账号"
DockPanel.Dock="Top"
Text="{Binding UserName}" />
<PasswordBox
Margin="0,10"
md:HintAssist.Hint="请输入密码"
pass:PassWordExtensions.PassWord="{Binding PassWord, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
DockPanel.Dock="Top">
<i:Interaction.Behaviors>
<pass:PasswordBehavior />
</i:Interaction.Behaviors>
</PasswordBox>
<Button
Command="{Binding ExecuteCommand}"
CommandParameter="Login"
Content="登录系统"
DockPanel.Dock="Top" />
<DockPanel Margin="0,5" LastChildFill="False">
<TextBlock Text="注册账号">
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseLeftButtonDown">
<i:InvokeCommandAction Command="{Binding ExecuteCommand}" CommandParameter="ResgiterPage" />
</i:EventTrigger>
</i:Interaction.Triggers>
</TextBlock>
<TextBlock DockPanel.Dock="Right" Text="忘记密码?" />
</DockPanel>
</DockPanel>
</md:TransitionerSlide>
<md:TransitionerSlide>
<DockPanel Margin="15" VerticalAlignment="Center">
<TextBlock
Margin="0,10"
DockPanel.Dock="Top"
FontSize="22"
FontWeight="Bold"
Text="注册账号" />
<TextBox
Margin="0,5"
md:HintAssist.Hint="请输入用户名"
DockPanel.Dock="Top"
Text="{Binding UserDto.Account}" />
<TextBox
Margin="0,5"
md:HintAssist.Hint="请输入账号"
DockPanel.Dock="Top"
Text="{Binding UserDto.UserName}" />
<PasswordBox
Margin="0,5"
md:HintAssist.Hint="请输入密码"
pass:PassWordExtensions.PassWord="{Binding UserDto.PassWord, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
DockPanel.Dock="Top">
<i:Interaction.Behaviors>
<pass:PasswordBehavior />
</i:Interaction.Behaviors>
</PasswordBox>
<PasswordBox
Margin="0,5"
md:HintAssist.Hint="请再次输入密码"
pass:PassWordExtensions.PassWord="{Binding UserDto.NewPassWord, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
DockPanel.Dock="Top">
<i:Interaction.Behaviors>
<pass:PasswordBehavior />
</i:Interaction.Behaviors>
</PasswordBox>
<Button
Command="{Binding ExecuteCommand}"
CommandParameter="Resgiter"
Content="注册账号"
DockPanel.Dock="Top" />
<Button
Margin="0,10"
Command="{Binding ExecuteCommand}"
CommandParameter="Return"
Content="返回登录"
DockPanel.Dock="Top"
Style="{StaticResource MaterialDesignOutlinedButton}" />
</DockPanel>
</md:TransitionerSlide>
</md:Transitioner>
2.viewmodel
using MyToDo.Extensions;
using MyToDo.Service;
using MyToDo.Shared.Dtos;
using Prism.Commands;
using Prism.Events;
using Prism.Mvvm;
using Prism.Services.Dialogs;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MyToDo.ViewModels.Dialogs
{
public class LoginViewModel : BindableBase, IDialogAware
{
public LoginViewModel(IEventAggregator aggregator)
{
ExecuteCommand = new DelegateCommand<string>(Execute);
this.aggregator = aggregator;
}
public string Title { get; set; } = "ToDo";
public event Action<IDialogResult> RequestClose;
public bool CanCloseDialog()
{
return true;
}
public void OnDialogClosed()
{
LoginOut();
}
public void OnDialogOpened(IDialogParameters parameters)
{
}
#region Login
private int selectIndex;
public int SelectIndex
{
get { return selectIndex; }
set { selectIndex = value; RaisePropertyChanged(); }
}
public DelegateCommand<string> ExecuteCommand { get; private set; }
private string passWord;
private readonly ILoginService loginService;
private readonly IEventAggregator aggregator;
private void Execute(string obj)
{
switch (obj)
{
case "Login": Login(); break;
case "LoginOut": LoginOut(); break;
case "Resgiter": Resgiter(); break;
case "ResgiterPage": SelectIndex = 1; break;
case "Return": SelectIndex = 0; break;
}
}
async void Login()
{
//呼叫api,登錄校驗
xxxxxxx
if (loginResult != null && loginResult.Status)
{
RequestClose?.Invoke(new DialogResult(ButtonResult.OK));
}
else
{
//登录失败提示...
aggregator.SendMessage(loginResult.Message, "Login");
}
}
private async void Resgiter()
{
//呼叫api,進行註冊
xxxxxxx
aggregator.SendMessage("注册成功", "Login");
//注册成功,返回登录页页面
SelectIndex = 0;
}
void LoginOut()
{
RequestClose?.Invoke(new DialogResult(ButtonResult.No));
}
}
}
又回歸到前面的內容DialogContent
namespace BlankApp1.Views.Dialog
{
/// <summary>
/// LoginView.xaml 的互動邏輯
/// </summary>
public partial class LoginView : UserControl
{
public LoginView(IEventAggregator aggregator)
{
InitializeComponent();
aggregator.RegisterMessage(arg =>
{
LoginSnakeBar.MessageQueue.Enqueue(arg.Message);
}, "Login");
}
}
}