Заголовок столбца таблицы данных WPF более одного раза - PullRequest
4 голосов
/ 14 апреля 2010

Можно ли сгруппировать заголовки столбцов в сетке данных WPF?

То, что я ищу, это

| Column 1 | Column 2 | Column 3|
| a  b  c  | a  b  c  | a  b  c |
| z  x  y  | z  x  y  | z  x  y |

Я искал вокруг и не вижу очевидного способа сделать это. Я мог бы использовать шаблонный столбец, а затем имитировать дополнительные ячейки в каждом шаблоне, но это не сработало бы для упорядочения и т. Д.

Полагаю, все, что я говорю, это то, что я ищу, так это то, как людям удалось охватить заголовки столбцов несколькими столбцами.

Любая помощь или идеи будут с благодарностью.

Ответы [ 6 ]

5 голосов
/ 05 августа 2011

Это старая ветка, но я подумал, что должен рассказать, как я это сделал.

В моем приложении я хочу отобразить три столбца записей даты под одним заголовком столбца «Даты платы за обслуживание». Я создал один столбец с двумя шаблонами данных, один для отображения и один для редактирования:

<DataGrid.Resources>
  <DataTemplate x:Key="cellTemplate">
     <Grid>
        <Grid.ColumnDefinitions>
           <ColumnDefinition Width="100" />
           <ColumnDefinition Width="100" />
           <ColumnDefinition Width="100" />
        </Grid.ColumnDefinitions>
        <TextBlock x:Name="tbDate1"
                    Text="{Binding Path=Date1}"
                    Grid.Column="0" />
        <TextBlock x:Name="tbDate2"
                    Text="{Binding Path=Date2}"
                    Grid.Column="1" />
        <TextBlock x:Name="tbDate3"
                    Text="{Binding Path=Date3}"
                    Grid.Column="2" />
     </Grid>
  </DataTemplate>
  <DataTemplate x:Key="cellEditingTemplate">
     <Grid>
        <Grid.ColumnDefinitions>
           <ColumnDefinition Width="100" />
           <ColumnDefinition Width="100" />
           <ColumnDefinition Width="100" />
        </Grid.ColumnDefinitions>
        <DatePicker Grid.Column="0"
                    Margin="0"
                    Name="dpDate1"
                    Width="100"
                    SelectedDate="{Binding Path=Date1}" />
        <DatePicker Grid.Column="1"
                    Margin="0"
                    Name="dpDate2"
                    Width="100"
                    SelectedDate="{Binding Path=Date2}" />
        <DatePicker Grid.Column="2"
                    Margin="0"
                    Name="dpDate3"
                    Width="100"
                    SelectedDate="{Binding Path=Date3}" />
     </Grid>
  </DataTemplate>

Затем я определяю столбец как DataGridTemplateColumn, указывая на приведенные выше шаблоны данных:

<DataGrid.Columns>
....
   <DataGridTemplateColumn CellTemplate="{StaticResource cellTemplate}"
                           Header="Maintenance Fee Dates"
                           CellEditingTemplate="{StaticResource cellEditingTemplate}" />
....
</DataGrid.Columns>

Поскольку DataTemplate размещается с сеткой, имеющей три столбца фиксированной длины, я получаю три хороших столбца дат (или DatePickers при редактировании) под заголовком одного столбца.

Горизонтальные линии сетки могут обрабатываться сеткой. Чтобы иметь вертикальные линии сетки между тремя столбцами, просто поместите элемент управления среднего столбца в элемент управления Border. Установите для элемента управления Border ту же ширину, что и для столбца Grid, отобразите только его правую и левую границы и установите его BorderBrush в соответствии с цветом линий сетки DataGrid:

  <DataTemplate x:Key="cellTemplate">
     <Grid>
        <Grid.ColumnDefinitions>
           <ColumnDefinition Width="100" />
           <ColumnDefinition Width="100" />
           <ColumnDefinition Width="100" />
        </Grid.ColumnDefinitions>
        <TextBlock x:Name="tbDate1"
                    Text="{Binding Path=Date1}"
                    Grid.Column="0" />
        <Border BorderThickness="1,0,1,0"
                BorderBrush="DarkGray"
                Width="100">
           <Border.Child>
              <TextBlock x:Name="tbDate2"
                          Text="{Binding Path=Date2}"
                          Grid.Column="1" />
           </Border.Child>
        </Border>
        <TextBlock x:Name="tbDate3"
                    Text="{Binding Path=Date3}"
                    Grid.Column="2" />
     </Grid>
  </DataTemplate>
2 голосов
/ 16 марта 2011

Этот вопрос немного устарел, но это был один из первых результатов Google, который появился, когда я искал решение этой проблемы, и мне не нравится ни один из опубликованных здесь ответов. Итак, вот простая альтернатива, использующая пользовательский заголовок и ClipToBounds = False.

<DataGridTextColumn.Header>
    <StackPanel Orientation="Horizontal">
        <TextBlock x:Name="HeightSpacer" Text="P" FontWeight="Bold" />
        <Canvas Height="{Binding ElementName=HeightSpacer, Path=ActualHeight}">
            <TextBlock Text="hone Numbers" FontWeight="Bold" ClipToBounds="False" />
        </Canvas>
    </StackPanel>
</DataGridTextColumn.Header>

Единственное, что вам нужно сделать, это убедиться, что общая ширина всех столбцов, которые этот заголовок рассылает спамом, не меньше ширины столбца заголовка.

TextBlock, который содержит первый символ текста заголовка и привязку Canvas.Height, используется для блокировки высоты, необходимой для заголовка. Это необходимо только в том случае, если ваш полный заголовок сетки данных не имеет элемента, определяющего высоту заголовка, или если заголовок, спамующий несколько столбцов, больше остальных (что было в моем случае ... это был единственный столбец заголовка с полужирным шрифтом) текст)

1 голос
/ 26 мая 2010

Возможно, вам лучше удалить заголовки столбцов и добавить свои собственные вне сетки. Вот хороший пост здесь , в котором показано, как создать «заголовок», охватывающий несколько столбцов.

1 голос
/ 14 апреля 2010

Создайте шаблон HeaderTemplate для своих столбцов.

    <DataGrid>
        <DataGrid.Columns>
            <DataGridTextColumn>
                <DataGridTextColumn.HeaderTemplate>
                    <DataTemplate>
                        <StackPanel>
                            <TextBlock>Column 1</TextBlock>
                            <TextBlock>xyz</TextBlock>
                        </StackPanel>
                    </DataTemplate>
                </DataGridTextColumn.HeaderTemplate>
            </DataGridTextColumn>
            <DataGridTextColumn Header="Header" />
        </DataGrid.Columns>
    </DataGrid>
0 голосов
/ 31 июля 2016

Вот как я это сделал, полностью в XAML.

Ширина столбца GD определяет ширину каждого из 4 столбцов, UniformGrid следит за тем, чтобы столбцы имели равную ширину. Текстовые поля растягиваются до полной доступной ширины.

Окраска ячейки DG (= 4 текстовых поля) заменяется окраской (MouseOver) отдельных текстовых полей.

<DataGridTemplateColumn Width=200>
    <DataGridTemplateColumn.CellStyle>
        <Style/> <!-- Disable previously set style -->
    </DataGridTemplateColumn.CellStyle>
    <DataGridTemplateColumn.Header>
        <StackPanel>
            <TextBlock  
                IsEnabled="False"
                Style="{StaticResource TextBlockDataGridHeader}">
                <Run>Windspeeds in area</Run>
            </TextBlock>
            <UniformGrid
                HorizontalAlignment="Stretch"
                Columns="4">
                <Label Grid.Column="0" Content="1"/>
                <Label Grid.Column="1" Content="2"/>
                <Label Grid.Column="2" Content="3"/>
                <Label Grid.Column="3" Content="4"/>
            </UniformGrid>
            <TextBlock           
                Style="{StaticResource TextBlockDataGridHeader}"
                Foreground="Red"
                Text="m/s"/>

        </StackPanel>
    </DataGridTemplateColumn.Header>
    <DataGridTemplateColumn.CellTemplate>
        <DataTemplate>
            <UniformGrid
                HorizontalAlignment="Stretch"
                Columns="4">
                <UniformGrid.Resources>
                    <Style TargetType="TextBox">
                        <Setter Property="Padding" Value="3,0,3,0"/>
                        <!-- Let row background shine through -->
                        <Setter Property="Background" Value="Transparent"/>
                        <Setter Property="Foreground" Value="White"/>
                        <!-- 'Cells' have no border -->
                        <Setter Property="BorderThickness" Value="0"/>
                        <Style.Triggers>
                            <!-- Flip colors on mouseOver -->
                            <Trigger Property="IsMouseOver" Value="True">
                               <Setter Property="Background" Value="White" />
                               <Setter Property="Foreground" Value="Black" />
                            </Trigger>
                        </Style.Triggers>
                    </Style>
                </UniformGrid.Resources>                  
                <TextBox 
                    Grid.Column="0"         
                    Text="{Binding VRef0[0],Mode=TwoWay, UpdateSourceTrigger=LostFocus,StringFormat=N1}"/>
                <TextBox 
                    Grid.Column="1"
                    Text="{Binding VRef0[1],Mode=TwoWay, UpdateSourceTrigger=LostFocus,StringFormat=N1}"/>
                <TextBox 
                    Grid.Column="2"
                    Text="{Binding VRef0[2],Mode=TwoWay, UpdateSourceTrigger=LostFocus,StringFormat=N1}"/>
                <TextBox 
                    Grid.Column="3"
                    Text="{Binding VRef0[3],Mode=TwoWay, UpdateSourceTrigger=LostFocus,StringFormat=N1}"/>
            </UniformGrid>
        </DataTemplate>                        
    </DataGridTemplateColumn.CellTemplate> 
</DataGridTemplateColumn>
0 голосов
/ 29 июня 2016

Это старый пост, и мне понравилось D'Hags answere. К сожалению, это не полностью удовлетворило мое требование. Поэтому я немного расширил решение D'Hags, которое теперь позволяет:

  • интервалы столбцов возможны произвольным образом, а не только для всей строки
  • диапазон столбцов определяется с помощью ссылок на объекты. Когда столбец 2 и столбец 3 привязываются к одной и той же ссылке на объект, тогда отображается диапазон
  • диапазон столбцов должен вести себя точно так же, как другие столбцы, так что, например, возможен выбор.

Решение выглядит так:

Датагрид со стилем:

    <DataGrid  x:Name="dataGrid" ItemsSource="{Binding}" AutoGenerateColumns="False">
        <DataGrid.Resources>
            <Style TargetType="DataGridRow">

                        <Setter Property="ItemsPanel" >
                            <Setter.Value>
                                <ItemsPanelTemplate>
                                    <local:DataGridSpannedCellPanel ></local:DataGridSpannedCellPanel>

                                </ItemsPanelTemplate>
                            </Setter.Value>
                        </Setter>

            </Style>
        </DataGrid.Resources>

    </DataGrid>

Это устанавливает следующий класс для использования вместо непосредственного использования DataGridCellsPanel:

public class DataGridSpannedCellPanel : DataGridCellsPanel
{
    protected override Size ArrangeOverride(Size arrangeSize)
    {
        if (DataContext is IEnumerable)
        {
            base.ArrangeOverride(arrangeSize);

            IEnumerable<Object> data = ((IEnumerable)DataContext).Cast<Object>();
            double totalPreviousWidth = 0;
            double totalPos = 0;


            List<int> columnSize = new List<int>();
            double currentSize = 0;


            for (int i = 0; i < data.Count(); ++i)
            {
                Object el = data.ElementAt(i);
                Object nextEl = null;

                UIElement uiel = InternalChildren[i];

                if (data.Count() > i + 1)
                {
                    nextEl = data.ElementAt(i + 1);
                }


                if (Object.ReferenceEquals(el, nextEl) && el != null)
                {
                    totalPreviousWidth += uiel.RenderSize.Width;
                    uiel.Arrange(new Rect(new Point(0, 0), new Size(0, 0)));
                }
                else
                {
                    if (totalPreviousWidth > 0)
                    {
                        uiel.Arrange(new Rect(new Point(totalPos, 0),
                    new Size(totalPreviousWidth + uiel.RenderSize.Width, uiel.RenderSize.Height))

                     );
                        currentSize = totalPreviousWidth + uiel.RenderSize.Width;
                    }

                    totalPos += uiel.RenderSize.Width;

                    totalPreviousWidth = 0;
                }
            }

            return arrangeSize;
        }
        else
        {
            return base.ArrangeOverride(arrangeSize);
        }

    }
 }
}

И он используется следующим образом:

public partial class MainWindow : Window
{

    void AddColumn(DataGrid dg, int i)
    {

        var col = new DataGridTextColumn();
        col.Header = (char)('A' + i);
        col.Binding = new Binding("[" + i + "]");

        dg.Columns.Add(col);

    }

    public MainWindow()
    {
        InitializeComponent();

        for (int i = 0; i < 10; ++i)
        {
            AddColumn(dataGrid, i);
        }

        List<object> rows = new List<object>();

        String[] txtHeader = new string[7];
        String multiSpan = "MergedColumn";
        txtHeader[0] = "Col1";
        txtHeader[1] = "Col2";
        txtHeader[2] = "Col3";
        // these columns should be merged to one, which is indicated by assigning 
        // the same reference to all columns.
        txtHeader[3] = multiSpan;
        txtHeader[4] = multiSpan;
        txtHeader[5] = multiSpan;

        int[] intArr = new int[10];
        for (int i = 0; i < 10; i++)
        {
            intArr[i] = i;
        }

        rows.Add(txtHeader);
        rows.Add(intArr);

        dataGrid.ItemsSource = rows;
    }
}
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...