Reputation: 21979
I have an ItemsControl
used to display View
of items like this:
<ItemsControl ItemsSource="{Binding Items}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<ContentControl Content="{Binding View}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
Below is short mcve to give you an idea:
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;
}
}
As you can see each item has pre-created View
(unfortunately this can't/shouldn't be changed), which can be anything, includes binding, etc.
My question: how to move creating of View
into xaml (as data templates)?
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? -->
Pseudo-code
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?
}
Upvotes: 0
Views: 1585
Reputation: 35646
if you absolutely have to use UIElements in view model (instead of templates), and at the same time want to declare them in xaml, then
x:Shared="False"
on UIElement<Window.Resources>
<TextBlock x:Key="type1" x:Shared="False" Text="{Binding Text}"/>
<CheckBox x:Key="type2" x:Shared="False" Content="{Binding Text}"/>
</Window.Resources>
each time you request a resource, you will get a new copy
LoadTemplate method is reduced to FindResource
object LoadTemplate(string key)
{
return FindResource(key);
}
Upvotes: 1
Reputation: 169160
Instead of creating a UI control such as a TextBlock
or a CheckBox
in the view model you should create a CLR object:
public class MyTextClass
{
public string Text { get; set; }
}
...
var view = new MyTextClass();
var item = new Item { Text = "1", View = control };
You could then use a DataTemplate
in the view to associate an instance of your CLR object with a control:
<DataTemplate DataType="local:MyTextClass">
<TextBlock Text="{Binding Text}" />
</DataTemplate>
When you set the DataType
property of a DataTemplate
without specifying an x:Key
, the DataTemplate
gets applied automatically to data objects of that type: https://msdn.microsoft.com/en-us/library/system.windows.datatemplate.datatype(v=vs.110).aspx
Upvotes: 1