WPF&Silverlight之XamlReader动态创建控件并绑定
使用 XamlReader.Load
XamlReader 是一个很大程度上具有方法的无状态的静态类,它可基于输入的 XAML 标记创建对象。XamlReader 提供并行如何通过 Silverlight 运行时和 Silverlight 应用程序模型对 XAML 进行分析的对象构建行为。 分析 XAML 生成托管对象的运行时对象树。 该对象树提供方法以便对那些在运行时使用命名的引用(由分析的 XAML中的 Name 或 x:Name 标识)或正经过完整树的部分的那些对象进行编程。
当使用 Load 方法创建 XAML 对象时,有几个要重点理解的一般概念。
XAML 内容字符串必须定义单个根元素。
XAML 内容字符串必须是格式良好的 XML,并且必须是有效的 XAML。
根元素必须声明在 XAML 中引用的任何实体所需的 XAML 命名空间。 对于默认的 Silverlight XAML 命名空间这是真实的,Load 的大多数字符串应指定根元素中的 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" ,以便 Silverlight 核心 XAML 命名空间是默认的 XAML 命名空间。
XAML 命名空间映射中引用的任何自定义程序集必须已可用于应用程序,(通常通过 AssemblyPart 包装)。
Load 的 XAML 不应尝试指定 x:Class,或包括事件处理程序的任何 XAML 定义的属性。 Load 逻辑不能集成具有运行时代码隐藏类的加载的 XAML。 如果您要添加事件处理程序,则必须在代码中这样做:引用 Load 结果的对象树结构内获得的对象,并将特定于语言的语法用于附加处理程序(如 += )。 有关使用代码的附加事件的更多信息,请参见 Silverlight 的事件概述。
将创建的对象树与主 Silverlight 对象树连接 下图演示了 Silverlight 对象层次结构和从 XAML 片段新创建的对象树之间的关系。
断开连接的 Silverlight 对象树
浏览器托管的 HTML 页面中的所有 Silverlight 内容最后才呈现,原因是,在对象关系中,它与 Silverlight 应用程序模型中加载为 RootVisual 的对象连接。 然后,RootVisual 是复合的 Silverlight,并且,将呈现相应的内容并传递到使用一种插件/控制访问层( Silverlight 实现在其本机代码的)的 HTML 主机。 最初,不呈现任何没有连接至主对象树(基于 RootVisual 的树)的对象树。
当您在 XAML 片段中创建了一个断开连接的对象树时,可以通过调用存在于主要对象树中的 Api 对象将其添加到主 Silverlight 对象树。 可以将断开连接的对象树设置为现有对象的属性值,也可以作为子对象将将其添加到其它对等对象的集合中。 (后者实际上也是属性设置,只不过您设置的是父对象的属性的集合。)当该片段成为主要的 Silverlight 对象树的一部分时,Silverlight 将检查由主对象树所组成的更改,并呈现 XAML 片段中的对象。 下图演示了 Silverlight 对象树和来自分析 XAML 片段的对象树之间新的关系(连接后)。
已连接的 Silverlight 对象树
对于将 XAML 生成的内容动态添加到主 Silverlight 对象树,有以下一些要求:
必须存在与 Silverlight 插件关联的 XAML 内容,不能替换整个内容树。 必须至少保留原始根元素。
在 XAML 分析 API 中创建的对象只能将能分配给主对象中的一个对象。 (这与初始 XAML 处理行为相似,即 XAML 与所创建的对象之间是 1:1 的关系,模板的特殊情况除外。)如果希望将向不同区域的应用程序主对象树添加同一 XAML 创建的对象,则必须使用同一输入字符串和不同的返回值目标多次分析 XAML。
期望用作连接点的主对象树中现有的 Silverlight 对象必须支持适当的属性至集。 换句话说,连接点对象必须有某种形式的可设置的属性值。 一些示例如下:
连接点对象支持诸如 Child 或 Content 这样的广义的子元素属性,这需要一个基类型,如 UIElement。 新对象树的根对象必须可分配给该属性。
连接点对象支持集合属性,并且该属性的集合类型也支持 Add 方法。 新对象树然后可以作为一个项目添加。
连接点对象支持特定类型的属性值相匹配的新树的根对象。 例如,您可以创建一个新的 Brush 与 Load 输入,然后使用它来设置 Background 值。
从 XAML 创建对象的安全问题 为了使基于 Silverlight 的应用程序免受安全攻击,强烈建议您不要将不可信的 XAML 字符串传递给 Load(或传递给 JavaScript equivalent CreateFromXaml)。 不可信的 XAML 可能包含镜像合法站点的伪装接口,这将导致欺骗安全威胁。 此外,XAML 可能包含对脚本事件处理程序的引用。如果您还未准备好通过指定当前加载的 XAML 的 x:Class 声明 XAML 中的托管 API,这需要尤为注意:默认的不含 x:Class 的编程模型为 JavaScript。 其结果是将向主树添加不受信任的 XAML 可能会导致无意执行脚本的 Silverlight 应用程序对象树。 应始终确认使用的 XAML 内容的来源是可信的。
动态加载并绑定实例
StringBuilder sb = new StringBuilder();
sb.Append(@"<Paragraph xmlns=""http://schemas.microsoft.com/winfx/2006/xaml/presentation"">XXXXXX");
sb.Append(@"<Run Foreground=""Red"" FontWeight=""Normal"" Text=""{Binding Filed,Mode=OneWay}""></Run> XXXXXX");
sb.Append(@"</Paragraph>");
Paragraph pg = (Paragraph)XamlReader.Load(sb.ToString());
if ((Paragraph)txtTopInfo.Blocks[0] != pg)
{
txtTopInfo.Blocks.Clear();
this.txtTopInfo.Blocks.Add(pg);
}