本文主要讲述如何在同一个窗体内,实现不同功能模块的页面切换。
首先搭建一个简单的项目框架,然后有红和绿两个页面,ViewModels中的Base 中简单实现了ICommand 和 INotifyPropertyChanged接口
public class CommandBase : ICommand
{
public event EventHandler CanExecuteChanged;
public CommandBase(Action executeAction, Func<bool> canExcuteFunc = null)
{
this.ExecuteAction = executeAction;
this.CanExecuteFunc = canExcuteFunc;
}
public CommandBase(Action<object> executeParaAction, Func<object, bool> canExecuteParaFunc = null)
{
this.ExecuteParaAction = executeParaAction;
this.CanExecuteParaFunc = canExecuteParaFunc;
}
public bool CanExecute(object parameter=null)
{
if (parameter==null)
{
return this.CanExecuteFunc == null ? true : CanExecuteFunc.Invoke();
}
return CanExecuteParaFunc == null ? true : CanExecuteParaFunc.Invoke(parameter);
}
public void Execute(object parameter = null)
{
if (parameter == null)
{
ExecuteAction?.Invoke();
}
else
{
ExecuteParaAction?.Invoke(parameter);
}
}
public Action ExecuteAction {
get; set; }
public Func<bool> CanExecuteFunc {
get; set; }
public Action<object> ExecuteParaAction {
get; set; }
public Func<object,bool> CanExecuteParaFunc {
get; set; }
}
public class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged([CallerMemberName]string name="")
{
PropertyChanged?.Invoke(this,new PropertyChangedEventArgs(name));
}
}
利用Frame的Source 属性加载内部的控件,使用Frame的时候,用于切换的页面可以是UserControl 或者Page,如案例中使用的就是Page
实现代码如下:
<Window x:Class="WpfApp2.Views.MainView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApp2.Views"
xmlns:vm="clr-namespace:WpfApp2.ViewModels"
mc:Ignorable="d"
Title="MainView" Height="450" Width="800">
<Window.DataContext>
<vm:MainViewModel></vm:MainViewModel>
</Window.DataContext>
<DockPanel Grid.Column="0">
<StackPanel Background="LightBlue">
<RadioButton IsChecked="True" Command="{Binding ChangePageCommand}" CommandParameter="PageRedView.xaml" Content="红色" Margin="10"></RadioButton>
<RadioButton Command="{Binding ChangePageCommand}" CommandParameter="PageGreenView.xaml" Content="绿色" Margin="10"></RadioButton>
</StackPanel>
<Frame NavigationUIVisibility="Hidden" Source="{Binding PageName}"/>
</DockPanel>
</Window>
注意:这里的CommandParameter传入的是PageRedView.xaml文件
public class MainViewModel:ViewModelBase
{
private string _pageName;
public string PageName
{
get {
return _pageName; }
set {
_pageName = value; OnPropertyChanged(); }
}
public ICommand ChangePageCommand {
get; set; }
public MainViewModel()
{
ChangePageCommand = new CommandBase(ChangePage);
ChangePage("UserControlRed.xaml");//默认选中红色界面
}
private void ChangePage(object obj)
{
PageName = obj.ToString();
}
}
使用反射+ContentControl 的方式也可使用页面切换,不过该方式下ContentControl 的Content不可以承接Page,但是可以承接UserControl。(Page只有Frame 和Window可以承接,)
首先将红色和绿色两个界面修改为UserControl并命名为UserControlRed和UserControlGreen ,然后修改代码如下:
<DockPanel Grid.Column="0">
<StackPanel Background="LightBlue">
<RadioButton IsChecked="True" Command="{Binding ChangePageCommand}" CommandParameter="UserControlRed" Content="红色" Margin="10"></RadioButton>
<RadioButton Command="{Binding ChangePageCommand}" CommandParameter="UserControlGreen" Content="绿色" Margin="10"></RadioButton>
</StackPanel>
<ContentControl Content="{Binding MainContent}"/>
</DockPanel>
public class MainViewModel:ViewModelBase
{
private FrameworkElement mainContent;
public FrameworkElement MainContent
{
get {
return mainContent; }
set {
mainContent = value; OnPropertyChanged(); }
}
public ICommand ChangePageCommand {
get; set; }
public MainViewModel()
{
ChangePageCommand = new CommandBase(ChangePage);
ChangePage("UserControlRed");//默认选中红色界面
}
private void ChangePage(object obj)
{
//【 * 】这里需要拼接路径
Type type = Type.GetType("WpfApp2.Views." + obj.ToString());
MainContent = (FrameworkElement)System.Activator.CreateInstance(type);
}
}
上面的代码运行后会发现:
OnExplicitShutdown 表示只有手动调用Shutdown方法的时候,应用程序才会关闭,否则应用程序不会关闭,多用于 用户登录窗口, 过度到引用的主界面中
<Application x:Class="WpfApp2.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApp2"
ShutdownMode="OnExplicitShutdown">
<Application.Resources>
</Application.Resources>
</Application>
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
new MainView().ShowDialog();
new TestView().ShowDialog();
App.Current.Shutdown();
}
上面代码的意思,就是启动的时候 先启动并展示MainView这个窗口,然后当MainView的窗口关闭的时候,就展示TestView这个窗口,当TestView窗口关闭的时候,整个应用程序就会关闭。
这里就涉及到一个知识点:ShowDialog()和Show()的区别
- ShowDialog就是模式窗体,使用ShowDialog()后,代码会”卡“在这里,后面的代码不会执行;直到使用ShowDialog显示的窗体被关闭,后面的代码才会执行。
- 关闭窗体方式1:直接点击使用ShowDialog显示的窗体关闭按钮,关闭当前窗体,则可继续
- 关闭窗体方式2:只要设置了窗体的DialogResult属性(true或false),窗体就会关闭退出
- Show就是非模式的窗体,显示窗体后不论窗体是否关闭都执行Show后面的语句。
- ShowDialog() 的返回值DialogResult 为
bool?
类型,如果通过关闭按钮,关闭窗体,默认返回值为false- Show() 的返回值为void ,只管执行即可
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
//增加一层判断,表示如果是点击窗体关闭按钮,则直接退出应用程序
//另外这也要求我们在手动设置DialogResult的时候,需要设置为true,才可以将这个场景予以区分
if (new MainView().ShowDialog()==true)
{
new TestView().ShowDialog();
}
App.Current.Shutdown();
}
还是借用【2、修改应用程序关闭方式实现窗体切换】+MVVM的方式,适用于登录界面过度到主窗口
在这以上1-3小节介绍的都是,关闭一个窗口后,然后又需要展示一个窗口,多用于登录窗口到主窗口的过渡场景。但是在平常的开发不仅仅只有这一种场景,还有一种常见场景是在主窗口 点击某个信息列表的按钮,然后打开详情信息的窗口(主窗口不可关闭),此场景如果使用原生代码直接new xxxWindow().ShowDialog();
即可。但是如果在MVVM解耦思想的项目下,在ViewModel中直接使用这样的代码,就达不到解耦的目的了。因此我们需要一个中间层来管理窗口和处理窗体间信息的传递。
由此我们可以定义一个WindowManager类,
public class WindowManager
{
private static Dictionary<string, Action<object>> _dir = new Dictionary<string, Action<object>>();
public static void Register(string key,Action<object> action)
{
if (!string.IsNullOrEmpty(key)&&!_dir.ContainsKey(key))
{
_dir.Add(key,action);
}
}
public static void DoAction(string key,object obj)
{
if (!string.IsNullOrEmpty(key) && _dir.ContainsKey(key))
{
_dir[key]?.Invoke(obj);
}
}
}
WindowManager 可以根据项目需求,做不同的扩展和兼容(如我们定义有返回值的委托Func,或者用泛型让该类更加通用),由上面的代码可知:该类的主要作用就是做了一个 处理窗体间传递信息用的集合,由于WindowManager第三方的身份,我们可以在任意地方使用Register 注册一个委托,然后使用DoAction执行委托,这样足以满足我们降低耦合的目的。
另外我们使用MVVM+WindowManager 写了一个增删改查的小案例,先看下实现的效果:
主要代码如下:
具体案例Demo(VS2019)的下载链接:关于MVVM下窗口间信息的传递案例demo
以上就是今天要介绍的内容,希望以上内容可以帮助到你,如文中有不对之处,还请批评指正。
文章浏览阅读118次。题意紫书第十章的题目。多组数据,每次给出三个数a,b,n,(a,b<2642^{64}264,n<=1000),问第aba^{b}ab个斐波那契数模n的值。斐波那契数列从f(0)=0,f(1)=1开始。题解因为是要求出f(ab)f(a^{b})f(ab)%n的值,所以先在%n条件下算出斐波那契数列。算到哪里结束呢?注意到在%n条件下,斐波那契数列如果前两个数相同,则由递推公式f(i)=f(i−1)+f(i−2)f(i)=f(i-1)+f(i-2)f(i)=f(i−1)+f(i−2),第三个_colossal fibonacci numbers! uva - 11582
文章浏览阅读454次。Leftmargin topmargin用来调整链接或文字位置Text用来调整字体颜色点击进入百度页面 添加链接alink点击时链接 link当前显示链接 vlink点击后链接 主要用来控制链接字体的颜色bgcolor用来设置背景颜色background用来设置背景图片(GIF、JPG)background=fixed使背景图片成固定效果,不随滚动条_html基本语法共有几种
文章浏览阅读1w次,点赞13次,收藏262次。在日常的工作学习当中,我们总会遇到各式各样的问题,其中不少的问题都是一遍又一遍简单重复的操作,不妨直接用Python脚本来自动化处理。今天我就给大家分享10个Python高级脚本,帮助我们减少无谓的时间浪费,提高工作学习中的效率。 喜欢记得收藏、关注、点赞。注:完整版代码、数据、技术交流文末获取给照片添加水印给照片添加水印的代码多种多样,下面这种的或许是最为简单的形式,from PIL import Imagefrom PIL import ImageFontfrom PIL import _python写一个脚本
文章浏览阅读60次。《信息学奥赛一本通 初赛真题解析》第四章 阅读程序 第9节 树和图_信息学奥赛一本通+"第四章 阅读程序"+filetype:pptx
文章浏览阅读195次。当我们在手机上安装360安全卫士时,手机屏幕上时刻都会出现一个小浮动窗口,点击该浮动窗口可跳转到安全卫士的操作界面,而且该浮动窗口不受其他activity的覆盖影响仍然可见(多米音乐也有相关的和主界面交互的悬浮小窗口)。它能悬浮在手机桌面,且不受Activity界面的影响,说明该悬浮窗口是不隶属于Activity界面的,也就是说,他是隶属于启动它的应用程序所在进程。如360App所在的应用进程..._android 模仿360悬浮窗口
文章浏览阅读2.7k次。二进制字符串名字存储尺寸描述bytea1或4字节外加真正的二进制串变长二进制串db=# create table demo_bytea(bytea bytea);插入插入文本db=# insert into demo_bytea values('123');INSERT 0 1db=# select * from demo_bytea; bytea---------- \x313233(1 row)插入转义类型这个不是很理解,什么叫转义类型,我的_pgsql 如何把二进制文件直接放入数据库
文章浏览阅读10w+次,点赞979次,收藏2.6k次。大多数据结构课本中,串涉及的内容即串的模式匹配,需要掌握的是朴素算法、KMP算法及next值的求法。在考研备考中,参考严奶奶的教材,我也是在关于求next值的算法中卡了一下午时间,感觉挺有意思的,把一些思考的结果整理出来,与大家一起探讨。以下的顺序为1、最基本的朴素算法2、优化的KMP算法3、应算法需要定义的next值4、手动写出较短串的next值的方法5、最难理解的、足足有5行的代码..._kmp算法next计算方法
文章浏览阅读688次。什么原因导致工厂招工越来越难?辞职农民工说出里面的心酸说到工厂,里面打工的人,几乎都是农村的,每年一过完年出来打工,他们都是直奔工厂,因为条件有限,他们在大城市根本没有更好的选择,只有选择工厂上班,毕竟工厂对学历没有太大的要求,要知道,现在大学生找工作都难,何况这些从农村出来的,可是现在,工厂为什么越来越难招工?这是什么原因导致的,很多人辞职去外面做事,也..._招工难博客
文章浏览阅读1.1w次,点赞2次,收藏19次。导入js:一、hello vue<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>Document</title><script src="https://cdn.staticfile.org/vue/2.2.2/vue...._vue.js 菜鸟教程
文章浏览阅读243次。要想做好社群运营,除了朋友圈搭建、线下活动组织、产品制度设计外,最重要的一点就是群内的维护。群内的维护也不仅仅是靠群规、群主的维系,还要配合一些活动来提升社群的活跃、用户参与和认同。今天为大家罗列一些,做社群运营常用的一些促活、催单的小互动、小游戏。因为不同社群适合的活动不一样的,因此大家根据自己的业务类型来做结合调整。1、群成员的介绍也可以叫群成员破冰,这种比较适合资源型的社群、或者有门槛的小群,给每个成员提供介绍的模板,入群的时候发到群里面。既能避免入群的尴尬冷场,又能方便大家今后资源上的互_房产社群提升群活跃度
文章浏览阅读229次。在Java中,使用"|“作为分隔符时,可以使用转义字符”|"来表示真正的分隔符。但是,如果字段中包含了"aaa|bb"这样的内容,Java会将其视为分隔符,导致分割结果不正确。为了解决这个问题,可以使用正则表达式的预先查找(lookahead)和后顾查找(lookbehind)来匹配分隔符,而不是直接使用分隔符本身。在上述代码中,使用了正则表达式"(?\)|“来匹配分隔符”|“。\)“表示前面不能有转义字符”",这样就可以排除掉被转义的分隔符。这样就能够正确地将字段中包含转义字符的内容保留在分割结果中。_java转义了特殊字符但是需要分号分隔
文章浏览阅读2.4k次。nginx_ng 保持当前域名