Silverlight中的类型化数据模板

时间:2010-10-26 18:51:31

标签: silverlight mvvm

我的理解是Silverlight不支持具有DataType属性的DataTemplates。

如何在SL中完成以下内容(作者是Josh Smith,下面的完整链接)。简而言之,他说如果将TabControl的标签页绑定到ViewModel集合,WPF将通过查找具有相应(匹配)DataType集的DataTemplate来计算如何动态显示每个标签页。很酷,但我想知道你如何(可以?)在Silverlight中做到这一点。

  

将视图应用于ViewModel

     

MainWindowViewModel间接添加   并删除WorkspaceViewModel   来自主窗口的对象   TabControl的。依靠数据   绑定,一个的Content属性   TabItem收到一个   ViewModelBase派生的对象   显示。 ViewModelBase不是UI   元素,所以它没有固有的支持   用于渲染自己。默认情况下,在   WPF是一个非可视对象   显示呼叫结果   TextBlock中的ToString方法。   这显然不是你需要的,   除非您的用户有刻录   希望看到我们的类型名称   ViewModel类!

     

您可以轻松告诉WPF如何渲染   使用typed的ViewModel对象   的DataTemplates。一个类型化的DataTemplate   没有分配x:Key值   对它,但它确实有它的DataType   属性设置为的实例   输入类。如果WPF尝试渲染一个   你的ViewModel对象,它会   检查是否有资源系统   在范围内有一个类型化的DataTemplate   其DataType与(或a)相同   基类)你的类型   ViewModel对象。如果它找到一个,它   使用该模板来渲染   选项卡引用的ViewModel对象   item的内容属性。

     

MainWindowResources.xaml文件有   一个ResourceDictionary。那本字典   被添加到主窗口的资源中   层次结构,这意味着   它包含的资源在   窗口的资源范围。当一个标签   item的内容设置为ViewModel   object,这是一个类型化的DataTemplate   字典提供一个视图(即,一个   用户控件)渲染它,如图所示   如图10所示。

图10中的

http://msdn.microsoft.com/en-us/magazine/dd419663.aspx

1 个答案:

答案 0 :(得分:1)

这是你可以做到的一种方式。我过去曾经使用过这样的技术,并且取得了很大的成功。

考虑一个非常简单的容器,它将为您创建视图:

public class ViewMapper : ContentControl
{
    protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e)
    {
        base.OnPropertyChanged(e);

        if (e.Property.Name == "DataContext")
            WhenDataContextChanges();
    }

    private void WhenDataContextChanges()
    {
        if (DataContext == null)
            Content = null;
        else
            Content = ViewFactory.GetView(DataContext.GetType());
    }
}

修改

因此,您可以使用此控件为您执行映射:

<Border DataContext="{Binding MyViewModel}">
    <ViewMapper />
</Border>

结束编辑

请注意,ViewMapper只是等待数据上下文更改,查找数据类型的相应视图,并创建一个新视图。它依赖于ViewFactory,这是一个非常简单的静态查找,它将类型映射到视图:

public class ViewFactory
{
    private static readonly Dictionary<string, Func<UIElement>> _registry = new Dictionary<string, Func<UIElement>>();

    private static string Key(Type viewModelType)
    {
        return viewModelType.FullName;
    }

    public static void RegisterView(Type viewModelType, Func<UIElement> createView)
    {
        _registry.Add(Key(viewModelType), createView);
    }

    public static UIElement GetView(Type viewModelType)
    {
        var key = Key(viewModelType);
        if (!_registry.ContainsKey(key))
            return null;

        return _registry[key]();
    }
}

然后,您只需要在某个地方注册视图映射:

ViewFactory.RegisterView(typeof(SomeViewModel), () => new SomeView());

请注意,ViewFactory可以轻松使用Activator.CreateInstance而不是使用Func机制。更进一步,你可以使用IoC容器...你总是可以决定通过ViewModel上的字符串Name属性而不是类型来映射...这里的可能性是无穷无尽的。