使用 ControlTemplate 和 ContentPresenter 的自定义 DataGrid 控件

Custom DataGrid control with ControlTemplate and ContentPresenter

我有一个自定义 DataGrid(我扩展了它并包含了一个 DependencyProperty Label),我正在使用 DataGrid 并想添加 Label 使用 ControlTemplateContentPresenter 进行控制。在 ContentTemplate 中,DependencyProperty Label 正常工作并显示,但 ContentPresenter 不工作或根本不显示任何 DataGrid 控件。我用 ItemsPresenter 试了一下,它显示了行,我想知道是否有办法以这种方式使用 ContentPresenter 显示 DataGrid?这样做的正确方法是什么?

MyUserControl.xaml

<UserControl
    x:Class="MyNamespace.UI.MyUserControl"
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
     xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
     xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
     xmlns:e="clr-namespace:MyNamespace.UI"
     mc:Ignorable="d" 
     d:DesignHeight="350" d:DesignWidth="400">
    <UserControl.Resources>
        <Style TargetType="{x:Type e:DataGrid}"  BasedOn="{StaticResource {x:Type DataGrid}}">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type e:DataGrid}">
                        <StackPanel>
                            <Label Content="{Binding Label, RelativeSource={RelativeSource TemplatedParent}}" ContentStringFormat="{}{0}: " />
                            <ContentPresenter Margin="2" HorizontalAlignment="Center" VerticalAlignment="Center"/>
                        </StackPanel>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </UserControl.Resources>
    <WrapPanel  x:Name="LayoutRoot" Width="900" HorizontalAlignment="Stretch" Margin="12" VerticalAlignment="Stretch">
        <e:DataGrid Label="My Label 1"     ItemsSource="{Binding Source={StaticResource MySource1}}"/>
        <e:DataGrid Label="My Label 2"     ItemsSource="{Binding Source={StaticResource MySource2}}"/>
    </WrapPanel>
</UserControl>

DataGrid.cs

namespace MyNamespace.UI
{
    public class DataGrid : System.Windows.Controls.DataGrid
    {
        public string Label
        {
            get { return (string)GetValue(LabelProperty); }
            set { SetValue(LabelProperty, value); }
        }

        public static readonly DependencyProperty LabelProperty =
            DependencyProperty.Register("Label", typeof(string), typeof(DataGrid), new UIPropertyMetadata(""));

        public DataGrid()
        {}
    }
}

ControlTemplate 定义了整个 控件的外观。因此,您不能简单地在模板中放置一个 <ContentPresenter /> 并期望出现一个 DataGrid。此外,您不能仅继承 ControlTemplate:

的一部分

您可以复制整个默认模板并将您的 Label 添加到其中:

<Style TargetType="{x:Type e:DataGrid}"  BasedOn="{StaticResource {x:Type DataGrid}}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type DataGrid}">
                <Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Padding="{TemplateBinding Padding}" SnapsToDevicePixels="True">
                    <ScrollViewer x:Name="DG_ScrollViewer" Focusable="false">
                        <ScrollViewer.Template>
                            <ControlTemplate TargetType="{x:Type ScrollViewer}">
                                <Grid>
                                    <Grid.ColumnDefinitions>
                                        <ColumnDefinition Width="Auto"/>
                                        <ColumnDefinition Width="*"/>
                                        <ColumnDefinition Width="Auto"/>
                                    </Grid.ColumnDefinitions>
                                    <Grid.RowDefinitions>
                                        <RowDefinition Height="Auto"/>
                                        <RowDefinition Height="Auto"/>
                                        <RowDefinition Height="*"/>
                                        <RowDefinition Height="Auto"/>
                                    </Grid.RowDefinitions>
                                    <Label Content="{Binding Label, RelativeSource={RelativeSource TemplatedParent}}" ContentStringFormat="{}{0}: " />
                                    <Button Grid.Row="1" Command="{x:Static DataGrid.SelectAllCommand}" Focusable="false" Style="{DynamicResource {ComponentResourceKey ResourceId=DataGridSelectAllButtonStyle, TypeInTargetAssembly={x:Type DataGrid}}}" Visibility="{Binding HeadersVisibility, ConverterParameter={x:Static DataGridHeadersVisibility.All}, Converter={x:Static DataGrid.HeadersVisibilityConverter}, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}" Width="{Binding CellsPanelHorizontalOffset, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}"/>
                                    <DataGridColumnHeadersPresenter x:Name="PART_ColumnHeadersPresenter" Grid.Row="1" Grid.Column="1" Visibility="{Binding HeadersVisibility, ConverterParameter={x:Static DataGridHeadersVisibility.Column}, Converter={x:Static DataGrid.HeadersVisibilityConverter}, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}"/>
                                    <ScrollContentPresenter x:Name="PART_ScrollContentPresenter" CanContentScroll="{TemplateBinding CanContentScroll}" Grid.ColumnSpan="2" Grid.Row="2"/>
                                    <ScrollBar x:Name="PART_VerticalScrollBar" Grid.Column="2" Maximum="{TemplateBinding ScrollableHeight}" Orientation="Vertical" Grid.Row="2" Visibility="{TemplateBinding ComputedVerticalScrollBarVisibility}" Value="{Binding VerticalOffset, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}" ViewportSize="{TemplateBinding ViewportHeight}"/>
                                    <Grid Grid.Column="1" Grid.Row="3">
                                        <Grid.ColumnDefinitions>
                                            <ColumnDefinition Width="{Binding NonFrozenColumnsViewportHorizontalOffset, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}"/>
                                            <ColumnDefinition Width="*"/>
                                        </Grid.ColumnDefinitions>
                                        <ScrollBar x:Name="PART_HorizontalScrollBar" Grid.Column="1" Maximum="{TemplateBinding ScrollableWidth}" Orientation="Horizontal" Visibility="{TemplateBinding ComputedHorizontalScrollBarVisibility}" Value="{Binding HorizontalOffset, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}" ViewportSize="{TemplateBinding ViewportWidth}"/>
                                    </Grid>
                                </Grid>
                            </ControlTemplate>
                        </ScrollViewer.Template>
                        <ItemsPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
                    </ScrollViewer>
                </Border>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
    <Style.Triggers>
        <MultiTrigger>
            <MultiTrigger.Conditions>
                <Condition Property="IsGrouping" Value="true"/>
                <Condition Property="VirtualizingPanel.IsVirtualizingWhenGrouping" Value="false"/>
            </MultiTrigger.Conditions>
            <Setter Property="ScrollViewer.CanContentScroll" Value="false"/>
        </MultiTrigger>
    </Style.Triggers>
</Style>