5

问题:

有没有办法DataTemplate在 XAML 中定义 a 并在代码中实例化它(而不是通过 检索单例FindResource)并VisualTree在发送到DataTemplate需要 a 的位置之前对其进行修改,例如DataGridTemplateColumn.CellTemplate

背景:

我通过自己添加列来显示二维数组data[][],并且在 XAML 中定义了一个知道如何呈现数组中的每个元素的数组。但是,每个单元格的默认值是行,即. 所以我需要通过将根视觉元素设置为绑定列索引来“参数化”每一列。目前,定义为 in并通过 which 检索,每次都返回相同的实例。除了调用给我树而不是加载它本身。我正在寻找一种方法来实例化in 代码,进行所需的修改并设置为DataGridDataGridTemplateColumnDataTemplateDataContextdata[x]DataTemplateDataContext"[y]"yDataTemplateDataGrid.ResourcesFindResource()LoadContent()UIElementVisualTreeDataTemplateDataTemplateDataGridTemplateColumn.CellTemplate.

4

3 回答 3

9

受 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);
}

希望这对与我的问题具有相同要求的人有所帮助。

于 2012-12-28T21:44:02.160 回答
1
(templateKey as DataTemplate).LoadContent()

说明: 调用LoadContent时,会创建 中的UIElement对象DataTemplate,您可以将它们添加到另一个 的可视化树中UIElement

于 2012-12-22T07:27:16.727 回答
1

您应该DataTemplate在 WPF 中将其视为工厂。因此,我认为您实际上并不需要 的新实例DataTemplate,您只希望根据您的上下文以不同的方式应用它。

如果我正确理解您的问题,问题是DataContext您的DataGridCells 不正确:它是 Row ViewModel 而您希望它是 Cell ViewModel(这很有意义)。然而,这是 DataGrid 的基本行为,并且可能与每行中的 Cells 由未设置依赖属性的DataGridCellsPresenter(基本上是一个ItemsControl)持有的事实有关(因此解释了 bad )。ItemsSourceDataContext

我遇到了这个问题并找到了两种方法来解决这个问题(但我只设法完成了一项工作)。

第一个是继承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. 您还必须进行子类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>
于 2012-12-27T10:11:19.367 回答