问题:
有没有办法在XAML中定义DataTemplate
并在代码中实例化它(而不是通过FindResource
检索单例)并在发送到{{1}之前修改其VisualTree
是必需的,例如DataTemplate
?
背景:
我在DataGridTemplateColumn.CellTemplate
中通过添加data[][]
列来显示二维数组DataGrid
,并且在XAML中定义了DataGridTemplateColumn
,知道如何呈现数组中的每个元素。但是,每个单元格的默认DataTemplate
是行,即DataContext
。所以我需要通过将根视觉元素的data[x]
设置为绑定DataTemplate
来“DataContext
为每个列”参数化“"[y]"
,其中y
是列索引。目前,DataTemplate
定义为DataGrid.Resources
并由FindResource()
检索,每次都返回相同的实例。除了调用LoadContent()
之外,我还会在UIElement
本身上加载VisualTree
而不是DataTemplate
。我正在寻找一种方法来实例化代码中的DataTemplate
,进行所需的修改并设置为DataGridTemplateColumn.CellTemplate
。
答案 0 :(得分:7)
受Sisyphe的回答启发,我发现了这种更便携的解决方案:
public class DataGridBoundTemplateColumn : DataGridTemplateColumn
{
public string BindingPath { get; set; }
protected override FrameworkElement GenerateEditingElement(DataGridCell cell, object dataItem)
{
var element = base.GenerateEditingElement(cell, dataItem);
element.SetBinding(ContentPresenter.ContentProperty, new Binding(this.BindingPath));
return element;
}
protected override FrameworkElement GenerateElement(DataGridCell cell, object dataItem)
{
var element = base.GenerateElement(cell, dataItem);
element.SetBinding(ContentPresenter.ContentProperty, new Binding(this.BindingPath));
return element;
}
}
用法:
var cellTemplate = (DataTemplate)this.dataGrid.FindResource("cellTemplate");
foreach (var c in data.Columns)
{
var col = new DataGridBoundTemplateColumn
{
Header = c.HeaderText,
CellTemplate = cellTemplate,
BindingPath = string.Format("[{0}]", c.Index)
};
this.dataGrid.Columns.Add(col);
}
希望这可以帮助那些与我的问题具有相同要求的人。
答案 1 :(得分:2)
您应该在WPF中看到DataTemplate
作为工厂。因此,我认为您并不真正需要DataTemplate
的新实例,您只是希望根据您的上下文对其进行不同的应用。
如果我理解你的问题,问题是你的DataContext
单元格的DataGrid
不正确:它是行视图模型,而你希望它是Cell ViewModel(这很有意义) )。然而,这是DataGrid的基本行为,可能与每个行中的单元格由DataGridCellsPresenter(基本上是ItemsControl
)保持这一事实有关,其ItemsSource
依赖属性具有没有设置(因此解释了不好DataContext
)。
我遇到了这个问题并找到了解决这个问题的两种方法(但我只设法做了一个工作)。
第一个是子类DataGridCellsPresenter并覆盖OnItemChanged
方法手动设置ItemsSource。
protected override void OnItemChanged(object oldItem, object newItem)
{
var rowViewModel = newItem as ViewModel;
if (rowViewModel != null)
{
ItemsSource = rowViewModel.Items;
}
else
{
ItemsSource = null;
}
}
其中rowViewModel.Items应该指向类似data [x]的东西。但是,我使用此修复程序遇到了一些麻烦,无法使其正常工作。
第二个解决方案是子类DataGridCell
并在更改ColumnProperty
时更新dataContext。您还必须继承DataGridCellsPresenter
以使其创建正确的单元格控件
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();
}
}
最后,您还必须覆盖DataGridRow默认ControlTemplate,以使其使用自定义DataGridCellsPresenter
代替原始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>
答案 2 :(得分:1)
(templateKey as DataTemplate).LoadContent()
说明强>
当您致电LoadContent
时,UIElement
中的DataTemplate
个对象已创建,您可以将其添加到另一个UIElement
的可视树中。