【问题标题】:Typed Data Templates in SilverlightSilverlight 中的类型化数据模板
【发布时间】:2010-10-26 18:51:30
【问题描述】:

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

那么您将如何在 SL 中完成以下任务(作者是 Josh Smith,完整链接如下)。简而言之,他的意思是,如果您将 TabControl 的选项卡页绑定到 ViewModel 集合,WPF 将通过查找具有适当(匹配)DataType 集的 DataTemplate 来找出如何动态显示每个选项卡。太酷了,但我想知道您将如何(可以?)在 Silverlight 中做到这一点。

将视图应用于 ViewModel

MainWindowViewModel 间接添加 并删除 WorkspaceViewModel 对象进出主窗口 选项卡控件。依靠数据 绑定,a 的 Content 属性 TabItem 收到一个 ViewModelBase 派生对象 展示。 ViewModelBase 不是 UI 元素,所以它没有内在的支持 用于渲染自身。默认情况下,在 WPF 一个非可视对象由 显示调用结果 它在 TextBlock 中的 ToString 方法。 这显然不是你需要的, 除非你的用户有燃烧 希望看到我们的类型名称 ViewModel 类!

你可以很容易地告诉 WPF 如何渲染 使用类型化的 ViewModel 对象 数据模板。类型化的 DataTemplate 没有分配 x:Key 值 给它,但它确实有它的 DataType 属性设置为 类型类。如果 WPF 尝试渲染一个 您的 ViewModel 对象,它将 检查资源系统是否 在范围内有一个类型化的 DataTemplate 其 DataType 与(或 基类)你的类型 视图模型对象。如果它找到一个,它 使用该模板来呈现 选项卡引用的 ViewModel 对象 项目的 Content 属性。

MainWindowResources.xaml 文件有 资源字典。那本词典 被添加到主窗口的资源中 层次结构,这意味着 它包含的资源在 窗口的资源范围。当一个选项卡 项目的内容设置为 ViewModel 对象,来自此的类型化 DataTemplate 字典提供了一个视图(也就是说,一个 用户控件)来呈现它,如图所示 在图 10 中。在图 10 中。

http://msdn.microsoft.com/en-us/magazine/dd419663.aspx 在图 10 中。

【问题讨论】:

    标签: silverlight mvvm


    【解决方案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 属性而不是类型进行映射...这里的可能性是无穷无尽的。

    【讨论】:

    • 这真的很酷。我是否正确假设这适用于用户控件,并且当您创建用户控件时,您必须让它从 ViewMapper 继承,以便它知道当它的 DataContext 更改时该怎么做?这本身就很酷,但是上面的文章允许您将 TabControl(或其他)项目 Source 绑定到 ViewModel 列表,并且每个都知道如何根据 typed 数据模板进行显示。我只是想知道这在 SL 中是否可能,但也许我误解了你的帖子
    • 注意我的编辑。如果您想使用ViewMapper,只需将其放在您希望映射发生的位置即可。请注意我是如何将ViewMapper 放在Border 中的。您可以轻松地将其放在选项卡中并获取数据映射。实际上,我更喜欢这样的方法而不是 DataTyped DataTemplates,因为它将映射从视图中取出,并留给配置。
    猜你喜欢
    • 2011-03-11
    • 1970-01-01
    • 2015-05-01
    • 2014-09-16
    • 2018-10-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多