【问题标题】:How do I make a WPF data template fill the entire width of the listbox?如何使 WPF 数据模板填充列表框的整个宽度?
【发布时间】:2010-09-13 05:13:40
【问题描述】:

我在 WPF 中有一个 ListBox DataTemplate。我希望一个项目紧贴ListBox 的左侧,另一件紧贴右侧,但我不知道该怎么做。

到目前为止,我有一个包含三列的Grid,左右各有内容,中心是一个占位符,其宽度设置为“*”。我哪里错了?

代码如下:

<DataTemplate x:Key="SmallCustomerListItem">
    <Grid HorizontalAlignment="Stretch">
        <Grid.RowDefinitions>
            <RowDefinition/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition/>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>
        <WrapPanel HorizontalAlignment="Stretch" Margin="0">
            <!--Some content here-->
            <TextBlock Text="{Binding Path=LastName}" TextWrapping="Wrap" FontSize="24"/>
            <TextBlock Text=", " TextWrapping="Wrap" FontSize="24"/>
            <TextBlock Text="{Binding Path=FirstName}" TextWrapping="Wrap" FontSize="24"/>

        </WrapPanel>
        <ListBox ItemsSource="{Binding Path=PhoneNumbers}" Grid.Column="2" d:DesignWidth="100" d:DesignHeight="50"
     Margin="8,0" Background="Transparent" BorderBrush="Transparent" IsHitTestVisible="False" HorizontalAlignment="Stretch"/>
    </Grid>
</DataTemplate>

【问题讨论】:

  • 您能否发布您的 XAML,以便清楚您目前拥有什么?

标签: wpf layout listbox datatemplate


【解决方案1】:

我还必须设置:

HorizontalContentAlignment="Stretch"

关于包含ListBox

【讨论】:

  • 塔帕尔。谷歌搜索帮助,这是第一个链接。不错的一个:)
  • @Eric Haskins 我对 Windows Phone 的 Pivot 控件有同样的问题 (&lt;controls:Pivot.ItemTemplate&gt;&lt;DataTemplate /&gt;&lt;/controls:Pivot.ItemTemplate&gt;) 但是我应该把代码放在哪里?我尝试了一些,但我无法弄清楚。
  • 给 Windows Phone 用户的注意事项 - 这不起作用;该属性被 ListBox 的 ItemContainerStyle 覆盖。要使其正常工作,请在此处查看 Gabriel Mongeon 的回答:stackoverflow.com/questions/838828/…
  • 这一定是最烦人的 UI hack 之一。为什么默认不设置这个?嘘。
  • 另外值得一提的是,您可能需要将其设置为 ListBoxItem 的样式,如果有的话:&lt;ListView.ItemContainerStyle&gt; &lt;Style TargetType="ListViewItem"&gt; &lt;Setter Property="HorizontalContentAlignment" Value="Stretch" /&gt; &lt;/Style&gt; &lt;/ListView.ItemContainerStyle&gt;
【解决方案2】:
<Grid.Width>
    <Binding Path="ActualWidth" 
             RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType={x:Type ScrollContentPresenter}}" />
</Grid.Width>

【讨论】:

  • 我喜欢这种方法的简单性。它不仅确保小项目填满宽度,还确保内容希望非常宽的项目被限制在列表框宽度内。
  • 正是我要搜索的内容:太小时填充宽度,太大时限制宽度。
  • 我刚刚注意到这个解决方案会导致 ListBox 的宽度始终比项目的宽度略小,这会稍微切断项目并激活列表框底部的水平滚动条。我通过显式禁用水平滚动来解决此问题。
【解决方案3】:

好的,这就是你所拥有的:

第 0 列:WrapPanel
第 1 列:无
第2栏:ListBox

听起来您希望WrapPanel 在左边缘,ListBox 在右边缘,并留出空间来占据中间的剩余部分。

最简单的方法实际上是使用DockPanel,而不是Grid

<DockPanel>
    <WrapPanel DockPanel.Dock="Left"></WrapPanel>
    <ListBox DockPanel.Dock="Right"></ListBox>
</DockPanel>

这应该在WrapPanelListBox 之间留出空白空间。

【讨论】:

    【解决方案4】:

    扩展 Taeke 的答案,将 ScrollViewer.HorizontalScrollBarVisibility="Hidden" 设置为 ListBox 允许子控件采用父控件的宽度而不显示滚动条。

    <ListBox Width="100" ScrollViewer.HorizontalScrollBarVisibility="Hidden">                
        <Label Content="{Binding Path=., Mode=OneWay}" HorizontalContentAlignment="Stretch" Height="30" Margin="-4,0,0,0" BorderThickness="0.5" BorderBrush="Black" FontFamily="Calibri" >
            <Label.Width>
                <Binding Path="Width" RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType={x:Type ListBox}}" />
            </Label.Width>
        </Label>
    </ListBox >
    

    【讨论】:

      【解决方案5】:

      默认情况下Grid 应该占据ListBox 的整个宽度,因为它的默认ItemsPanelVirtualizingStackPanel。我假设您没有更改了ListBox.ItemsPanel

      也许如果你去掉中间的ColumnDefinition(其他是默认的"*"),把HorizontalAlignment="Left"放在你的WrapPanelHorizontalAlignment="Right"放在ListBox的电话号码上。您可能需要稍微更改 ListBox 以使电话号码更加右对齐,例如为它们创建一个 DataTemplate

      【讨论】:

        【解决方案6】:

        如果您想使用Grid,那么您需要将您的ColumnDefinitions 更改为:

            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="Auto"/>
                <ColumnDefinition Width="*"/>
                <ColumnDefinition Width="Auto"/>
            </Grid.ColumnDefinitions>
        

        如果您不需要使用Grid,那么您可以使用DockPanel

            <DockPanel>
                <WrapPanel DockPanel.Dock="Left">
                    <!--Some content here-->
                    <TextBlock Text="{Binding Path=LastName}" TextWrapping="Wrap" FontSize="24"/>
                    <TextBlock Text=", " TextWrapping="Wrap" FontSize="24"/>
                    <TextBlock Text="{Binding Path=FirstName}" TextWrapping="Wrap" FontSize="24"/>
                </WrapPanel>
                <ListBox DockPanel.Dock="Right" ItemsSource="{Binding Path=PhoneNumbers}" 
         Margin="8,0" Background="Transparent" BorderBrush="Transparent" IsHitTestVisible="False"/>
                <TextBlock />
            </DockPanel>
        

        注意最后的TextBlock。任何未定义"DockPanel.Dock" 的控件都将填充剩余空间。

        【讨论】:

        • 这不会使数据模板填充列表框的宽度。
        • 您需要在列表框上使用 Horizo​​ntalContentAlignment="Stretch",如下所述
        【解决方案7】:

        Taeke 的回答效果很好,根据 vancutterromney 的回答,您可以禁用水平滚动条以摆脱恼人的尺寸不匹配。但是,如果您确实想要两全其美——在不需要时移除滚动条,但在 ListBox 变得太小时自动启用它,您可以使用以下转换器:

        /// <summary>
        /// Value converter that adjusts the value of a double according to min and max limiting values, as well as an offset. These values are set by object configuration, handled in XAML resource definition.
        /// </summary>
        [ValueConversion(typeof(double), typeof(double))]
        public sealed class DoubleLimiterConverter : IValueConverter
        {
            /// <summary>
            /// Minimum value, if set. If not set, there is no minimum limit.
            /// </summary>
            public double? Min { get; set; }
        
            /// <summary>
            /// Maximum value, if set. If not set, there is no minimum limit.
            /// </summary>
            public double? Max { get; set; }
        
            /// <summary>
            /// Offset value to be applied after the limiting is done.
            /// </summary>
            public double Offset { get; set; }
        
            public static double _defaultFailureValue = 0;
        
            public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
            {
                if (value == null || !(value is double))
                    return _defaultFailureValue;
        
                double dValue = (double)value;
                double minimum = Min.HasValue ? Min.Value : double.NegativeInfinity;
                double maximum = Max.HasValue ? Max.Value : double.PositiveInfinity;
                double retVal = dValue.LimitToRange(minimum, maximum) + Offset;
                return retVal;
            }
        
            public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
            {
                throw new NotImplementedException();
            }
        }
        

        然后根据所需的最大/最小值在 XAML 中定义它,以及处理其他答案中提到的烦人的 2 像素大小不匹配的偏移量:

        <ListBox.Resources>
            <con:DoubleLimiterConverter x:Key="conDoubleLimiter" Min="450" Offset="-2"/>
        </ListBox.Resources>
        

        然后在Width绑定中使用转换器:

        <Grid.Width>
            <Binding Path="ActualWidth" RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType={x:Type ScrollContentPresenter}}" Converter="{StaticResource conDoubleLimiter}"  />
        </Grid.Width>
        

        【讨论】:

          【解决方案8】:

          Taeke 的答案中的方法强制水平滚动条。这可以通过添加一个转换器来解决,该转换器将网格的宽度减小垂直滚动条控件的宽度。

          using System;
          using System.Globalization;
          using System.Windows;
          using System.Windows.Data;
          using System.Windows.Markup;
          
          namespace Converters
          {
              public class ListBoxItemWidthConverter : MarkupExtension, IValueConverter
              {
                  private static ListBoxItemWidthConverter _instance;
          
                  #region IValueConverter Members
          
                  public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
                  {
                      return System.Convert.ToInt32(value) - SystemParameters.VerticalScrollBarWidth;
                  }
          
                  public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
                  {
                      throw new NotImplementedException();
                  }
          
                  #endregion
          
                  public override object ProvideValue(IServiceProvider serviceProvider)
                  {
                      return _instance ?? (_instance = new ListBoxItemWidthConverter());
                  }
              }
          }
          

          将命名空间添加到 XAML 的根节点。

          xmlns:converters="clr-namespace:Converters"
          

          并更新网格宽度以使用转换器。

          <Grid.Width>
              <Binding Path="ActualWidth" RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType={x:Type ScrollContentPresenter}}" Converter="{converters:ListBoxItemWidthConverter}"/>
          </Grid.Width>
          

          【讨论】:

          • 这应该用 Horizo​​ntalContentAlignment 来完成。
          • @EdPlunkett 你的意思是 ListBox 上的 Horizo​​ntalContentAlignment,就像 Eric Haskins 接受的答案一样?如果是这样,我无法让它发挥作用,这就是为什么我转向这种更糟糕的方法。
          • 天啊,正确的一般答案甚至不在此页面上。答案在这里:stackoverflow.com/a/2924249/424129 -- 在列表框中的列表框 item 控件上设置HorizontalContentAlignment="Stretch",您可以通过ListBox.ItemContainerStyle 执行此操作。
          • @EdPlunkett 我确实遇到了那个答案,但除非我一直忽略一些简单的东西,否则它也不适合我。可能是因为我使用的是数据模板。
          猜你喜欢
          • 1970-01-01
          • 2013-01-17
          • 2017-04-13
          • 1970-01-01
          • 1970-01-01
          • 2020-07-31
          • 1970-01-01
          相关资源
          最近更新 更多