【发布时间】:2012-01-08 07:11:29
【问题描述】:
我正在将 XAML 序列化用于对象图(在 WPF / Silverlight 之外),并且我正在尝试创建一个自定义标记扩展,该扩展将允许使用对 XAML 中其他地方定义的集合的选定成员的引用来填充集合属性.
这是一个简化的 XAML sn-p,展示了我的目标:
<myClass.Languages>
<LanguagesCollection>
<Language x:Name="English" />
<Language x:Name="French" />
<Language x:Name="Italian" />
</LanguagesCollection>
</myClass.Languages>
<myClass.Countries>
<CountryCollection>
<Country x:Name="UK" Languages="{LanguageSelector 'English'}" />
<Country x:Name="France" Languages="{LanguageSelector 'French'}" />
<Country x:Name="Italy" Languages="{LanguageSelector 'Italian'}" />
<Country x:Name="Switzerland" Languages="{LanguageSelector 'English, French, Italian'}" />
</CountryCollection>
</myClass.Countries>
每个 Country 对象的 Languages 属性将填充一个 IEnumerable
这是我尝试创建将担任此角色的自定义标记扩展:
[ContentProperty("Items")]
[MarkupExtensionReturnType(typeof(IEnumerable<Language>))]
public class LanguageSelector : MarkupExtension
{
public LanguageSelector(string items)
{
Items = items;
}
[ConstructorArgument("items")]
public string Items { get; set; }
public override object ProvideValue(IServiceProvider serviceProvider)
{
var service = serviceProvider.GetService(typeof(IXamlNameResolver)) as IXamlNameResolver;
var result = new Collection<Language>();
foreach (var item in Items.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(item => item.Trim()))
{
var token = service.Resolve(item);
if (token == null)
{
var names = new[] { item };
token = service.GetFixupToken(names, true);
}
if (token is Language)
{
result.Add(token as Language);
}
}
return result;
}
}
事实上,这段代码几乎可以工作。只要在引用它们的对象之前在 XAML 中声明被引用对象,ProvideValue 方法就会正确返回填充了被引用项的 IEnumerable
var token = service.Resolve(item);
但是,如果 XAML 包含前向引用(因为 Language 对象是在 Country 对象之后声明的),它会中断,因为这需要修复令牌(显然)不能被转换为语言。
if (token == null)
{
var names = new[] { item };
token = service.GetFixupToken(names, true);
}
作为一个实验,我尝试将返回的集合转换为 Collection,希望 XAML 稍后能以某种方式解析标记,但它在反序列化期间会引发无效的强制转换异常。
谁能建议如何最好地完成这项工作?
非常感谢, 蒂姆
【问题讨论】:
-
+1 感谢您发布此信息。我发现它是我学习 XAML 服务曲线的一个很好的练习。我希望我在下面发布的建议在一年后仍然对您有用。
-
@Glenn Slayden:感谢您对此的跟进。您提出了两个非常创新的解决方案。虽然我的代码现在已经实现并使用 DmitryG 建议的想法运行,但审查它并对其进行调整以使用您更简洁的方法将会很有趣。
标签: c# xaml collections markup-extensions