6

内容に応じて列のサイズを論理的にテーブルに設定したい。これはWPFで可能ですか?

代替テキストhttp://img43.imageshack.us/img43/2640/flowdocument.jpg

これが私が使っているコードです:

<Window x:Class="FlowDocument.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1" Height="300" Width="300">
    <Window.Resources>
        <Style TargetType="{x:Type TableCell}">
            <Setter Property="BorderBrush" Value="Gray" />
            <Setter Property="BorderThickness" Value="3" />


        </Style>
        <Style TargetType="{x:Type Paragraph}">
            <Setter Property="Padding" Value="2, 2, 2, 2" />
        </Style>
    </Window.Resources>
    <Grid>
        <FlowDocumentScrollViewer>
            <FlowDocument>
                <Table>
                    <Table.Columns>
                        <TableColumn Background="LightBlue" />
                        <TableColumn Background="Coral" />
                    </Table.Columns>
                    <TableRowGroup>
                        <TableRow>
                            <TableCell>
                                <Paragraph>This is a long piece of text</Paragraph>
                            </TableCell>
                            <TableCell>
                                <Paragraph>This isn't</Paragraph>
                            </TableCell>
                        </TableRow>
                        <TableRow>
                            <TableCell>
                                <Paragraph>This is a another long piece of text. The column should be wider than the other one!</Paragraph>
                            </TableCell>
                            <TableCell>
                                <Paragraph>Ditto</Paragraph>
                            </TableCell>
                        </TableRow>
                    </TableRowGroup>
                </Table>
            </FlowDocument>
        </FlowDocumentScrollViewer>
    </Grid>
</Window>
4

4 に答える 4

4

それはあなたが探しているものではありませんが、あなたは次のようなことをすることができます

<Table.Columns>
    <TableColumn Background="LightBlue" Width="2*"  />
    <TableColumn Background="Coral" Width="*" />
</Table.Columns>
于 2009-10-19T16:57:07.150 に答える
4

これは、列の最も幅の広いセルの目的の幅を決定することで可能になります。最も幅の広いセルは、すべての行をループしてセルの目的の幅を決定し、最大値を記憶することで決定できます。

この例では、すべての列が最適化されています。19の値は、左右のセルのパディングとセルの境界線の太さの結果である可能性があります。

void autoresizeColumns(Table table)
{
    TableColumnCollection columns = table.Columns;
    TableRowCollection rows = table.RowGroups[0].Rows;
    TableCellCollection cells;
    TableRow row;
    TableCell cell;

    int columnCount = columns.Count;
    int rowCount = rows.Count;
    int cellCount = 0;

    double[] columnWidths = new double[columnCount];
    double columnWidth;

    // loop through all rows
    for (int r = 0; r < rowCount; r++)
    {
        row = rows[r];
        cells = row.Cells;
        cellCount = cells.Count;

        // loop through all cells in the row    
        for (int c = 0; c < columnCount && c < cellCount; c++)
        {
            cell = cells[c];
            columnWidth = getDesiredWidth(new TextRange(cell.ContentStart, cell.ContentEnd)) + 19;

            if (columnWidth > columnWidths[c])
            {
                columnWidths[c] = columnWidth;
            }
        }
    }

    // set the columns width to the widest cell
    for (int c = 0; c < columnCount; c++)
    {
        columns[c].Width = new GridLength(columnWidths[c]);
    }
}


double getDesiredWidth(TextRange textRange)
{
    return new FormattedText(
        textRange.Text,
        CultureInfo.CurrentCulture,
        FlowDirection.LeftToRight,
        new Typeface(
            textRange.GetPropertyValue(TextElement.FontFamilyProperty) as FontFamily,
            (FontStyle)textRange.GetPropertyValue(TextElement.FontStyleProperty),
            (FontWeight)textRange.GetPropertyValue(TextElement.FontWeightProperty),
            FontStretches.Normal),
            (double)textRange.GetPropertyValue(TextElement.FontSizeProperty),
        Brushes.Black,
        null,
        TextFormattingMode.Display).Width;
}
于 2014-05-11T13:40:19.023 に答える
4

実際、Microsoftは、この目的のためにテーブルではなくグリッドを使用することをお勧めします 。docs.microsoft.com:テーブルとグリッド

残念ながら、Gridはそのままの単純なグリッド線をサポートしていません。Microsoftによると、これGrid.ShowGridLinesは設計目的のみであり、かなり醜い破線を描画します。Micrsoftは、自分でグリッド線を描画することを望んでいます。それはマイクロソフトからどれほど怠惰ですか?

これを行う方法のサンプルコードを次に示します。

線のある単純なグリッド

<FlowDocumentScrollViewer>
  <FlowDocument>
    <BlockUIContainer>
      <Grid HorizontalAlignment="Left" RenderOptions.EdgeMode="Aliased" UseLayoutRounding="True">
        <Grid.ColumnDefinitions>
          <ColumnDefinition/>
          <ColumnDefinition/>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
          <RowDefinition/>
          <RowDefinition/>
        </Grid.RowDefinitions>
        <Grid.Resources>
          <Style TargetType="Border">
            <Setter Property="BorderBrush" Value="Black"/>
            <Setter Property="Padding" Value="2,0,3,0"/>
          </Style>

        </Grid.Resources>
        <Border Grid.Row="0" Grid.Column="0" BorderThickness="1,1,1,1">
          <TextBlock Text="AAA"/>
        </Border>
        <Border Grid.Row="0" Grid.Column="1" BorderThickness="0,1,1,1">
          <TextBlock Text="BBB"/>
        </Border>
        <Border Grid.Row="1" Grid.Column="0" BorderThickness="1,0,1,1">
          <TextBlock Text="CCC"/>
        </Border>
        <Border Grid.Row="1" Grid.Column="2" BorderThickness="0,0,1,1">
          <TextBlock Text="QgQ"/>
        </Border>
      </Grid>
    </BlockUIContainer>
  </FlowDocument>
</FlowDocumentScrollViewer>

主なアイデアは、各TextBoxを境界線の内側に設定し、境界線ごとにどちらの側に境界線が必要かを決定することです。

正確な1ピクセルの線を取得するには、とを設定する必要がGrid.RenderOptions.EdgeMode="Aliased"ありGrid.UseLayoutRounding="True"ます。

于 2019-05-28T19:26:54.923 に答える
0

以下のような単純化された「AutoFit」関数を記述できます。これは、特定の範囲内で列の幅を大まかに圧縮します。

整数ではなく倍精度浮動小数点数を使用し、それらを正確に計算しようとすると、無駄に収束するのにはるかに長い時間がかかる場合があります。

using System;
using System.Windows;
using System.Windows.Input;
using System.Windows.Documents;
using System.Windows.Controls;
using System.Text.RegularExpressions;
using System.Linq;
using System.Collections.Generic;



namespace Example {

    //----------------------------------------------------------------------------------------------------
    public class MyTable : Table {

        ...

        //------------------------------------------------------------------------------------------------
        public MyTable() {

            ...

            AutoFit();

            ...

        }
        //------------------------------------------------------------------------------------------------

        ...

        //------------------------------------------------------------------------------------------------
        private void AutoFit() {

            int extent = 10;
            int[] lengths = new int[this.Columns.Count];

            // collect content lengths of each column of the first 5 rows
            foreach(TableRow row in this.RowGroups[0].Rows.Take(5)) {
                for(int i = 0; i < row.Cells.Count; i++) {
                    TableCell cell = row.Cells[i];
                    TextRange t = new TextRange(cell.ContentStart, cell.ContentEnd);
                    int length = new List<string>(Regex.Split(t.Text, @"\r\n|[\r\n]")).Select(s => s.Length).Max();
                    lengths[i] = Math.Max(lengths[i], length);
                }
            }

            // keep content lengths with column index before sort
            List<ColumnSize> contentSizes = lengths.Select((length, index) => {
                return new ColumnSize() {Index = index, Size = length};
            }).OrderBy(e => e.Size).ToList();

            // assign compacted ratio to columns by recursion
            int[] compactedSizes = Compact(new int[contentSizes.Count], contentSizes, extent);

            // set width to columns
            for(int i = 0; i < compactedSizes.Length; i++) {
                this.Columns[i].Width = new GridLength(compactedSizes[i], GridUnitType.Star);
            }

        }
        //------------------------------------------------------------------------------------------------
        private int[] Compact(int[] sizes, List<ColumnSize> contentSizes, int extent) {

            int min = contentSizes.Min(e => e.Size);
            int max = extent - contentSizes.Count + 1;

            contentSizes = contentSizes.Select(e => {
                int size = (int)Math.Floor((double)e.Size / (double)min);
                e.Size = size > max ? max : size;
                return e;
            }).OrderBy(e => e.Size).ToList();

            if(contentSizes.Sum(e => e.Size) > extent) {
                if(sizes.All(v => v == 0)) {
                    sizes = sizes.Select(v => 1).ToArray();
                } else {
                    contentSizes.TakeWhile(e => e.Size == 1).ToList().ForEach(e => sizes[e.Index] += 1);
                }
                sizes = Compact(sizes, contentSizes.SkipWhile(e => e.Size <= 1).ToList(), extent);
            } else {
                contentSizes.ForEach(e => sizes[e.Index] = e.Size);
            }

            return sizes;

        }
        //------------------------------------------------------------------------------------------------
        private class ColumnSize {

            public int Index { get; set; }
            public int Size { get; set; }

        }
        //------------------------------------------------------------------------------------------------

        ...

    }
    //----------------------------------------------------------------------------------------------------

}
于 2020-09-17T11:34:18.767 に答える