加载并创建数据模板的实例

时间:2017-02-13 11:30:59

标签: c# wpf datatemplate

我有ItemsControl用于显示View这样的项目:

<ItemsControl ItemsSource="{Binding Items}">
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <ContentControl Content="{Binding View}" />
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

以下简短介绍给您一个想法:

public class Item
{
    public string Text { get; set; }
    public object View { get; set; }
    ... // more properties used in bindings
}

public partial class MainWindow : Window
{
    public ObservableCollection<Item> Items { get; } = new ObservableCollection<Item>();

    public MainWindow()
    {
        InitializeComponent();
        // 1
        {
            var control = new TextBlock();
            var item = new Item { Text = "1", View = control };
            BindingOperations.SetBinding(control, TextBlock.TextProperty, new Binding(nameof(Item.Text)) { Source = item });
            Items.Add(item);
        }
        // 2
        {
            var control = new CheckBox();
            var item = new Item { Text = "2", View = control };
            BindingOperations.SetBinding(control, CheckBox.ContentProperty, new Binding(nameof(Item.Text)) { Source = item });
            Items.Add(item);
        }
        // ... and so on
        DataContext = this;
    }
}

正如您所看到的,每个项目都已预先创建View(不幸的是,这不能改变),可以是任何内容,包括绑定等。

我的问题:如何将View创建为xaml(作为数据模板)?

Pseudoxaml:

<SomeContainer.Resources>
    <DataTemplate x:Key="type1">
        <TextBlock Text="{Binding Text}" />
    </DataTemplate>
    <DataTemplate x:Key="type2">
        <CheckBox Content="{Binding Text}" />
    </DataTemplate>
</SomeContainer.Resources>
<ItemsControl ... /> <!-- same definition as early? -->

伪代码

Items.Add(new Item { Text = "1", View = LoadTemplate("type1") });
Items.Add(new Item { Text = "2", View = LoadTemplate("type2") });

object LoadTemplate(string key)
{
    var resource = FindResource(key);
    ... // what next?
}

2 个答案:

答案 0 :(得分:1)

您应该创建一个CLR对象,而不是在视图模型中创建诸如TextBlockCheckBox之类的UI控件:

public class MyTextClass
{
    public string Text { get; set; }
}

...

var view = new MyTextClass();
var item = new Item { Text = "1", View = control };

然后,您可以在视图中使用DataTemplate将CLR对象的实例与控件关联:

<DataTemplate DataType="local:MyTextClass">
    <TextBlock Text="{Binding Text}" />
</DataTemplate>

当您设置DataType的{​​{1}}属性而未指定DataTemplate时,x:Key会自动应用于该类型的数据对象:https://msdn.microsoft.com/en-us/library/system.windows.datatemplate.datatype(v=vs.110).aspx

答案 1 :(得分:1)

如果绝对必须在视图模型中使用UIElements(而不是模板),并且同时想要在xaml中声明它们,那么

  • 不要使用DataTemplate
  • 在UIElement上使用x:Shared="False"
<Window.Resources>
    <TextBlock x:Key="type1" x:Shared="False" Text="{Binding Text}"/>
    <CheckBox x:Key="type2" x:Shared="False" Content="{Binding Text}"/>
</Window.Resources>

每次申请资源时,您都会获得一份新副本

LoadTemplate方法简化为FindResource

object LoadTemplate(string key)
{
    return FindResource(key);
}