使用MVVM DataTemplate在WPF XAML视图之间切换
原文 使用MVVM DataTemplate在WPF XAML视图之间切换
更新:这个技术的改进版本,一个不创建视图,可以在以下链接找到:
http://www.technical-recipes.com/2018/navigating-between-views-in-wpf-mvvm/
已经在许多博客/网站论坛上讨论过这种技术,包括:
https://rachel53461.wordpress.com/2011/05/28/switching-between-viewsusercontrols-using-mvvm/
http://stackoverflow.com/questions/19654295/wpf-mvvm-navigate-views
http:// stackoverflow .COM /问题/ 10993385 /改变-视图- buttonclick
我认为分享这种技术的工作版本的实现是有用的。
完整的Visual Studio项目可以从这里下载:
http://www.technical-recipes.com/Downloads/MvvmSwitchViews.zip
总而言之,您的应用程序至少应该实现以下内容:
一个ViewModel,它包含一个定义当前视图的属性,以便更改视图以切换ViewModel的属性。
ViewModel需要实现INotifyPropertyChanged,否则在属性更改时不会通知视图。
一个ContentControl,其内容绑定到当前视图。
您希望切换的每个视图的一些DataTemplates。
要开始,请在Visual Studio中创建一个新的WPF项目:

在我们的项目中创建2个新的WPF用户控件,View1.xaml和View2.xaml:

View1.xaml
|
1
2
3
4
五
6
7
8
9
10
11
12
13
14
15
16
17
18
|
<UserControl x:Class="MvvmSwitchViews.View1" mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="300"> <Grid> <Button Content="Goto View 2" Command="{Binding GotoView2Command}" HorizontalAlignment="Center" Margin="10,10,0,0" VerticalAlignment="Center" Width="75"> </Button> </Grid></UserControl> |
View2.xaml
|
1
2
3
4
五
6
7
8
9
10
11
12
13
14
15
16
17
18
|
<UserControl x:Class="MvvmSwitchViews.View2" mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="300"> <Grid> <Button Content="Goto View 1" Command="{Binding GotoView1Command}" HorizontalAlignment="Center" Margin="10,10,0,0" VerticalAlignment="Center" Width="75"> </Button> </Grid></UserControl> |
为每个视图创建ViewModel:View1ViewModel和View2ViewModel。这些只是我们极简主义实现的空类:

View1ViewModel.cs
|
1
2
3
4
五
6
|
namespace MvvmSwitchViews{ public class View1ViewModel { }} |
View2ViewModel.cs
|
1
2
3
4
五
6
|
namespace MvvmSwitchViews{ public class View2ViewModel { }} |
修改MainWindow.xaml以包含DataTemplate和CurrentView绑定:
MainWindow.xaml
|
1
2
3
4
五
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
<Window x:Class="MvvmSwitchViews.MainWindow" xmlns:local="clr-namespace:MvvmSwitchViews" Title="MainWindow" Height="350" Width="525"> <Window.Resources> <DataTemplate DataType="{x:Type local:View1ViewModel}"> <local:View1/> </DataTemplate> <DataTemplate DataType="{x:Type local:View2ViewModel}"> <local:View2/> </DataTemplate> </Window.Resources> <Window.DataContext> <local:MainWindowViewModel /> </Window.DataContext> <Grid> <ContentControl Content="{Binding CurrentView}" /> </Grid></Window> |
然后,我们为MainWindow.xaml创建一个名为MainWindowViewModel的新ViewModel:
MainWindowViewModel.cs
|
1
2
3
4
五
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
三十
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
|
using System.Windows.Input;namespace MvvmSwitchViews{ public class MainWindowViewModel : ViewModelBase { private ICommand _gotoView1Command; private ICommand _gotoView2Command; private object _currentView; private object _view1; private object _view2; public MainWindowViewModel() { _view1 = new View1(); _view2 = new View2(); CurrentView = _view2; } public object GotoView1Command { get { return _gotoView1Command ?? (_gotoView1Command = new RelayCommand( x => { GotoView1(); })); } } public ICommand GotoView2Command { get { return _gotoView2Command ?? (_gotoView2Command = new RelayCommand( x => { GotoView2(); })); } } public object CurrentView { get { return _currentView; } set { _currentView = value; OnPropertyChanged("CurrentView"); } } private void GotoView1() { CurrentView = _view1; } private void GotoView2() { CurrentView = _view2; } }} |
我们还需要实现INotifyPropertyChanged或创建一个实现INotifyPropertyChanged的类。为此,我们创建了一个名为ViewModelBase的新类:

ViewModelBase.cs
|
1
2
3
4
五
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
using System;using System.ComponentModel;using System.Windows.Input;namespace MvvmSwitchViews{ public class ViewModelBase : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; protected void OnPropertyChanged(string propertyName) { var handler = PropertyChanged; if (handler != null) { handler(this, new PropertyChangedEventArgs(propertyName)); } } }} |
为我们的事件处理创建另外三个类来实现RelayCommand,EventArgs和EventRaiser:
RelayCommand.cs
|
1
2
3
4
五
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
三十
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
|
using System;using System.Windows.Input;namespace MvvmSwitchViews{ public class RelayCommand<T> : ICommand { private readonly Predicate<T> _canExecute; private readonly Action<T> _execute; public RelayCommand(Action<T> execute) : this(execute, null) { _execute = execute; } public RelayCommand(Action<T> execute, Predicate<T> canExecute) { if (execute == null) { throw new ArgumentNullException("execute"); } _execute = execute; _canExecute = canExecute; } public bool CanExecute(object parameter) { return _canExecute == null || _canExecute((T) parameter); } public void Execute(object parameter) { _execute((T) parameter); } public event EventHandler CanExecuteChanged { add { CommandManager.RequerySuggested += value; } remove { CommandManager.RequerySuggested -= value; } } } public class RelayCommand : ICommand { private readonly Predicate<object> _canExecute; private readonly Action<object> _execute; public RelayCommand(Action<object> execute) : this(execute, null) { _execute = execute; } public RelayCommand(Action<object> execute, Predicate<object> canExecute) { if (execute == null) { throw new ArgumentNullException("execute"); } _execute = execute; _canExecute = canExecute; } public bool CanExecute(object parameter) { return _canExecute == null || _canExecute(parameter); } public void Execute(object parameter) { _execute(parameter); } // Ensures WPF commanding infrastructure asks all RelayCommand objects whether their // associated views should be enabled whenever a command is invoked public event EventHandler CanExecuteChanged { add { CommandManager.RequerySuggested += value; CanExecuteChangedInternal += value; } remove { CommandManager.RequerySuggested -= value; CanExecuteChangedInternal -= value; } } private event EventHandler CanExecuteChangedInternal; public void RaiseCanExecuteChanged() { CanExecuteChangedInternal.Raise(this); } }} |
EventArgs.cs
|
1
2
3
4
五
6
7
8
9
10
11
12
13
14
|
using System;namespace MvvmSwitchViews{ public class EventArgs<T> : EventArgs { public EventArgs(T value) { Value = value; } public T Value { get; private set; } }} |
EventRaiser.cs
|
1
2
3
4
五
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
三十
31
32
33
34
35
36
37
38
39
|
using System;namespace MvvmSwitchViews{ public static class EventRaiser { public static void Raise(this EventHandler handler, object sender) { if (handler != null) { handler(sender, EventArgs.Empty); } } public static void Raise<T>(this EventHandler<EventArgs<T>> handler, object sender, T value) { if (handler != null) { handler(sender, new EventArgs<T>(value)); } } public static void Raise<T>(this EventHandler<T> handler, object sender, T value) where T : EventArgs { if (handler != null) { handler(sender, value); } } public static void Raise<T>(this EventHandler<EventArgs<T>> handler, object sender, EventArgs<T> value) { if (handler != null) { handler(sender, value); } } }} |
我们现在可以运行该应用程序来演示如何通过按下按钮来实现视图切换:

然后切换到下一个视图:

使用MVVM DataTemplate在WPF XAML视图之间切换的更多相关文章
- 使用MVVM DataTriggers在WPF XAML视图之间切换/Window窗口自适应内容大小并居中
原文 使用MVVM DataTriggers在WPF XAML视图之间切换 相关文章: http://www.technical-recipes.com/2016/switching-between- ...
- 【逆向工具】IDA使用5-( string、图形化与视图的切换、图形化显示反汇编地址、自动注释、标签使用)
分析petya病毒时新学会的技巧. IDA技巧1 : string 提取文件中的字符串内容,如果看到一些文件字符串可以定位到关键的函数中. view -> open subview -> ...
- 使用MVVM设计模式构建WPF应用程序
使用MVVM设计模式构建WPF应用程序 本文是翻译大牛Josh Smith的文章,WPF Apps With The Model-View-ViewModel Design Pattern,译者水平有 ...
- 企业级架构 MVVM 模式指南 (WPF 和 Silverlight 实现) 译(2)
本书包含的章节内容 第一章:表现模式,以一个例子呈献给读者表现模式的发展历程,我们会用包括MVC和MVP在内的各种方式实现一个收费项目的例子.沿此方向,我们会发现每一种模式的问题所在,这也是触发设计模 ...
- MVVM框架从WPF移植到UWP遇到的问题和解决方法
MVVM框架从WPF移植到UWP遇到的问题和解决方法 0x00 起因 这几天开始学习UWP了,之前有WPF经验,所以总体感觉还可以,看了一些基础概念和主题,写了几个测试程序,突然想起来了前一段时间在W ...
- wpf多程序集之间共享资源字典--CLR名称空间未定义云云
wpf多程序集之间共享资源字典--CLR名称空间未定义云云 分类: WPF 2012-10-28 10:57 1162人阅读 评论(0) 收藏 举报 以下介绍如何创建可用于在多个程序集之间共享的资源字 ...
- WPF XAML之bing使用StringFormat
WPF XAML之bing使用StringFormat // 转化为百分比 Text="{Binding Progress, StringFormat=\{0:P\}}" < ...
- Objective-C ,ios,iphone开发基础:多个视图(view)之间的切换2,使用导航栏控制,以及视图之间传值。
首先需要说明的是每个应用程序都是一个window,背景色为黑色.在window上可以跑多个view进行来回切换,下面就通过手动写代码来体现导航栏切换view的原理. 第一步,新建一个single vi ...
- ASP.NET MVC 之控制器与视图之间的数据传递
今天,我们来谈谈控制器与视图之间的数据传递. 数据传递,指的是视图与控制器之间的交互,包括两个方向上的数据交互,一个是把控制器的数据传到视图中,在视图中如何显示数据,一个是把视图数据传递到控制器中, ...
随机推荐
- Android 图片压缩,基于比例和质量压缩
package cc.util.android.image; import java.io.ByteArrayOutputStream; import java.io.File; import jav ...
- windows go 安装
go的安装很简单,下载go的msi文件 这里提供go1.9的msi下载链接 https://www.lanzous.com/i2gb54d 直接全部next就行,默认安装在了c盘的go 然后配置环境变 ...
- 因权限引起的svn提交失败的错误及其解决办法
作者:朱金灿 来源:http://blog.csdn.net/clever101 前段时间,一个网友发邮件向我请教一个svn提交失败的错误.他的具体错误是这样的: 在配置svn强制输入日志时候遇到一个 ...
- php array数组的相关处理函数and str字符串处理与正则表达式
下面给各位同学整理了一些关于php array数组的相关处理函数and str字符串处理与正则表达式,希望文章对你会有所帮助. 数组的相关处理函数: 1)数组的键值操作函数 array_value ...
- QT学习记录之理解信号槽机制
作者:朱金灿 来源:http://blog.csdn.net/clever101 QT的事件机制采用的信号槽机制.所谓信号槽机制,简而言之就是将信号和信号处理函数绑定在一起,比如一个按钮被单击是一个信 ...
- 开发自己的PHP MVC框架(一)
这个教程能够使大家掌握用mvc模式开发php应用的基本概念.此教程分为三个部分.如今这篇是第一部分. 如今市面上有非常多流行的框架供大家使用.可是我们也能够自己动手开发一个mvc框架.採用mvc模式能 ...
- 【codeforces 757C】Felicity is Coming!
time limit per test2 seconds memory limit per test256 megabytes inputstandard input outputstandard o ...
- @RequiresPermissions 解释
@RequiresAuthentication 验证用户是否登录,等同于方法subject.isAuthenticated() 结果为true时. @RequiresUser 验证用户是否被记忆,us ...
- [Javascript] Write a function pipeline
const _pipe = (f, g) => (...args) => g(f(...args)) export const pipe = (...fns) => fns.redu ...
- POJ 2104 - 主席树 / 询问莫队+权值分块
传送门 题目大意应该都清楚. 今天看到一篇博客用分块+莫对做了这道题,直接惊呆了. 首先常规地离散化后将询问分块,对于某一询问,将莫队指针移动到指定区间,移动的同时处理权值分块的数字出现次数(单独.整 ...