XAML 在列标题之间放置一点空间

llycmphe  于 2023-06-19  发布在  其他
关注(0)|答案(1)|浏览(118)

在WPF中,我使用自定义ColumnHeaderStyle ...

<DataGrid.ColumnHeaderStyle>
                <Style TargetType="{x:Type DataGridColumnHeader}">
                    <Setter Property="Template">
                        <Setter.Value>
                            <ControlTemplate TargetType="{x:Type DataGridColumnHeader}">
                                <Border Background="#3ec9ed"
                                        BorderBrush="Black"
                                        BorderThickness="0"
                                        Padding="10"
                                        CornerRadius="25">
                                    <ContentPresenter HorizontalAlignment="Center"
                                                      VerticalAlignment="Center"
                                                      Margin="5,0,5,0" />
                                </Border>
                            </ControlTemplate>
                        </Setter.Value>
                    </Setter>
                    <Setter Property="Foreground"
                            Value="White" />
                    <Setter Property="HorizontalContentAlignment"
                            Value="Center" />
                    <Setter Property="Padding"
                            Value="15" />
                    <Setter Property="SeparatorBrush"
                            Value="Red" />
                    <Setter Property="SeparatorVisibility"
                            Value="Visible" />
                </Style>
            </DataGrid.ColumnHeaderStyle>

现在看起来是这样的。

我想在每个列标题之间添加一点空间。就像这样

我能做些什么来实现这一目标?

hvvq6cgz

hvvq6cgz1#

DataGrid将所有列标题 Package 到一个通用的顶级DataGridColumnHeader容器中(它基本上是一个包含各个列标题的大的单列)。
当您通过全局Style设置DataGridColumnHeader.Background时,该值也适用于这个外部容器,这实际上会使列标题之间的间隙消失(因为它们共享相同的Background)。
解决方案是将此顶级列的Background设置为例如。Brushes.Transparent。顶层列通常具有-1DataGridColumnHeader.DisplayIndex
这允许我们使用模板Trigger来处理这个特殊列。
您还必须将模板元素正确地连接到模板化的父元素,以允许DataGridColumnHeader属性(如BackgroundMargin)按预期行为(即对布局有任何影响)。您通常使用TemplateBinding标记扩展来实现此目的。
为了允许单独设置第一个和最后一个项目的边框,您需要一个带有自定义IMultiValueConverterMultiBinding,以便检测最后一个项目/列。
下面示例中的ItemIndexComparerConverter允许使用Index表示法指定感兴趣项的索引(例如,^1引用最后一项,1引用第二项)。只需将索引传递给MultiBinding.ConverterParameter属性。
固定和改进的Style在10 DIP的列之间应用间隙(Margin左右5 DIP),如下所示:

<DataGrid.ColumnHeaderStyle>
  <Style TargetType="{x:Type DataGridColumnHeader}">
    <Setter Property="Margin"
            Value="5,0" />
    <Setter Property="Background"
            Value="#3ec9ed" />
    <Setter Property="BorderBrush"
            Value="Black" />
    <Setter Property="BorderThickness"
            Value="0" />
    <Setter Property="Padding"
            Value="10" />
    <Setter Property="Foreground"
            Value="White" />
    <Setter Property="HorizontalContentAlignment"
            Value="Center" />
    <Setter Property="Template">
      <Setter.Value>
        <ControlTemplate TargetType="{x:Type DataGridColumnHeader}">
          <Border>
            <Border x:Name="Border"
                    Background="{TemplateBinding Background}"
                    BorderBrush="{TemplateBinding BorderBrush}"
                    BorderThickness="{TemplateBinding BorderThickness}"
                    Padding="{TemplateBinding Padding}"
                    CornerRadius="0">
              <ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
                                VerticalAlignment="{TemplateBinding VerticalContentAlignment}" />
            </Border>
          </Border>

          <ControlTemplate.Triggers>

            <!-- Set the top level column header that contains the individual table column headers 
                 to have a Transparent background in order to make the gaps visible -->
            <Trigger Property="DisplayIndex"
                     Value="-1">
              <Setter Property="Background"
                      Value="Transparent" />
            </Trigger>

            <!-- Round corners on the left for first column's border -->
            <Trigger Property="DisplayIndex"
                     Value="0">
              <Setter TargetName="Border"
                      Property="CornerRadius"
                      Value="25,0,0,25" />
            </Trigger>

            <!-- Round corners on the right for last column's border -->
            <DataTrigger Value="True">
              <DataTrigger.Binding>
                <MultiBinding ConverterParameter="^1">
                  <MultiBinding.Converter>
                    <local:ItemIndexComparerConverter />
                  </MultiBinding.Converter>
                  <Binding RelativeSource="{RelativeSource Self}"
                           Path="DisplayIndex" />
                  <Binding RelativeSource="{RelativeSource AncestorType=ItemsControl}" />
                </MultiBinding>
              </DataTrigger.Binding>

              <Setter TargetName="Border"
                      Property="CornerRadius"
                      Value="0,25,25,0" />
            </DataTrigger>
          </ControlTemplate.Triggers>
        </ControlTemplate>
      </Setter.Value>
    </Setter>
  </Style>
</DataGrid.ColumnHeaderStyle>
    • ItemIndexComparerConverter. cs**

MultiBinding.ConverterParameterIndex引用值等于项的索引时返回true的转换器,否则返回false
所需的输入(通过MultiBinding)是当前项的索引和相关项源集合的ItemsControl

public class ItemIndexComparerConverter : IMultiValueConverter
{
  public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
  {
    if (parameter is not string referenceIndexText
      || values.FirstOrDefault(item => item is int) is not int indexOfCurrentItem
      || values.FirstOrDefault(item => item is ItemsControl) is not ItemsControl itemsControl)
    {
      return false;
    }

    Index referenceIndex = referenceIndexText.StartsWith('^')
      ? Index.FromEnd(int.Parse(referenceIndexText[1..]))
      : Index.FromStart(int.Parse(referenceIndexText));
    int trueReferenceIndex = referenceIndex.GetOffset(itemsControl.Items.Count);

    return indexOfCurrentItem == trueReferenceIndex;
  }

  public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
    => throw new NotSupportedException();
}

相关问题