You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

XamlWriter导出XAML后XamlReader加载失败的问题求助

解决XamlWriter序列化TextOptions后XamlReader加载失败的问题

问题原因

TextOptions的附加属性内部依赖MS.Internal.Media.TextOptionsInternal的实现,XamlWriter.Save()序列化时会直接输出内部类型的属性引用(msim:TextOptionsInternal.TextHintingMode),但XamlReader无法访问MS.Internal命名空间下的内部成员,因此加载时抛出“无法设置未知成员”的错误。

解决方案

方案一:正则替换(简单直接,推荐)

在序列化后的XAML字符串中,将内部属性引用替换为公开的TextOptions属性,并移除内部命名空间声明:

using System.Text.RegularExpressions;

// 序列化控件
string xaml = XamlWriter.Save(ctl);

// 替换内部属性为公开的TextOptions附加属性
xaml = Regex.Replace(xaml, @"msim:TextOptionsInternal\.([a-zA-Z]+)", @"TextOptions.$1");

// 移除MS.Internal.Media命名空间声明
xaml = Regex.Replace(xaml, @"xmlns:msim=""clr-namespace:MS.Internal.Media;assembly=PresentationCore""", string.Empty);

// 后续使用XamlReader加载处理后的XAML
ParserContext parser = new ParserContext();
parser.XmlnsDictionary.Add("x", "http://schemas.microsoft.com/winfx/2006/xaml");
parser.XmlnsDictionary.Add("", "http://schemas.microsoft.com/winfx/2006/xaml/presentation");
parser.XmlnsDictionary.Add("s", "clr-namespace:System;assembly=mscorlib");

UIElement el = XamlReader.Parse(xaml, parser) as UIElement;

方案二:序列化前后手动处理属性(更可靠)

先保存控件的TextOptions属性值,临时清除属性后再序列化,最后手动将属性添加回XAML中:

using System.Xml.Linq;

// 保存当前TextOptions设置
TextHintingMode hintingMode = TextOptions.GetTextHintingMode(ctl);

// 临时清除控件上的TextOptions属性
TextOptions.SetTextHintingMode(ctl, TextHintingMode.Default);

// 序列化控件
string xaml = XamlWriter.Save(ctl);

// 解析XAML为XDocument,手动添加TextOptions属性
XDocument doc = XDocument.Parse(xaml);
XNamespace presentationNs = "http://schemas.microsoft.com/winfx/2006/xaml/presentation";
XNamespace optionsNs = "http://schemas.microsoft.com/winfx/2006/xaml/presentation/options";

var buttonElement = doc.Root?.Element(presentationNs + "Button");
if (buttonElement != null)
{
    // 添加TextOptions.TextHintingMode属性
    buttonElement.SetAttributeValue(optionsNs + "TextHintingMode", hintingMode.ToString());
    
    // 移除内部命名空间声明(如果存在)
    var msimAttr = doc.Root?.Attribute(XName.Get("msim", "http://www.w3.org/2000/xmlns/"));
    msimAttr?.Remove();
}

// 转回XAML字符串
xaml = doc.ToString();

// 恢复控件原有的TextOptions设置
TextOptions.SetTextHintingMode(ctl, hintingMode);

// 加载XAML
ParserContext parser = new ParserContext();
parser.XmlnsDictionary.Add("x", "http://schemas.microsoft.com/winfx/2006/xaml");
parser.XmlnsDictionary.Add("", "http://schemas.microsoft.com/winfx/2006/xaml/presentation");
parser.XmlnsDictionary.Add("s", "clr-namespace:System;assembly=mscorlib");
// 添加options命名空间,确保属性能被正确解析
parser.XmlnsDictionary.Add("options", "http://schemas.microsoft.com/winfx/2006/xaml/presentation/options");

UIElement el = XamlReader.Parse(xaml, parser) as UIElement;

方案三:自定义Xaml序列化代理(复杂但灵活)

通过实现IValueSerializer或自定义XamlWriter,拦截TextOptions属性的序列化过程,强制输出公开的属性引用。不过这种方式需要深入WPF的XAML序列化机制,实现成本较高,适用于需要批量处理多个控件的场景。

内容的提问来源于stack exchange,提问作者user23617663

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 18:20:22