You should see the DataTemplate in WPF as Factory. So, I think that you really don't need a new instance of the DataTemplate , you just want it to be applied differently depending on your context.
If I understand your problem correctly, the problem is that the DataContext your DataGrid Cells are incorrect: this is a Row ViewModel, whereas you want it to be a Cell ViewModel (which makes sense). This, however, is the main behavior of the DataGrid and is probably due to the fact that the cells in each row are held by the DataGridCellsPresenter (which is mainly ItemsControl ), the ItemsSource property is not set (thus explaining the bad DataContext ).
I ran into this problem and found two ways to fix this (but I only managed to do one job).
The first of these is a subclass of DataGridCellsPresenter and overrides the OnItemChanged method to set the ItemsSource element manually.
protected override void OnItemChanged(object oldItem, object newItem) { var rowViewModel = newItem as ViewModel; if (rowViewModel != null) { ItemsSource = rowViewModel.Items; } else { ItemsSource = null; } }
where rowViewModel.Items should point to something like data [x] in your case. However, I ran into some problems using this fix and was unable to get it to work correctly.
The second solution is a subclass of DataGridCell and updates the dataContext when ColumnProperty changes. You must also subclass DataGridCellsPresenter to create the correct cell controls.
public class MyDataGridCell : DataGridCell { protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e) { if (e.Property == ColumnProperty) { var viewModel = DataContext as YourViewModelType; if (viewModel != null) { var column = (e.NewValue as DataGridTemplateColumn); if (column != null) { var cellViewModel = viewModel[column.DisplayIndex]; DataContext = cellViewModel; } } } base.OnPropertyChanged(e); } } public class MyDataGridCellsPresenterControl : DataGridCellsPresenter { protected override System.Windows.DependencyObject GetContainerForItemOverride() { return new MyDataGridCell(); } }
Finally, you will also have to override the default ControlTemplate DataGridRow so that it uses your own DataGridCellsPresenter instead of the original DataGridCellsPresenter .
<ControlTemplate x:Key="DataGridRowControlTemplate" TargetType="{x:Type DataGridRow}"> <Border x:Name="DGR_Border" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" SnapsToDevicePixels="True"> <SelectiveScrollingGrid> <SelectiveScrollingGrid.ColumnDefinitions> <ColumnDefinition Width="Auto"/> <ColumnDefinition Width="*"/> </SelectiveScrollingGrid.ColumnDefinitions> <SelectiveScrollingGrid.RowDefinitions> <RowDefinition Height="*"/> <RowDefinition Height="Auto"/> </SelectiveScrollingGrid.RowDefinitions> <local:MyDataGridCellsPresenter Grid.Column="1" ItemsPanel="{TemplateBinding ItemsPanel}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/> <DataGridDetailsPresenter Grid.Column="1" Grid.Row="1" Visibility="{TemplateBinding DetailsVisibility}"> <SelectiveScrollingGrid.SelectiveScrollingOrientation> <Binding Path="AreRowDetailsFrozen" RelativeSource="{RelativeSource FindAncestor, AncestorLevel=1, AncestorType={x:Type DataGrid}}"> <Binding.ConverterParameter> <SelectiveScrollingOrientation>Vertical</SelectiveScrollingOrientation> </Binding.ConverterParameter> </Binding> </SelectiveScrollingGrid.SelectiveScrollingOrientation> </DataGridDetailsPresenter> <DataGridRowHeader Grid.RowSpan="2" SelectiveScrollingGrid.SelectiveScrollingOrientation="Vertical"> <DataGridRowHeader.Visibility> <Binding Path="HeadersVisibility" RelativeSource="{RelativeSource FindAncestor, AncestorLevel=1, AncestorType={x:Type DataGrid}}"> <Binding.ConverterParameter> <DataGridHeadersVisibility>Row</DataGridHeadersVisibility> </Binding.ConverterParameter> </Binding> </DataGridRowHeader.Visibility> </DataGridRowHeader> </SelectiveScrollingGrid> </Border> </ControlTemplate>