WPF 跨应用程序域的 UI(Cross AppDomain UI)
为自己写的程序添加插件真的是一个相当常见的功能,然而如果只是简单加载程序集然后去执行程序集中的代码,会让宿主应用程序暴露在非常危险的境地!因为只要插件能够运行任何一行代码,就能将宿主应用程序修改得天翻地覆哭爹喊娘;而根本原因,就在于暴露了整个托管堆和整个 UI 树。
如果将宿主和插件放到不同的应用程序域中,则可以解决此问题。本文将介绍跨应用程序域承载 UI 的方法,其中也包含跨域(Cross-Domain)调用方法。
来自于托管插件框架的辅助类
.NET Framework 自 3.5 以来推出了托管插件框架(MAF,Managed AddIn Framework),位于 System.AddIn 命名空间。其特性在于,将宿主和插件隔离在不同的应用程序域中,避免插件对宿主造成不良影响。
此命名空间中存在 FrameworkElementAdapters 类型,在 System.Windows.Presentation 程序集中,详见 FrameworkElementAdapters.cs。虽说主要用于 MAF 插件框架,但其实只需要此类型便可以实现跨应用程序域的 UI。
FrameworkElementAdapters 只有两个方法,ViewToContractAdapter 将 UI 转换成 INativeHandleContract,而 ContractToViewAdapter 将 INativeHandleContract 用一个 FrameworkElement 进行承载。
public static class FrameworkElementAdapters
{
[SecurityCritical]
public static FrameworkElement ContractToViewAdapter(INativeHandleContract nativeHandleContract);
[SecurityCritical]
public static INativeHandleContract ViewToContractAdapter(FrameworkElement root);
}
一个极简的跨域 UI Demo
首先,我们需要有一个支持跨域调用的类型,并有任意的可以用来返回 INativeHandleContract 的方法。
internal sealed class DomainX : MarshalByRefObject
{
public INativeHandleContract GetElement()
{
return FrameworkElementAdapters.ViewToContractAdapter(
new Rectangle
{
Width = 200,
Height = 100,
Fill = Brushes.ForestGreen,
});
}
}
我们需要跨域创建这个 UI 控件并得到 INativeHandleContract。
var domain = AppDomain.CreateDomain("X");
var instance = (DomainX)domain.CreateInstanceAndUnwrap(typeof(DomainX).Assembly.FullName, typeof(DomainX).FullName);
var contract = instance.GetElement();
然后,在需要承载这个跨域 UI 的地方取得这个 INativeHandleContract 的实例 contract。
var element = FrameworkElementAsyncAdapters.ContractToViewAdapter(contract);
// this 在这里是 MainWindow 或者 MainPage,或者其它任何能够承载 FrameworkElement 的对象。
this.Content = element;
以上的这两端代码都可以写在 MainWindow 的 Loaded 事件中。
对 MAF 吐一下槽
MAF 框架对插件和宿主程序集所在的文件夹结构有要求。这可是非常讨厌的一项特性!因为当我们希望采用 MAF 框架的时候,我们的应用程序可能已经有自己独特的一套目录了。就算我们从零开始写应用,采用 MAF 约定的方式组织 dll 也是很丑的方式(带有很重的 MAF 的影子)。
它没有提供任何的配置,而且如果不按照约定放置文件夹,还会发生如下错误:
参考资料
- ENikS/System.AddIn: Projects related to Microsoft System.AddIn
- Add-In Performance: What can you expect as you cross an isolation boundary and how to make it better [Jesse Kaplan] – CLR Add-In Team Blog
- WPF Add-Ins Overview - Microsoft Docs
- Walkthrough: Creating an Extensible Application - Microsoft Docs
- Add-ins and Extensibility - Microsoft Docs
WPF 跨应用程序域的 UI(Cross AppDomain UI)的更多相关文章
- 跨应用程序域(AppDomain)的单例(Singleton)实现
转载自: 跨应用程序域(AppDomain)的单例(Singleton)实现 - CorePlex代码库 - CorePlex官方网站,Visual Studio插件,代码大全,代码仓库,代码整理,分 ...
- WPF 同一窗口内的多线程/多进程 UI(使用 SetParent 嵌入另一个窗口)
原文 WPF 同一窗口内的多线程/多进程 UI(使用 SetParent 嵌入另一个窗口) WPF 的 UI 逻辑只在同一个线程中,这是学习 WPF 开发中大家几乎都会学习到的经验.如果希望做不同线程 ...
- 解析.NET对象的跨应用程序域访问--AppDomain(上篇)
在目前的项目开发中,分布式开发已经逐渐成为主流.一个项目要是没有采用分布式架构,都不好意思跟别人说这是一个完整的项目.这句话虽然有些过激,但是随着人们对效率的要求在提高,以及产品需要提升用户体验.只有 ...
- 如何跨线程访问Winform中的UI元素
如何跨线程访问Winform中的UI元素 假如制作一个Socket聊天应用程序,很可能会用到多线程: 例如为Receive方法开辟单独一个线程,例如为Receive方法开辟单独一个线程(后台运行的线程 ...
- 【.net 深呼吸】跨应用程序域执行程序集
应用程序域,你在网上可以查到它的定义,凡是概念性的东西,大伙儿只需要会搜索就行,内容看了就罢,不用去记忆,更不用去背,“名词解释”是大学考试里面最无聊最没水平的题型. 简单地说,应用程序域让你可以在一 ...
- 面向UI编程:ui.js 1.0 粗糙版本发布,分布式开发+容器化+组件化+配置化框架,从无到有的艰难创造
时隔第一次被UI思路激励,到现在1.0的粗糙版本发布,掐指一算整整半年了.半年之间,有些细节不断推翻重做,再推翻再重做.时隔今日,终于能先出来个东西了,这个版本很粗糙,主体功能大概能实现了,但是还是有 ...
- 解析.NET对象的跨应用程序域访问(下篇)
转眼就到了元宵节,匆匆忙忙的脚步是我们在为生活奋斗的写照,新的一年,我们应该努力让自己有不一样的生活和追求.生命不息,奋斗不止.在上篇博文中主要介绍了.NET的AppDomain的相关信息,在本篇博文 ...
- 解析.NET对象的跨应用程序域访问(上篇)
在目前的项目开发中,分布式开发已经逐渐成为主流.一个项目要是没有采用分布式架构,都不好意思跟别人说这是一个完整的项目.这句话虽然有些过激,但是随着人们对效率的要求在提高,以及产品需要提升用户体验.只有 ...
- NET对象的跨应用程序域
NET对象的跨应用程序域 转眼就到了元宵节,匆匆忙忙的脚步是我们在为生活奋斗的写照,新的一年,我们应该努力让自己有不一样的生活和追求.生命不息,奋斗不止.在上篇博文中主要介绍了.NET的AppDoma ...
随机推荐
- JS组件系列——基于Bootstrap Ace模板的菜单和Tab页效果
Ace模板地址:http://code.google.com/p/ace-engine/wiki/AceTemplate(有时会打不开) Ace英文官网:http://wrapbootstrap.co ...
- 完美解决 No toolchains found in the NDK toolchains folder for ABI with prefix: mips64el-linux-android
问题描述 好久之前的一个Android项目,最近需要重构一下 因为Android Studio的开发环境以及Gradle的版本等等都进行了一定的更新,于是导入Project以后,出现了报错: No t ...
- PHP会话控制之如何正确设置session_name
定义: string session_name([string $name]) 说明: 在php.ini中配置为:session.name = PHPSESSID 在请求开始的时候,会话名称会被重置并 ...
- PHP处理MySQL事务代码
php使用mysqli进行事务处理 <?php$db = new mysqli("localhost","root",""," ...
- 在Hibernate中使用原生SQL语句
使用原生SQL查询必须注意:程序必须选出所有的数据列才可被转换成持久化实体.假设实体在映射时有一个<many-to-one../>的关联指向另外一个实体,则SQL查询中必须返回该<m ...
- python环境配置
有个chatserver.py文件写的服务器代码,mac下终端执行python chatserver.py 总是报上面的错,求解 ImportError: No module named twist ...
- js中页面加载完成后执行的几种方式及执行顺序
1:使用jQuery的$(function){}; 2:使用jquery的$(document).ready(function(){});前两者本质上没有区别,第1种是第2种的简写方式.两个是docu ...
- 一点记忆—— Java框架知识的学习有感
一点记忆—— Java框架知识的学习有感 说一下自己学习的框架知识的历程吧:好久了,应该是一年前,也就是大三上的时候,我对于基本的 Java编程就已经达到所谓的“熟练”,认为自己可以在 ...
- Unity 3D 无法显示中文的解决方法
大家开始用unity3D时想必都会遇到一个问题,使用中文时会乱码.这是由于编码方式不同导致的,具体解决方法如下: 程序写代码什么的最好下个像Notepad++类似的工具,这里使用Notepad++修改 ...
- 深入理解java泛型
一. 什么是泛型? 泛 型(Generic type 或者 generics)是对 简单的理解,就是对类型的参数化,比如我们定义一个类属性或者实例属性时,往往要指定具体的类型,如Integer.Per ...