Detailed WPF Prims framework

foreword

The Prims framework is a framework of WPF, which is characterized by integrating our usual development modes and encapsulating many commonly used functions. For example, message notification, routing navigation, and Model binding.

Basic use of Prism

source

WPF-Prism8.0 Core Tutorial (Public Welfare)

Prism choice, DryIoc or Unity

According to the description on the Internet, DryIoc is more efficient, but I see that among the number of Nuget downloads, the number of Unity downloads is much higher than that of DryIoc. I haven’t used it much, so use DryIoc as recommended.

Performance comparison between Unity and DryIocinsert image description here

Prism basic framework construction

insert image description here
In App.xaml, modify

App.xaml.cs

    /// <summary>
    /// 继承prism的PrismApplication类
    /// </summary>
    public partial class App : PrismApplication
    {
    
    
        //设置启动页
        protected override Window CreateShell()
        {
    
    
            //启动页为MainWindow
            return Container.Resolve<MainWindow>();

        }

        protected override void RegisterTypes(IContainerRegistry containerRegistry)
        {
    
    
            
        }
    }

App.xaml

<!--xmlns:prism,引入prism命名空间-->
<!--prism:PrismApplication,继承prism下的PrismApplication类-->
<!--去掉StartupUrl,保证只有一个启动页-->
<prism:PrismApplication x:Class="PrismTest.App"
                        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                        xmlns:local="clr-namespace:PrismTest"
                        xmlns:prism="http://prismlibrary.com/">
</prism:PrismApplication>

Prism Updates

Correspondence between View and ViewModel

insert image description here
View and ViewModel can be automatically bound, and the naming requirement is .

  • Model:NameViewModel
  • View:Name/NameView (both are available)
    add the following code in View
xmlns:prism引入命名空间
prism:ViewModel设置自动绑定
可以不加,默认进行了绑定。
<Window ...
        xmlns:prism="http://prismlibrary.com/"
        prism:ViewModelLocator.AutoWireViewModel="True">

You can also force binding in App.xaml

Unbind in original file

app.xaml

        /// <summary>
        /// 路由管理
        /// </summary>
        /// <param name="containerRegistry"></param>
        protected override void RegisterTypes(IContainerRegistry containerRegistry)
        {
            //通过RegisterForNavigation进行强行绑定,强行让ViewA和ViewAViewModel进行绑定
            containerRegistry.RegisterForNavigation<ViewA, ViewAViewModel>();
            
        }

Parameter dynamic update

	//继承BindableBase接口
    public class MyListBoxItem : BindableBase
    {
    
    
        private string text;
        public string Text
        {
    
    
            get {
    
     return text; }
            set {
    
      SetProperty(ref text, value);}//此方法为Prism提供
        }
    }

You can enter propp plus tab key, template input, submit code writing efficiency

insert image description here

function dynamic binding

Function dynamic binding needs to use the delegate type, if the delegate does not understand, you need to go back and find out by yourself

viewModel


//声明委托
public DelegateCommand TestBtn {
    
     get; set; }
//构造函数
public MainWindowViewModel()
{
    
    
    //实例化委托
    TestBtn = new DelegateCommand(() =>
    {
    
    
        //执行内容
    });
}

view

使用Command引用委托,如果没有TestBtn委托也不报错
        <Button Content="测试方法"
                FontSize="100"
                Grid.Row="1"
                Command="{Binding TestBtn}"/>

Prism new project template

Install in extensions, manage extensions
insert image description here
We will have a Prism template framework when we create a new program

insert image description here

When using it, you will be prompted what container to use, and the DryIoc container is recommended here

insert image description here

The new file path is as follows

insert image description here

region

Prism continues to divide the interface into multiple Regions, and adds elements to the Regions.

insert image description here

The difference with WPF User Components.

  • Region is equivalent to dividing an empty area, and WPF is an area with content.
  • Region is equivalent to the superior of WPF user control, used to contain user control

use case

MainWindow.xaml

    <Grid>
        <!--声明Region,名称为ContentRegion,使用名称来进行注入-->
        <ContentControl prism:RegionManager.RegionName="ContentRegion" />
        
    </Grid>

UserControl1.xaml, for user controls placed on the Region

    <Grid>
        <TextBlock  Text="我是用户控件" FontSize="100"/>
    </Grid>

MainWindowViewModel.xaml

        //注册regionManager控件
        private readonly IRegionManager _regionManager;

        public MainWindowViewModel(IRegionManager regionManager)
        {
    
    
            this._regionManager = regionManager;
			//ContentRegion是窗口已声明的Region,使用字符串进行弱绑定
            regionManager.RegisterViewWithRegion("ContentRegion",typeof(UserControl1));
        }

generate effect
insert image description here

Test for limited space

insert image description here

<Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition />
            <ColumnDefinition />
        </Grid.ColumnDefinitions>
        <!--声明Region,名称为ContentRegion,使用名称来进行注入-->
        <ContentControl prism:RegionManager.RegionName="ContentRegion" />
        
    </Grid>

achieve effect

insert image description here

news subscription

Message subscription is valid if it is subscribed first and then published, and it is invalid if it is published first and then subscribed.

How to use message subscription

 public class MainWindowViewModel : BindableBase
    {
    
    
        private string _title = "Prism Application";
                //声明委托
        public DelegateCommand TestBtn {
    
     get; set; }
        public DelegateCommand SendCommand {
    
     get; set; }
        private readonly IEventAggregator _eventAggregator;
        public string Title
        {
    
    
            get {
    
     return _title; }
            set {
    
     SetProperty(ref _title, value); }
        }
        //构造函数
        public MainWindowViewModel(IRegionManager regionManager,IEventAggregator eventAggregator)
        {
    
    

            //实例化委托
            //订阅
            TestBtn = new DelegateCommand(() =>
            {
    
    
                eventAggregator.GetEvent<MessageEvent>().Subscribe(OnMessageRecevied);
            });
			//发送
            SendCommand = new DelegateCommand(() =>
            {
    
    
            	//执行参数
                eventAggregator.GetEvent<MessageEvent>().Publish("Hello Event");
            });
            
            this._eventAggregator = eventAggregator;
        }


        public void OnMessageRecevied(string msg)
        {
    
    
            Title += msg + "\r\n";
        }


        

		//消息订阅类
        public class MessageEvent: PubSubEvent<string> {
    
    
        }
    }

Note
eventAggregator.GetEvent<MessageEvent>(). MessageEvent is defined by ourselves, which is equivalent to the subscribed message topic.

eventAggregator.GetEvent().

  • Subscribe(OnMessageRecevied);
    • OnMessageRecevied is the processing function
  • Publish(“Hello Event”)
    • "Hello Event" is an input parameter, because OnMessageRecevied(string msg)

unsubscribe

eventAggregator.GetEvent<MessageEvent>().Unsubscribe(OnMessageRecevied);

Recommendations

  • Note that this is used globally, so it is generally used for page communication
    • For example: AView. I just use AViewEvent. One page corresponds to one event notification.
  • Since the parameters brought in are not necessarily, we can set Dictionary as the input parameter, and set the corresponding function through key value filtering. Pass parameters quickly through NetJson.

route navigation

Routing navigation and Region are used together and are specially used for page conversion

  • Create new switching user controls ViewA, ViewB, and ViewC. The content of ViewA, B, and C is different, so it is omitted here
    insert image description here
  • Register the page in App.xaml.cs
        /// <summary>
        /// 路由管理
        /// </summary>
        /// <param name="containerRegistry"></param>
        protected override void RegisterTypes(IContainerRegistry containerRegistry)
        {
    
    
            //将ViewA,B,C添加到导航,这样才能进行路由管理
            containerRegistry.RegisterForNavigation<ViewA>("ViewA");
            containerRegistry.RegisterForNavigation<ViewB>();
            containerRegistry.RegisterForNavigation<ViewC>();
        }

  • Add delegate event in MainView
   <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="50"/>
            <RowDefinition />
        </Grid.RowDefinitions>
        <StackPanel Orientation="Horizontal">
            <Button Content="ViewA"
                    Command="{Binding OpenACommand}" />
            <Button Content="ViewB"
                    Command="{Binding OpenBCommand}" />
            <Button Content="ViewC"
                    Command="{Binding OpenC_Command}" />
            <Button Content="上一页"
                    Command="{Binding GoBackCommand}" />
            <Button Content="下一页"
                    Command="{Binding GoForwordCommand}"/>
        </StackPanel>
        <!--这个Region是我们等会切换窗口信息的-->
        <ContentControl Grid.Row="1" prism:RegionManager.RegionName="ContentRegion" />
    </Grid>

Manage Navigation in MainiView


namespace PrismNavigation.ViewModels
{
    
    
    public class MainWindowViewModel : BindableBase
    {
    
    
        private string _title = "Prism Application";
        public string Title
        {
    
    
            get {
    
     return _title; }
            set {
    
     SetProperty(ref _title, value); }
        }

        /// <summary>
        /// 导航日志
        /// </summary>
        private IRegionNavigationJournal _journal;
        //Region,用于页面切换
        private readonly IRegionManager _regionManager;
        public DelegateCommand OpenACommand {
    
     get; set; }
        public DelegateCommand OpenBCommand {
    
     get; set; }
        public DelegateCommand OpenC_Command {
    
     get; set; }
        public DelegateCommand GoBackCommand {
    
     get; set; }
        public DelegateCommand GoForwordCommand {
    
     get; set; }


        public MainWindowViewModel(IRegionManager regionManager,IEventAggregator eventAggregator)
        {
    
    
            _regionManager = regionManager;
            OpenACommand = new DelegateCommand(OpenA);
            OpenBCommand = new DelegateCommand(OpenB);
            OpenC_Command = new DelegateCommand(OpenC);
            GoBackCommand = new DelegateCommand(GoBack);
            GoForwordCommand = new DelegateCommand(GoForword);

        }

        private void OpenA()
        {
    
    
            NavigationParameters para = new NavigationParameters
            {
    
    
                {
    
     "Value", "Hello Prism" }
            };
            //进行路由传参,ContentRegion是xmal中的Region名称,ViewA是在App.xmal中注册的名称,arg是日志回调,para是路由传递的参数
            _regionManager.RequestNavigate("ContentRegion", "ViewA", arg =>
            {
    
    
                ///获取导航日志
                _journal = arg.Context.NavigationService.Journal;
            }, para);

        }
        private void OpenB()
        {
    
    
            _regionManager.RequestNavigate("ContentRegion", "ViewB", arg =>
            {
    
    
                ///获取导航日志
                _journal = arg.Context.NavigationService.Journal;
            });

        }
        private void OpenC()
        {
    
    
            _regionManager.RequestNavigate("ContentRegion", "ViewC", arg =>
            {
    
    
                ///获取导航日志
                _journal = arg.Context.NavigationService.Journal;
            });

        }

        private void GoForword()
        {
    
    
            _journal.GoForward();
        }

        private void GoBack()
        {
    
    
            _journal.GoBack();
        }
    }
}

Route interception in ViewA

 public class ViewAViewModel :BindableBase, IConfirmNavigationRequest
    {
    
    
        private string _name;
        public string Name
        {
    
    
            get {
    
     return _name; }
            set {
    
     SetProperty(ref _name, value); }
        }


        /// <summary>
        /// IConfirmNavigationRequest的路由离开拦截,
        /// </summary>
        /// <param name="navigationContext"></param>
        /// <param name="continuationCallback"></param>
        /// <exception cref="NotImplementedException"></exception>
        public void ConfirmNavigationRequest(NavigationContext navigationContext, Action<bool> continuationCallback)
        {
    
    
            var res = true;
            if(MessageBox.Show("确认导航?","温馨提示",MessageBoxButton.YesNo) == MessageBoxResult.No)
            {
    
    
                res = false;
            }
            //如果res为true则拦截,true则放行
            continuationCallback?.Invoke(res);
        }

        /// <summary>
        /// 用于判断是否要重新创建新的事例,即是否保留之前的信息,True为重新创建。
        /// </summary>
        /// <param name="navigationContext"></param>
        /// <returns></returns>
        /// <exception cref="NotImplementedException"></exception>
        public bool IsNavigationTarget(NavigationContext navigationContext)
        {
    
    
            return true;
        }
        /// <summary>
        /// 离开页面时触发,一般用于取消事件监听
        /// </summary>
        /// <param name="navigationContext"></param>
        /// <exception cref="NotImplementedException"></exception>
        public void OnNavigatedFrom(NavigationContext navigationContext)
        {
    
    

        }
        /// <summary>
        /// 显示页面前触发,一般用于设置事件监听
        /// </summary>
        /// <param name="navigationContext"></param>
        /// <exception cref="NotImplementedException"></exception>
        public void OnNavigatedTo(NavigationContext navigationContext)
        {
    
    
            //拿到Key为Value的值,返回类型为string
            Name = navigationContext.Parameters.GetValue<string>("Value");
        }
    }

achieve effect
insert image description here

a brief introdction

  • Routing navigation is Region navigation, and WPF user controls must be added to Region before navigation can be performed
  • When registering, you can add an alias
    • containerRegistry.RegisterForNavigation<ViewA>("alias");
_regionManager.RequestNavigate("ContentRegion", "别名");//原本是ViewA的,可以替换成别名

Dialog/popup functionality

Prism encapsulates the commonly used function of the dialog box. Although it is called a dialog box, it is actually the functional effect of a pop-up window.

Implementation code

app.xaml

        /// <summary>
        /// 路由管理
        /// </summary>
        /// <param name="containerRegistry"></param>
        protected override void RegisterTypes(IContainerRegistry containerRegistry)
        {
    
    
			.......
            //这里也能起别名
            containerRegistry.RegisterDialog<MsgView,MsgViewModel>("别名");   
        }

MainViewModel uses this popup

public class MainWindowViewModel : BindableBase
    {
    
    
        private string _title = "Prism Application";
        public string Title
        {
    
    
            get {
    
     return _title; }
            set {
    
     SetProperty(ref _title, value); }
        }

        /// <summary>
        /// 导航日志
        /// </summary>
        private IRegionNavigationJournal _journal;
        private readonly IRegionManager _regionManager;
        //注册弹窗服务
        private IDialogService _dialogService;
        public DelegateCommand OpenACommand {
    
     get; set; }

		//构造函数中传入对话框
        public MainWindowViewModel(IRegionManager regionManager,IEventAggregator eventAggregator,IDialogService dialogService)
        {
    
    
            _regionManager = regionManager;
            OpenACommand = new DelegateCommand(OpenA);
            GoForwordCommand = new DelegateCommand(GoForword);
            //使用对话框
            _dialogService = dialogService;

        }

        private void OpenA()
        {
    
    
        	//对话框传递的参数
            DialogParameters param = new DialogParameters();
            param.Add("Value", "paramTest");
            //打开名为MsgView的弹窗,并传递参数
            _dialogService.Show("MsgView", param, arg =>
            {
    
    
            	//弹窗关闭的回调函数,会有参数返回
                if(arg.Result == ButtonResult.OK)
                {
    
    
                    Debug.WriteLine("调试成功");
                }
            });
        }
    }

MsgView


    <Grid Background="White">
        <Grid.RowDefinitions>
            <RowDefinition Height="30" />
            <RowDefinition />
            <RowDefinition Height="50"/>
        </Grid.RowDefinitions>
        <TextBox Grid.Row="1" Text="{Binding Title}" FontSize="20"/>
        <Label Content="{Binding Title}"/>
        <DockPanel Grid.Row="2" LastChildFill="False">
            <Button Content="取消" Width="60"
                    DockPanel.Dock="Right"
                    Command="{Binding CancelCommand}" />
            <Button Content="确定"
                    Width="60"
                    DockPanel.Dock="Right"
                    Command="{Binding SaveCommand}"/>

        </DockPanel>
    </Grid>
public class MsgViewModel :BindableBase, IDialogAware
    {
    
    

        private string _title;
        public string Title
        {
    
    
            get {
    
     return _title; }
            set {
    
     SetProperty(ref _title, value); }
        }

        /// <summary>
        /// 用于弹窗关闭的回调函数
        /// </summary>
        public event Action<IDialogResult> RequestClose;

        public DelegateCommand SaveCommand {
    
     get; set; }

        public DelegateCommand CancelCommand {
    
     get; set; }

        public MsgViewModel() {
    
    
            SaveCommand = new DelegateCommand(() =>
            {
    
    
                DialogParameters keyValuePairs = new DialogParameters();
                keyValuePairs.Add("Value", Title);
                //执行弹窗关闭,并传入回调参数
                RequestClose?.Invoke(new DialogResult(ButtonResult.OK, keyValuePairs));
                
            });

            CancelCommand = new DelegateCommand(() =>
            {
    
    
                RequestClose?.Invoke(new DialogResult(ButtonResult.No));
            });
        }

        /// <summary>
        /// 能否打开窗口
        /// </summary>
        /// <returns></returns>
        public bool CanCloseDialog()
        {
    
    
            return true;
        }
        /// <summary>
        /// 关闭的方法
        /// </summary>
        /// <exception cref="NotImplementedException"></exception>
        public void OnDialogClosed()
        {
    
    
            //throw new NotImplementedException();
        }
        /// <summary>
        /// 打开之前,接受弹窗传参
        /// </summary>
        /// <param name="parameters"></param>
        /// <exception cref="NotImplementedException"></exception>
        public void OnDialogOpened(IDialogParameters parameters)
        {
    
    
            Title = parameters.GetValue<string>("Value");
        }
    }

insert image description here

Guess you like

Origin blog.csdn.net/qq_44695769/article/details/131750480