2016-09-30 106 views
1

对于单个项目,我看到的建议是对前者使用TextBlock,将TextWrapping="true"用于前者,对后者使用Viewbox。然而,这两者并不能很好地结合在一起。我见过的将两者合并的唯一方法是在TextBlock][1]上明确设置一个[Width,但这需要知道高级文本的宽度,因为不同长度的文本只能很好地处理不同宽度而不适合使用与模板化,因为理想的长度将是可变的,事先不知道。如何在WPF ItemTemplate中结合自动换行和动态字体大小

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

enter image description here

其中一期工程为两个单词项OK,但多字,如果包裹在多线中的一条将填补该地区更好。

设置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(); 
    } 
} 
+0

只是一个大胆的想法,怎么样使用转换器来分割多一个字的多字串字符串,并将它们放入ViewBox中的某种StackPanel中?我从来没有使用ViewBox,所以我不知道它会工作,但它可能是一个跟踪。 – Kilazur

+0

@Kilazur远远超出我迄今为止所做的任何事情,我不确定我会如何去接近尝试。 –

回答

1

的问题是,你的Viewbox控件规模无论是内部的,但的TextBlocks不知道在它们所包含的内容中,只要它们被允许(默认为Infinity),它们就会逐渐增长(宽度方向)。

第一个快速解决方案是将MaxWidth(例如100)值设置为TextBlock。这样,多字TextBlock只会简单地反应为单个词:它会增长和缩小,但换行不会改变。

原因MaxWidth的作品,而不是Width在逻辑上是明显的,当你知道Viewbox控件是如何工作的:单个词的TextBlocks较小,所以他们Width更小,等他们长大更在视框比他们多的话同行,使他们以更大的字体出现。


这个解决方案扩展,可以绑定MaxWidth到TextBlock的父母的MaxWidth之一,有一个不断变化的文字环绕时,窗口大小。如果您觉得多字TextBlock没有足够的垂直空间,则可以添加一个将修改该值的转换器(如将其除以2)。

代码隐藏转换器:

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> 

MaxWidth:

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

下面的例子是一个比较复杂的多的“证据概念“而不是解决方案;我们用转换器分割多个单词以在模板化的UniformGrid的槽中显示每个单词;这种行为似乎更自然,但多字串的布局有点粗糙。

enter image description here

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

我会捣鼓,看看能不能找到合理的东西,我想要的是类似于前两个按钮的第一个图像和第三个第二个图像的东西。 –

+0

@丹我添加了一个更简单的解决方案(和解释),只需将您的'TextBlock'的MaxWidth属性设置为令您满意的东西(100似乎很好地工作)。 – Kilazur

+0

这是朝着正确方向迈出的一步,比我之前所做的更好;但是在“a”和“row”之间分割“连续几个词”也不是那么好。 –