如何在 WPF ItemTemplate 中组合自动换行和动态字体大小 [英] How do I combine word wrap and dynamic font size in an WPF ItemTemplate

查看:38
本文介绍了如何在 WPF ItemTemplate 中组合自动换行和动态字体大小的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我看到的单个项目的建议是使用 TextBlockTextWrapping="true" 为前者,而 Viewbox对于后者.然而,两人并没有很好地一起玩.我见过将两者结合起来的唯一方法是在 TextBlock][1] 上显式设置 [Width,但这需要知道文本的宽度高级,因为不同长度的文本只能在不同的宽度下很好地工作,因此不适合与模板一起使用,因为理想的长度是可变的,并且事先不知道.

The recommendations I see for the individual items are to use a TextBlock with TextWrapping="true" for for former, and a Viewbox for the latter. However the two don't play nicely together. The only one I've seen for combining the two was to explicitly set a [Width on the TextBlock][1], but that requires knowing the width of the text in advanced because different lengths of text only work out nicely with different widths making in unsuitable for use with templating because the ideal length will be variable and not known in advance.

没有设置明确的宽度,我得到的是:

Without setting an explicit width what I get is:

对于两个单字项目,这可以正常工作,但如果多行多行,多字项目会更好地填充该区域.

Which works OK for the two single word items, but the multi-word one would fill the area much better if wrapped over multiple lines.

TextBlock 上设置 Width="80" 可以使多字文本很好地换行;但搞砸了单字项目的布局.

Setting Width="80" on the TextBlock gets the multi-word text to wrap nicely; but screws up the layout of single word items.

我想要的是缩放单个单词元素以适应(如顶部图像中的前两个按钮)并在缩放之前包装多个单词项目以更好地利用可用空间(类似于第三个按钮在第二个示例中 - 尽管如果 3 行或更多行会更好,则无需将其限制为仅两行文本).

What I'd like is something that scales single word elements to fit (like the first two buttons in the top image) and wraps multiple word items prior to scaling to make better use of the available space (similar to the third button in the second example - although there's no need to limit it to only two rows of text if 3 or more would work better).

我用于上述示例的 XAML 是:

My XAML used for the examples above is:

<Window x:Class="WpfApplication1.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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfApplication1"
        mc:Ignorable="d"
        Title="MainWindow" Height="150" Width="525">
    <Window.Resources>
        <local:MYViewModel x:Key="myVM"/>
    </Window.Resources>
    <Grid  DataContext="{Binding Source={StaticResource myVM}}">
        <ItemsControl ItemsSource="{Binding ThingsList, Mode= OneWay}"
                      HorizontalAlignment="Stretch" >
            <ItemsControl.ItemsPanel>
                <ItemsPanelTemplate>
                    <UniformGrid Columns="3" Rows="1"
                                 HorizontalAlignment="Stretch" />
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <Button>
                        <Viewbox>
                            <TextBlock TextWrapping="Wrap" Text="{Binding Name}" />
                        </Viewbox>
                    </Button>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>
    </Grid>
</Window>

背后:

public class NamedThing
{
    public string Name { get; set; }
}

public class MYViewModel
{
    public ObservableCollection<NamedThing> ThingsList { get; set; }
         = new ObservableCollection<NamedThing>
        {
            new NamedThing {Name = "Short"},
            new NamedThing {Name = "VeryVeryLongWord"},
            new NamedThing {Name = "Several Words in a Row"}
        };
}

/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{

    public MainWindow()
    {
        InitializeComponent();
    }
}

推荐答案

问题是您的 Viewbox 会缩放其中的任何内容,但 TextBlocks 不知道它们包含的内容,只会增长(宽度方向)因为他们被允许(默认情况下是 Infinity).

The problem is that your Viewbox scale whatever is inside it, but the TextBlocks don't know in what they are contained and just grow (width wise) as much as they're allowed to (which is Infinity by default).

第一个快速的解决方案是为 TextBlock 设置一个 MaxWidth(例如 100)值.这样,多词 TextBlock 的反应就和单词完全一样:它会增长和缩小,但换行不会改变.

A first and quick solution is to set a MaxWidth (100, for example) value to the TextBlock. This way, the multi-word TextBlock will simply react exactly as the single-word ones: it will grow and shrink, but the word wrapping won't change.

当您知道 Viewbox 的工作原理时,MaxWidth 起作用而不是 Width 起作用的原因在逻辑上是显而易见的:单个单词 TextBlocks 较小,因此它们的 Width更小,因此它们在 Viewbox 中比多字对应物增长得更多,使它们以更大的字体显示.

The reason MaxWidth works and not Width is logically obvious when you know how Viewbox works: single words TextBlocks are smaller, so their Width is smaller, so they grow much more in a Viewbox than their multi-words counterparts, making them appear in a bigger font.

扩展此解决方案,您可以将 MaxWidth 绑定到 TextBlock 的父级 MaxWidth 之一,以便在调整窗口大小时进行自动换行.如果您觉得多字 TextBlock 不占用足够的垂直空间,则可以添加一个转换器来修改值(例如,将其除以 2).

Expanding on this solution, you can bind MaxWidth to one of the TextBlock's parent's MaxWidth to have a evolving word-wrapping when the window is resized. You can then add a converter that will modify the value (like, divide it by 2) if you feel like the multi-word TextBlock doesn't take enough vertical space.

代码隐藏转换器:

public class WidthConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        return ((double)value) / 2.0;
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        return ((double)value) * 2.0;
    }
}

XAML 资源:

<Window.Resources>
    <local:MYViewModel x:Key="myVM" />
    <local:WidthConverter x:Key="wc" />
</Window.Resources>

最大宽度:

<TextBlock TextWrapping="Wrap"
    MaxWidth="{Binding ActualWidth, Converter={StaticResource wc}, RelativeSource={RelativeSource AncestorType={x:Type Button}}}"
    Text="{Binding Name}" />

<小时>

下面的例子比解决方案更复杂,更概念验证";我们用转换器拆分多词以在模板化 UniformGrid 的插槽中显示每个单词;行为似乎更自然,但多字串的布局有点粗糙.


The following example is a bit more complicated and more 'proof-of-concept' than solution; we split the multi-words with a converter to display each single word in a slot of a templated UniformGrid; the behavior seems more natural, but the layout of multi-word strings is kind of gross.

XAML:

<Window x:Class="WpfApplication2.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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfApplication2"
        mc:Ignorable="d"
        Title="MainWindow"
        Height="150"
        Width="525">
    <Window.Resources>
        <local:MYViewModel x:Key="myVM" />
        <local:ThingConverter x:Key="tc" />
    </Window.Resources>
    <Grid  DataContext="{Binding Source={StaticResource myVM}}">
        <ItemsControl ItemsSource="{Binding ThingsList, Mode= OneWay}"
                      HorizontalAlignment="Stretch">
            <ItemsControl.ItemsPanel>
                <ItemsPanelTemplate>
                    <UniformGrid Columns="3"
                                 Rows="1"
                                 HorizontalAlignment="Stretch" />
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <Button>
                        <Viewbox>
                            <ItemsControl ItemsSource="{Binding Converter={StaticResource tc}}">
                                <ItemsControl.ItemsPanel>
                                    <ItemsPanelTemplate>
                                        <UniformGrid />
                                    </ItemsPanelTemplate>
                                </ItemsControl.ItemsPanel>
                                <ItemsControl.ItemTemplate>
                                    <DataTemplate>
                                        <TextBlock HorizontalAlignment="Center"
                                                   VerticalAlignment="Center"
                                                   TextAlignment="Center"
                                                   Text="{Binding}" />
                                    </DataTemplate>
                                </ItemsControl.ItemTemplate>
                            </ItemsControl>
                        </Viewbox>
                    </Button>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>
    </Grid>
</Window>

代码隐藏:

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Windows;
using System.Windows.Data;

namespace WpfApplication2
{
    public class ThingConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            return new List<string>(((NamedThing)value).Name.Split(' '));
        }

        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            return ((List<string>)value).Aggregate((s, ss) => s + " " + ss);
        }
    }

    public class NamedThing
    {
        public string Name { get; set; }
    }

    public class MYViewModel
    {
        public ObservableCollection<NamedThing> ThingsList { get; set; }

        public MYViewModel()
        {
            ThingsList = new ObservableCollection<NamedThing>
            {
                new NamedThing {Name = "Short"},
                new NamedThing {Name = "VeryVeryLongWord"},
                new NamedThing {Name = "Several Words in a Row"}
            };
        }
    }

    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }
    }
}

这篇关于如何在 WPF ItemTemplate 中组合自动换行和动态字体大小的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆