【问题标题】:Adjust FontSize for ListViewItems when Container resizes its heightContainer 调整其高度时调整 ListView 项的字体大小
【发布时间】:2018-01-24 13:39:32
【问题描述】:

以下 ListView 应通过减小 FontSize 来调整其项目的大小,这些项目使用 TextBlock DataTemplate 呈现。初始 FontSize 在 Style 中指定,应为最大值 (23pt)。

如果项目文本过长,则最多将其换行为 2 行。

当窗口调整其高度或控件空间变得小于显示项目所需的空间时,FontSize 应减小,直到可以显示所有项目。如果可能,以前包装的文本应“展开”

<ListView x:Name="myListView" Grid.Row="0" Grid.Column="0"
                  Background="White" BorderBrush="Black" BorderThickness="1"
                  IsHitTestVisible="False"
                  ScrollViewer.HorizontalScrollBarVisibility="Disabled"
                  ScrollViewer.VerticalScrollBarVisibility="Disabled">
            <ListView.ItemTemplate>
                <DataTemplate>
                    <TextBlock MaxHeight="80"
                               Margin="0,0,0,21"
                               Text="{Binding}"
                               TextTrimming="CharacterEllipsis"
                               TextWrapping="Wrap">
                        <TextBlock.Style>
                            <Style TargetType="{x:Type TextBlock}">
                                <Setter Property="FontSize" Value="23pt" />
                                <Setter Property="TextTrimming" Value="CharacterEllipsis" />
                                <Setter Property="FontFamily" Value="Arial Regular" />
                                <Setter Property="VerticalAlignment" Value="Center" />
                                <Setter Property="HorizontalAlignment" Value="Left" />
                            </Style>
                        </TextBlock.Style>
                    </TextBlock>
                </DataTemplate>
            </ListView.ItemTemplate>
            <ListView.ItemContainerStyle>
                ...
            </ListView.ItemContainerStyle>
        </ListView>

Example Picture showing what i want

我已经尝试通过在 ListView 周围使用 ViewBox 来实现要求,但这也会调整高度和宽度(比率)==> 但是文本的可用宽度应该是恒定的。

另一种方法是覆盖 ListView 的 MeasureOverride 以减小 FontSize,如果需要的 listView 大小 > 控件的可用大小。但这也没有用。

也许有聪明人可以帮我解决这个问题。

最好的问候,

编辑 17.08.2017

我错过了一些必要的信息。 ListView 位于 row = 0 , column = 0 的网格内:

    <Grid.RowDefinitions>
        <RowDefinition Height="*" />
        <RowDefinition Height="Auto" />
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="250" />
        <ColumnDefinition Width="300" />
    </Grid.ColumnDefinitions>

GridCell 0,0 只能调整高度。 ListView 应采用整个 Cellsize 并调整其子项的 FontSize 以适应(最大 FontSize 可用)。 将文本换行到最多 2 个文本行也很重要。

【问题讨论】:

  • 我用一些完整的代码更新了我的答案。

标签: c# wpf xaml


【解决方案1】:

您可能需要执行一些操作,例如将FontSize 绑定到ListView 的宽度,并使用自定义IValueConverter 将该宽度更改为FontSize,这将使文本适合一行.

不幸的是,没有内置功能可以做你想做的事。


我现在为您提供了一个可行的解决方案!我不得不使用一些技巧来让它工作。转换器需要能够看到更多关于ListView 的信息,而不是通常能够看到的信息。为了解决这个问题,我使用IMultiValueConverter 将整个ListView 元素发送给它。它从MaxFontSize 开始并下降一个字体大小,直到找到最长线完全适合LitView 宽度的大小,或者它到达MinFontSize

您可能需要进行一些调整以完全满足您的需求,但这应该解决最困难的部分。您可能需要考虑优化尺寸代码,因为它可能会导致很多项目出现性能问题。应该有几个我现在没有时间做的相当明显的优化。

添加以下类:

class FontSizeConverter : FrameworkElement, IMultiValueConverter
{
    public double MaxFontSize { get; set; } = 50;
    public double MinFontSize { get; set; } = 1;

    private Size MeasureString(string candidate, Typeface typeface, double fontSize, ListView listView)
    {
        var formattedText = new FormattedText(candidate,
                                              CultureInfo.CurrentUICulture,
                                              FlowDirection.LeftToRight,
                                              typeface,
                                              fontSize,
                                              Brushes.Black,
                                              VisualTreeHelper.GetDpi(listView).PixelsPerDip);

        return new Size(formattedText.Width, formattedText.Height);
    }

    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
    {
        var containerListView = values[1] as ListView;
        if (containerListView == null || containerListView.ItemsSource==null)
        {
            return MaxFontSize;
        }

        Typeface typeface = new Typeface(containerListView.FontFamily, containerListView.FontStyle, containerListView.FontWeight, containerListView.FontStretch);
        double size = MaxFontSize;
        while (size > 0)
        {
            var biggestWidth = ((IEnumerable<string>)containerListView.ItemsSource).Select(s => MeasureString(s, typeface, size, containerListView).Width).Max();
            if (biggestWidth <= containerListView.ActualWidth)
            {
                return size;
            }
            size--;
        }
        return MinFontSize;
    }

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

使用此 XAML:

<Window
    x:Class="WpfApp4.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:local="clr-namespace:WpfApp4"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:system="clr-namespace:System;assembly=mscorlib"
    Title="MainWindow"
    Width="525"
    Height="350"
    mc:Ignorable="d">
    <Window.Resources>
        <x:Array x:Key="Data" Type="{x:Type system:String}">
            <system:String>Testing Testing Testing</system:String>
            <system:String>Some more text Some more text Some more text</system:String>
            <system:String>Longer text</system:String>
            <system:String>text text text text text texttext text text text text text</system:String>
            <system:String>Testing</system:String>
        </x:Array>
        <local:FontSizeConverter x:Key="FontSizeConverter" />
    </Window.Resources>
    <ListView
        Name="TheListView"
        Margin="8"
        ItemsSource="{Binding Source={StaticResource Data}}"
        ScrollViewer.HorizontalScrollBarVisibility="Disabled">
        <ListView.FontSize>
            <MultiBinding Converter="{StaticResource FontSizeConverter}">
                <Binding ElementName="TheListView" Path="ActualWidth" />
                <Binding ElementName="TheListView" />
            </MultiBinding>
        </ListView.FontSize>
        <ListView.Resources />
        <ListView.ItemTemplate>
            <DataTemplate>
                <TextBlock Text="{Binding}" />
            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>
</Window>

【讨论】:

  • 感谢您的帮助,但不幸的是,这并不是我想要实现的。我用其他信息编辑了我的问题。无论如何,我尝试了您的解决方案并将“宽度”更改为“高度”。但似乎在调整窗口高度时不会调用 ValueConverter(或 ItemsSource Updated)?
猜你喜欢
  • 1970-01-01
  • 2012-09-23
  • 1970-01-01
  • 1970-01-01
  • 2013-10-09
  • 1970-01-01
  • 1970-01-01
  • 2011-05-21
  • 1970-01-01
相关资源
最近更新 更多