【6月日新计划21】WPF入门-Region And Transitioner

264 阅读2分钟

【6月日新计划21】WPF入门-Region And Transitioner

在prism當中,我們可以讓一個頁面不在顯示固定的內容,而這種概念就變成了區域。將頁面的顯示部分分成幾個區域,每個區域都可以動態顯示一些功能。

1. Prism

1.NuGet Install

图片.png

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");
        }
    }
}