上文说到 可以使用DataTemplateSelector。

其实等于是用 DataTemplateSelector + 动态创建DataTemplate来实现。

using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Markup; namespace ContentDemo
{
class ContentDataTemplateSelector : DataTemplateSelector
{
//用来标示一下已经创建过的类型
private readonly static Queue<Type> ViewModelQueue = new Queue<Type>(); public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
do
{
if (item == null
|| item is UIElement)
{
break;
} // item 就是你的ViewModel的类型,在这主要就是找到ViewModel对应的View
// 好多框架中会在启动时构建自己的Map,来对应ViewModel
// 比如 Caliburn.Micro 框架中默认 是以名称对应的 XXXViewModel 和 XXXView,来构建Map的
// MvvmCross 框架中不仅提供了 名称,还提供了 Attribute的对应方式 // 在这为了演示方便,我就直接反射对应名称的 View了。 var viewModelType = item.GetType(); if (ViewModelQueue.Contains(viewModelType))
{
break;
} var viewModelName = viewModelType.Name; string name = null;
var index = viewModelName.LastIndexOf("ViewModel", StringComparison.OrdinalIgnoreCase);
if (index > )
{
name = viewModelName.Substring(, index);
} if (string.IsNullOrEmpty(name))
{
break;
} var viewName = string.Format("{0}.{1}{2}", viewModelType.Namespace, name, "View"); var view = viewModelType.Assembly.GetType(viewName, false, true); if (view != null)
{
var dataTemplate = CreateDataTemplate(view, viewModelType); var dtkey = dataTemplate.DataTemplateKey; if (dtkey != null)
{
Application.Current.Resources.Add(dtkey, dataTemplate);
ViewModelQueue.Enqueue(viewModelType);
} return dataTemplate;
} } while (false); return base.SelectTemplate(item, container);
} /// <summary>
/// 创建DataTemplate
/// </summary>
/// <param name="viewType"></param>
/// <param name="viewModelType"></param>
/// <returns></returns>
private DataTemplate CreateDataTemplate(Type viewType, Type viewModelType)
{
const string xamlTemplate = "<DataTemplate DataType=\"{{x:Type vm:{0}}}\"><v:{1} /></DataTemplate>";
var xaml = String.Format(xamlTemplate, viewModelType.Name, viewType.Name); var context = new ParserContext(); context.XamlTypeMapper = new XamlTypeMapper(new string[]);
context.XamlTypeMapper.AddMappingProcessingInstruction("vm", viewModelType.Namespace, viewModelType.Assembly.FullName);
context.XamlTypeMapper.AddMappingProcessingInstruction("v", viewType.Namespace, viewType.Assembly.FullName); context.XmlnsDictionary.Add("", "http://schemas.microsoft.com/winfx/2006/xaml/presentation");
context.XmlnsDictionary.Add("x", "http://schemas.microsoft.com/winfx/2006/xaml");
context.XmlnsDictionary.Add("vm", "vm");
context.XmlnsDictionary.Add("v", "v"); var template = (DataTemplate)XamlReader.Parse(xaml, context);
return template;
}
}
}

WPF有一个好处就是他的DataType,所以 你也不一定非要在选择器中处理,你可以在任意你想要的时机时,把DataTemplate加到资源里就可以了。

但是WinRT中,的DataTemplate,就没有DataType,就得通过 选择器来,返回对应的DataTemplate.

还有 WinRT中 不支持 ParserContext,就只能拼字符串构造了。

Xaml:

<Window x:Class="ContentDemo.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:ContentDemo"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<local:MainViewModel x:Key="MainViewModel" />
<!--<DataTemplate DataType="{x:Type local:FirstViewModel}">
<local:FirstView />
</DataTemplate>
<DataTemplate DataType="{x:Type local:SecondViewModel}">
<local:SecondView />
</DataTemplate>--> <local:ContentDataTemplateSelector x:Key="ContentDataTemplateSelector" />
</Window.Resources>
<Grid DataContext="{StaticResource MainViewModel}">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<ContentControl Grid.ColumnSpan="2" Content="{Binding Path=ViewModel}" ContentTemplateSelector="{StaticResource ContentDataTemplateSelector}" />
<Button Grid.Row="1" Grid.Column="0" Content="ViewModel 1" Command="{Binding Path=FirstCommand}"/>
<Button Grid.Row="1" Grid.Column="1" Content="ViewModel 2" Command="{Binding Path=SecondCommand}"/>
</Grid>
</Window>

其实要是,用了很多的 ContentControl ,每一个 都去绑定 Selector,还是很烦人的一件事。

这时候,我们可以加一个 ContentControl 的 默认样式,让他默认就使用这个Selector.

<Application x:Class="ContentDemo.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:ContentDemo"
StartupUri="MainWindow.xaml">
<Application.Resources>
<local:ContentDataTemplateSelector x:Key="ContentDataTemplateSelector" /> <Style TargetType="{x:Type ContentControl}">
<Setter Property="ContentTemplateSelector"
Value="{StaticResource ContentDataTemplateSelector}"/>
</Style>
</Application.Resources>
</Application>
<Window x:Class="ContentDemo.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:ContentDemo"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<local:MainViewModel x:Key="MainViewModel" />
<!--<DataTemplate DataType="{x:Type local:FirstViewModel}">
<local:FirstView />
</DataTemplate>
<DataTemplate DataType="{x:Type local:SecondViewModel}">
<local:SecondView />
</DataTemplate>--> <!--<local:ContentDataTemplateSelector x:Key="ContentDataTemplateSelector" />-->
</Window.Resources>
<Grid DataContext="{StaticResource MainViewModel}">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<ContentControl Grid.ColumnSpan="2" Content="{Binding Path=ViewModel}" />
<Button Grid.Row="1" Grid.Column="0" Content="ViewModel 1" Command="{Binding Path=FirstCommand}"/>
<Button Grid.Row="1" Grid.Column="1" Content="ViewModel 2" Command="{Binding Path=SecondCommand}"/>
</Grid>
</Window>

源码:Code

转载请注明出处:http://www.cnblogs.com/gaoshang212/p/3961011.html

ContentControl 与 ViewModel (二)的更多相关文章

  1. ContentControl 与 ViewModel (一)

    前阵子有人问我MVVM模式下,在View中嵌套View,切换View.想一想还是写下来吧. 主要就是用到 ContentControl 和 DataTemplate,这算是一种 ViewModel F ...

  2. Python Flask高级编程

    第1章 课程导语介绍课程的内容1-1 开宗明义 试看1-2 课程维护与提问 第2章 Flask的基本原理与核心知识本章我们首先介绍Python官方推荐的最佳包与虚拟环境管理工具:Pipenv.接着我们 ...

  3. [WPF源码分析]ContentControl依赖项属性的双向绑定,two-way binding view's DependencyProperty and ViewModel's variable

    问题:自定义控件的依赖项属性和VIewModel中的变量不能双向绑定 解决思路:对比.net源码 PresentationFramework  /   System.Windows.Controls ...

  4. WPF系列之二:解耦View层控件事件与ViewModel层事件的响应

    以前的做法: 1.当项目的时间比较紧迫的时候,对UI层中控件的事件的处理,往往采取的是类似Winform中最简单的做法,直接做一个事件的Handler直接去调用VM层的方法. 2.控件只有一个Comm ...

  5. (二)MVVMLight 关联View和ViewModel

    在我们按照(一)中的步骤,安装好MMVLight的环境后, 会多出一个文件夹ViewModel,里面有两个.cs文件MainViewModel.cs和ViewModelLocator.cs MainV ...

  6. (二)Knockout - ViewModel 的使用

    计算属性 实际应用中,我们通常需要对数据进行加工 如: 指定日期格式,将数字相加... 等,此时可使用ko.computed().当数据发生改变是,KO会使用computed重新计算 DEMO1 更改 ...

  7. MVVM模式解析和在WPF中的实现(六) 用依赖注入的方式配置ViewModel并注册消息

    MVVM模式解析和在WPF中的实现(六) 用依赖注入的方式配置ViewModel并注册消息 系列目录: MVVM模式解析和在WPF中的实现(一)MVVM模式简介 MVVM模式解析和在WPF中的实现(二 ...

  8. MVVM模式解析和在WPF中的实现(五)View和ViewModel的通信

    MVVM模式解析和在WPF中的实现(五) View和ViewModel的通信 系列目录: MVVM模式解析和在WPF中的实现(一)MVVM模式简介 MVVM模式解析和在WPF中的实现(二)数据绑定 M ...

  9. MVVM模式和在WPF中的实现(二)数据绑定

    MVVM模式解析和在WPF中的实现(二) 数据绑定 系列目录: MVVM模式解析和在WPF中的实现(一)MVVM模式简介 MVVM模式解析和在WPF中的实现(二)数据绑定 MVVM模式解析和在WPF中 ...

随机推荐

  1. 获取ServletContext

    ServletConfig       config.getServletContext(): GenericServlet      this.getServletContext(); HttpSe ...

  2. gcc相关

    linux操作系统上面开发程序, 光有了gcc 是不行的 它还需要一个   build-essential软件包作用是提供编译程序必须软件包的列表信息 也就是说 编译程序有了这个软件包它才知道 头文件 ...

  3. 一个比较完整的Inno Setup 安装脚本(转)

    一个比较完整的Inno Setup 安装脚本,增加了对ini文件设置的功能,一个安装包常用的功能都具备了. [Setup] ; 注: AppId的值为单独标识该应用程序. ; 不要为其他安装程序使用相 ...

  4. step2-------使用myeclipse创建maven java web项目

    1.文章内容概述: 在对项目需求进行分析之后,决定使用maven对我的java web项目进行管理,这篇文章记录了使用myeclipse创建maven java web项目的过程. 2.开发环境: j ...

  5. Dojo学习_组件属性

    注意组件的引用顺序,避免出现对象不是构造函数或属性undefined的情况! 1.修改文本  require([ 'dojo/dom', 'dojo/domReady!' ], function (d ...

  6. (学习网址)Python 自动化测试

    1.Python自动化测试地址 http://www.wtoutiao.com/author/python-selenium.html 2.unittest参考网址: 1)python自动化测试报告H ...

  7. Python全栈--7模块--random os sys time datetime hashlib pickle json requests xml

    模块分为三种: 自定义模块 内置模块 开源模块 一.安装第三方模块 # python 安装第三方模块 # 加入环境变量 : 右键计算机---属性---高级设置---环境变量---path--分号+py ...

  8. Correspondence / ˏkɔris'pɔndәns / dictionary10-800.doc

    I have taken courses in office administration, typing,reports and correspondence writing. Correspond ...

  9. 校验两次密码一致的js代码

    function checkpasswd(){ var passwd = document.getElementByIdx_x_x_xx_x('passwd').value; var repasswd ...

  10. sublime text 也能矩形选择

    原来用editplus,但发现sublime text后便果断选择这个,她真的是很完美,但有一点就是不能像editplus一样矩形选择(Ctrl+鼠标左键这我知道,但感觉很麻烦)而感到小小的不爽... ...