我使用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提出的想法,但審查它並使其適用於使用更簡潔的方法將會很有趣。 –