加载并创建数据模板实例
Load and create instance of data template
我有一个 ItemsControl
用于显示 View
个这样的项目:
<ItemsControl ItemsSource="{Binding Items}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<ContentControl Content="{Binding View}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
下面是简短的 mcve 给你一个想法:
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
(不幸的是,这无法更改t/shouldn),可以是任何内容,包括绑定等
我的问题:如何将 View
的创建移动到 xaml(作为数据模板)?
伪xaml:
<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?
}
与其在视图模型中创建 UI 控件,例如 TextBlock
或 CheckBox
,不如创建一个 CLR 对象:
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>
当您设置 DataTemplate
的 DataType
属性 而不指定 x:Key
时,DataTemplate
会自动应用于该类型的数据对象: https://msdn.microsoft.com/en-us/library/system.windows.datatemplate.datatype(v=vs.110).aspx
如果您绝对必须在视图模型(而不是模板)中使用 UIElement,同时想在 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);
}
我有一个 ItemsControl
用于显示 View
个这样的项目:
<ItemsControl ItemsSource="{Binding Items}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<ContentControl Content="{Binding View}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
下面是简短的 mcve 给你一个想法:
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
(不幸的是,这无法更改t/shouldn),可以是任何内容,包括绑定等
我的问题:如何将 View
的创建移动到 xaml(作为数据模板)?
伪xaml:
<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?
}
与其在视图模型中创建 UI 控件,例如 TextBlock
或 CheckBox
,不如创建一个 CLR 对象:
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>
当您设置 DataTemplate
的 DataType
属性 而不指定 x:Key
时,DataTemplate
会自动应用于该类型的数据对象: https://msdn.microsoft.com/en-us/library/system.windows.datatemplate.datatype(v=vs.110).aspx
如果您绝对必须在视图模型(而不是模板)中使用 UIElement,同时想在 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);
}