在Silverlight 2中渲染视图模型的异构集合

时间:2009-07-14 13:13:40

标签: collections silverlight-3.0 mvvm silverlight-2.0 heterogeneous

我有一个代表格式化内容的视图模型层次结构:

public abstract class ContentPartViewModel : ViewModel
{
}

public class TextContentPartViewModel : ContentPartViewModel
{
    public string Text { ... }
}

public class TitleContentPartViewModel : TextContentPartViewModel
{
}

public class HyperlinkContentPartViewModel : TextContentPartViewModel
{
    public string Uri { ... }
}

我有一个包含视图的模型,其中包含要呈现的ContentPartViewModel个集合:

public class ContentViewModel
{
    public ICollection<ContentPartViewModel> ContentParts { ... }
}

然后我有ContentView呈现内容的所有部分:

<UserControl ...>
    <ItemsControl ItemsSource="{Binding ContentParts}"/>
</UserControl>

在理想的世界中,我只为每个内容部分类型定义DataTemplate,然后相应地呈现它们。但是,Silverlight不支持DataType类的DataTemplate属性,因此这不是一个选项。

另一种选择是提供DataTemplateSelector并自己从视图模型类型到DataTemplate进行映射。唉,SL2中的ItemsControl没有ItemTemplateSelector属性 - 只有ItemTemplate属性。

这让我别无选择,只能提供一个ItemTemplate然后使用转换器来关闭除与该内容部分相关的部分之外的所有UI:

<ItemsControl.ItemTemplate>
    <DataTemplate>
        <Grid>
            <TextBlock Text="{Binding Text}" FontWeight="Bold" Visibility="{Binding Converter={StaticResource TitleContentPartConverter}}"/>

            <TextBlock Text="{Binding Text}" Visibility="{Binding Converter={StaticResource TextContentPartConverter}}"/>

            <HyperlinkButton Content="{Binding Text}" NavigateUri="{Binding Uri}" Visibility="{Binding Converter={StaticResource HyperlinkContentPartConverter}}"/>
        </Grid>
    </DataTemplate>
</ItemsControl.ItemTemplate>

对于性能和可读性/代码的正确性而言,这显然是非常糟糕的。这也使我更难以正确格式化输出。所以,问题:

  1. 任何人都可以推荐更好的方法在SL2中执行此操作吗?
  2. 有谁能确认SL3的情况是否有所改善?
  3. 谢谢, 肯特

1 个答案:

答案 0 :(得分:1)

  1. 是。 Silverlight 2或Silverlight 3不支持DataTemplate中的DataType。

  2. 您可以在Silverlight中处理ItemTemplateSelector。请看一下这个样本。

  3. http://silverlight.net/forums/t/12598.aspx

    protected override void PrepareContainerForItemOverride(DependencyObject element, object item)
    {
        base.PrepareContainerForItemOverride(element, item); 
        DataTemplateSelector selector = this.ItemTemplateSelector;
    
        if (null != selector)
        {
            ((ContentPresenter)element).ContentTemplate = selector.SelectTemplate(item, element);
        }
    }