So im trying to make a custom styled DataGrid with DataTemplateSelector. I'm new to WPF and binding so I'm probably doing something wrong.
The item object received as parameter to the SelectTemplate function is always null.
I've tried googling this problem but I can't find an answer.
XAML:
<Grid.Resources>
<!-- Default DataTemplate -->
<DataTemplate x:Key="DefaultDataTemplate">
<TextBlock Text="{Binding Path=Value}" />
</DataTemplate>
<!-- DataTemplate for Booleans -->
<DataTemplate x:Key="BooleanDataTemplate">
<CheckBox IsChecked="{Binding Path=Value, Mode=TwoWay}" />
</DataTemplate>
<!-- DataTemplate for Arrays -->
<DataTemplate x:Key="ArrayDataTemplate">
<ComboBox ItemsSource="{Binding Path=Value, Mode=TwoWay}" />
</DataTemplate>
<local:ValueDataTemplateSelector x:Key="templateSelector"
DefaultDataTemplate="{StaticResource DefaultDataTemplate}"
BooleanDataTemplate="{StaticResource BooleanDataTemplate}"
ArrayDataTemplate="{StaticResource ArrayDataTemplate}" />
</Grid.Resources>
<DataGrid Name="DG1" ItemsSource="{Binding TagListView}" AutoGenerateColumns="False" >
<DataGrid.Columns>
<DataGridTextColumn Header="Name" />
<DataGridTemplateColumn Header="Value" CellTemplateSelector="{StaticResource templateSelector}" CellEditingTemplateSelector="{StaticResource templateSelector}" />
</DataGrid.Columns>
</DataGrid>
code behind:
public partial class TestView : Window
{
public TestView()
{
var t = new TestViewModel();
DataContext = t;
InitializeComponent();
}
}
the view model:
class TestViewModel
{
public TestViewModel()
{
generateTestList();
TagListView = new ListCollectionView(testList);
}
private ObservableCollection<TestTag> testList;
private void generateTestList()
{
testList = new ObservableCollection<TestTag>();
bool b = false;
testList.Add(new TestTag("bool", (object)b, b.GetType()));
string s = "...";
testList.Add(new TestTag("string", (object)s, s.GetType()));
ushort ui = (ushort)100u;
testList.Add(new TestTag("uint16", (object)ui, ui.GetType()));
int[] i_arr = new int[] { 1, 2, 3 };
testList.Add(new TestTag("int[]", (object)i_arr, i_arr.GetType()));
}
public ListCollectionView TagListView { get; private set; }
}
DataTemplateSelector. "item" parameter to SelectTemplate is always null
public class ValueDataTemplateSelector : DataTemplateSelector
{
public DataTemplate DefaultDataTemplate { get; set; }
public DataTemplate BooleanDataTemplate { get; set; }
public DataTemplate ArrayDataTemplate { get; set; }
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
var tag = item as TestTag;
Type t = tag.Type;
if (t == typeof(bool))
return BooleanDataTemplate;
if (t == typeof(int[]))
return ArrayDataTemplate;
return DefaultDataTemplate;
}
}
the model
class TestTag : INotifyPropertyChanged
{
private string _Name;
private object _Value;
public Type Type;
public string Name
{
get { return _Name; }
private set
{
_Name = value;
NotifyPropertyChanged("Name");
}
}
public object Value
{
get
{
return _Value;
}
set
{
_Value = value;
NotifyPropertyChanged("Value");
}
}
It looks like you are just missing a null check on the SelectTemplate
method:
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
var tag = item as TestTag;
if(tag == null)
return DefaultDataTemplate;
Type t = tag.Type;
if (t == typeof(bool))
return BooleanDataTemplate;
if (t == typeof(int[]))
return ArrayDataTemplate;
return DefaultDataTemplate;
}
You might as well consider some cleaning up to your TestTag
model class, for instance use generic rather than an Object type, lose the Type property and use the typeof
whe needed ...