我使用XAML序列化的对象图(WPF/Silverlight外部),我试图创建一个自定义标记扩展,将允许使用填充集合属性引用XAML中其他地方定义的集合的选定成员。如何创建一个返回集合的XAML标记扩展
这里是一个简化的XAML片段演示了什么,我的目标是实现:
<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>
每个国家对象的语言属性是与 IEnumerable的<语言>包含要引用填充在 LanguageSelector中指定的对象 Language,这是一个自定义标记扩展。
这是我在创建自定义标记扩展,将这个角色服务的尝试:
[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包含向前引用(因为语言对象在国家之后宣布对象),它会中断,因为这需要修复令牌(显然)无法投射到语言。
if (token == null)
{
var names = new[] { item };
token = service.GetFixupToken(names, true);
}
作为一个实验我试过,希望XAML会以某种方式解决令牌后返回的集合转换为收藏<对象>,但反序列化过程引发无效转换异常。
任何人都可以建议如何最好地得到这个工作?
非常感谢, 添
+1感谢您发表该内容。我发现这是XAML Servces学习曲线的一个很好的练习。我希望下面发布的建议可能在一年后仍然适用于您。 –
@Glenn Slayden:谢谢你对此的跟进。你提出了两个非常创新的解决方案。尽管我的代码现在已经实现并正在使用DmitryG提出的想法,但审查它并使其适用于使用更简洁的方法将会很有趣。 –