如何在WPF ItemTemplate

时间:2016-09-30 13:36:15

标签: c# wpf xaml layout

我看到的针对单个项目的建议是使用TextBlockTextWrapping="true"代表前者,Viewbox代表后者。然而,两人并不能很好地融合在一起。我见过的唯一合并两者的是在Width上明确设置[TextBlock][1],但这需要知道高级文本的宽度,因为不同长度的文本只能很好地解决宽度不同,不适合用于模板,因为理想的长度是可变的,事先不知道。

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

enter image description here

哪个适用于两个单字项目,但如果包裹在多行上,则多字词会更好地填充该区域。

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

enter image description here

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

我用于上述示例的XAML是:

<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();
    }
}

1 个答案:

答案 0 :(得分:1)

问题是你的Viewbox可以扩展其内部的任何内容,但是TextBlocks不知道它们包含什么,只是在它们允许的范围内增长(宽度方面)(这是{默认情况下为{1}}。

第一个快速解决方案是将Infinity(例如100)值设置为MaxWidth。通过这种方式,多词TextBlock将完全像单词一样反应:它会增长和缩小,但包装词不会改变。

当您了解Viewbox的工作原理时,TextBlock的工作原因而非MaxWidth在逻辑上是显而易见的:单个单词TextBlocks较小,因此他们的Width较小,因此他们的成长更多一个Viewbox而不是它们的多词对应物,使它们以更大的字体显示。

扩展此解决方案,您可以将MaxWidth绑定到TextBlock的父级MaxWidth之一,以便在调整窗口大小时进行不断变换的自动换行。然后,如果您认为多字Width没有足够的垂直空间,则可以添加一个将修改该值的转换器(例如,除以2)。

代码隐藏转换器:

TextBlock

XAML资源:

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;
    }
}

MaxWidth:

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

以下示例有点复杂,更多的概念验证&#39;比解决方案;我们用转换器分割多个单词,以显示模板化UniformGrid的一个槽中的每个单词;行为似乎更自然,但多字符串的布局有点粗糙。

enter image description here

XAML:

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

代码隐藏:

<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>