我创建了绑定到 DataTable 的自定义 DataGrid。
DataGrid 可能有超过 50 列,所以我启用了列虚拟化。
我的模型是这样的:
public class Book
{
public int Id { get; set; }
}
public class HistoricalBook : Book
{
public DateTime HistoricalPeriod { get; set; }
}
public class CriminalBook : Book
{
public string MainCharacter { get; set; }
}
这就是我填充 DataTable 的方式
public class MainViewModel : ViewModelBase
{
private DataTable _table;
public DataTable Table
{
get { return _table; }
set
{
if (value == _table) return;
_table = value;
RaisePropertyChanged(() => Table);
}
}
public MainViewModel()
{
Initiate();
}
private void Initiate()
{
Table = new DataTable("BookTable");
for (int i = 0; i < 20; i++)
Table.Columns.Add(new DataColumn(String.Format("Column{0}", i), typeof (Book)));
Table.Columns.Add(new DataColumn("B", typeof (Book)));
for (int j = 0; j <= 80; j++)
{
var books = new Book[20];
if (j == 0)
{
for (int i = 0; i < 20; i++)
books[i] = new HistoricalBook
{
Id = i,
HistoricalPeriod = DateTime.Now.AddDays(i)
};
}
else
{
for (int i = 0; i < 20; i++)
books[i] = new CriminalBook
{
Id = i,
MainCharacter = string.Format("Name {0}", i)
};
}
Table.Rows.Add(books);
}
}
}
因为我想将不同的类绑定到我的 DataGrid 的每一行,所以我使用了自定义 DataGrid,它使用基于有界对象到单元格的 DataTemplateSelector 选择 DataTemplate。
public class MyDataGrid : DataGrid
{
public static readonly DependencyProperty CellTemplateSelectorProperty =
DependencyProperty.Register("Selector", typeof (DataTemplateSelector), typeof (MyDataGrid), new FrameworkPropertyMetadata(null));
public DataTemplateSelector CellTemplateSelector
{
get { return (DataTemplateSelector) GetValue(CellTemplateSelectorProperty); }
set { SetValue(CellTemplateSelectorProperty, value); }
}
public static readonly DependencyProperty CellEditTemplateSelectorProperty =
DependencyProperty.Register("EditSelector", typeof (DataTemplateSelector), typeof (MyDataGrid), new FrameworkPropertyMetadata(null));
public DataTemplateSelector CellEditTemplateSelector
{
get { return (DataTemplateSelector) GetValue(CellEditTemplateSelectorProperty); }
set { SetValue(CellEditTemplateSelectorProperty, value); }
}
protected override void OnAutoGeneratingColumn(DataGridAutoGeneratingColumnEventArgs e)
{
e.Cancel = true;
var column = new DataRowColumn(e.PropertyName) {Header = e.Column.Header, CellTemplateSelector = CellTemplateSelector,
CellEditingTemplateSelector = CellEditTemplateSelector
};
Columns.Add(column);
}
}
public class DataRowColumn : DataGridTemplateColumn
{
public string ColumnName { get; private set; }
public DataRowColumn(string column)
{
ColumnName = column;
}
protected override FrameworkElement GenerateElement(DataGridCell cell, object dataItem)
{
var row = dataItem as DataRowView;
if (row != null)
{
object item = row[ColumnName];
cell.DataContext = item;
FrameworkElement element = base.GenerateElement(cell, item);
return element;
}
return new FrameworkElement();
}
}
XAML:
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Grid.Resources>
<helper:BookTemplateSelector x:Key="bookTemplateSelector">
<helper:BookTemplateSelector.CriminalBookTemplate>
<DataTemplate>
<Label Content="{Binding Id}"
Width="50" />
</DataTemplate>
</helper:BookTemplateSelector.CriminalBookTemplate>
<helper:BookTemplateSelector.HistoricalBookTemplate>
<DataTemplate>
<Label Content="{Binding HistoricalPeriod}"
Width="50" />
</DataTemplate>
</helper:BookTemplateSelector.HistoricalBookTemplate>
</helper:BookTemplateSelector>
<helper:BookTemplateSelector x:Key="editBookTemplateSelector">
<helper:BookTemplateSelector.CriminalBookTemplate>
<DataTemplate>
<TextBox Text="{Binding Id}"
Width="50" />
</DataTemplate>
</helper:BookTemplateSelector.CriminalBookTemplate>
<helper:BookTemplateSelector.HistoricalBookTemplate>
<DataTemplate>
<TextBox Text="{Binding HistoricalPeriod}"
Width="50" />
</DataTemplate>
</helper:BookTemplateSelector.HistoricalBookTemplate>
</helper:BookTemplateSelector>
</Grid.Resources>
<control:MyDataGrid Grid.Row="0"
HeadersVisibility="None"
ItemsSource="{Binding Table}"
AutoGenerateColumns="True"
CellTemplateSelector="{StaticResource bookTemplateSelector}"
CellEditTemplateSelector="{StaticResource editBookTemplateSelector}"
EnableColumnVirtualization="True"
EnableRowVirtualization="True"
VirtualizingStackPanel.IsVirtualizing="True"
VirtualizingStackPanel.VirtualizationMode="Standard">
</control:MyDataGrid>
</Grid>
乍一看 DataGrid 工作正常:
滚动数据后显示不正确: