【问题标题】:Constant item width in horizontal ItemControl水平 ItemsControl 中的恒定项目宽度
【发布时间】:2011-09-30 03:30:17
【问题描述】:

我需要一个水平组织的ItemsControl,它将其所有项目限制为相同的宽度。我正在使用的项目是UserControls,并构建了一个自动调整大小的TextBlock,显示一个int 值(包含在依赖属性中),周围有一个Border。问题是较小的值会导致更窄的项目,我需要所有项目都相同。我已经考虑了一些解决方案,但我似乎无法做出任何工作。

第一种是将ItemsPanel 模板设置为Grid。这样我就可以使用代码隐藏根据数据源生成所需的列数,并将所有列宽设置为*。难题在于如何为每个项目设置网格列附加属性。

第二种解决方案是将ItemsPanel 模板设置为StackPanel。这会自动正确排列项目,但我无法将每个项目的宽度设置为最宽项目的宽度。

最后一个解决方案是将ItemsPanel 模板设置为UniformGrid,并在数据源更改时设置列数。这将自动正确排列项目并提供统一的宽度。我的问题是我根本无法显示任何项目。我试过手动添加按钮,它们显示得很好。我的UserControl 不会出现。我在下面列出了这个解决方案。

    <Window x:Class="Learning_WPF.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:my="clr-namespace:Learning_WPF"
            xmlns:sys="clr-namespace:System;assembly=mscorlib"
            Title="DateTape" Height="176" Width="500">
        <Window.Resources>
            <my:DateList x:Key="dateList" CollectionChanged="DateList_CollectionChanged" />
        </Window.Resources>
        <ItemsControl x:Name="itemsControl1" ItemsSource="{Binding Source={StaticResource dateList}, Path=/}" Grid.Row="1">
            <ItemsControl.ItemsPanel>
                <ItemsPanelTemplate>
                    <UniformGrid x:Name="daysGrid" Rows="1" />
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
        </ItemsControl>
    </Window>

    public partial class MainWindow : Window
    {
        UniformGrid daysGrid;
        DateList dateList;

        public MainWindow()
        {
            InitializeComponent();
            daysGrid = (UniformGrid)itemsControl1.ItemsPanel.LoadContent();
            dateList = (DateList)FindResource("dateList");
            dateList.Fill(DateTime.Today, DateTime.Today.AddDays(10));
        }

        private void DateList_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            daysGrid.Columns = dateList.Count;
        }

    }

    public class DateList : ObservableCollection<Date>
    {
        public void Fill(DateTime first, DateTime last)
        {
            // implementation fills the array with all of the days between first and last, inclusively
        }
    }

也许有更好的方法来实现我想要实现的目标(可能比使用控件更图形化)...

【问题讨论】:

  • 你试过 UniformGrid。试试看吧?
  • 我确实尝试过,但我之前遇到过麻烦。从那以后,我进行了一些重组。我再试一次...
  • 在我的情况下,我有一个集合,它具有属性 DispayText 并且绑定到按钮内容。为此,我创建了转换器,它将通过识别要显示的最高字符串来获取按钮的宽度,并在 UniformGrid 中设置 Row=1
  • @KishoreKumar,请在下面查看我的解决方案。

标签: wpf grid itemscontrol stackpanel


【解决方案1】:

如果UniformGrid 不适合您的解决方案,您始终可以尝试将ItemContainerStyle 设置为ItemsControl(假设您可以将ListBoxListBoxItem 孩子一起使用) ,就像这样:

<Setter Property="ItemContainerStyle">
    <Setter.Value>
        <Style TargetType="{x:Type ListBoxItem}" >
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type ListBoxItem}">
                        <ContentPresenter Width="75" ... />
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </Setter.Value>
</Setter>

【讨论】:

    【解决方案2】:

    我终于用Grid 让它工作了。我不得不做一些重要的代码隐藏,并且由于三重布局,界面明显缓慢,但它可以工作。欢迎提出改进建议。将此控件插入窗口时,将StartDate 属性从其默认值更改为EndDate 属性之前的值;否则 VS 将被锁定。

    XAML

        <UserControl x:Class="MyProject.DateTape"
                     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                     xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
                     xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
                     xmlns:my="clr-namespace:MyProject"
                     xmlns:sys="clr-namespace:System;assembly=mscorlib"
                     mc:Ignorable="d" 
                     d:DesignHeight="45" d:DesignWidth="188">
            <UserControl.Resources>
                <Thickness x:Key="bottomThickness" Bottom="1" Top="1" Left="0.5" Right="0.5" />
                <Thickness x:Key="topThickness" Bottom="0" Top="1" Left="0.5" Right="0.5" />
                <Style TargetType="Border">
                    <Setter Property="BorderBrush" Value="#FFBEBEBE"/>
                </Style>
                <Style TargetType="TextBlock">
                    <Setter Property="TextAlignment" Value="Center"/>
                    <Setter Property="Margin" Value="6,0"/>
                </Style>
            </UserControl.Resources>
            <Grid x:Name="mainGrid"/>
        </UserControl>
    

    C#

            public partial class DateTape : UserControl
            {
                public static readonly DependencyProperty StartDateProperty =
                    DependencyProperty.Register("StartDate", typeof(DateTime), typeof(DateTape),
                                                new PropertyMetadata(new PropertyChangedCallback(OnDatesChanged)));
                public static readonly DependencyProperty EndDateProperty =
                    DependencyProperty.Register("EndDate", typeof(DateTime), typeof(DateTape),
                                                new PropertyMetadata(new PropertyChangedCallback(OnDatesChanged)));
    
                [Category("Common"),
                 TypeConverter(typeof(DateConverter))]
                public DateTime StartDate
                {
                    get { return (DateTime)GetValue(StartDateProperty); }
                    set { SetValue(StartDateProperty, value); }
                }
                [Category("Common"),
                 TypeConverter(typeof(DateConverter))]
                public DateTime EndDate
                {
                    get { return (DateTime)GetValue(EndDateProperty); }
                    set { SetValue(EndDateProperty, value); }
                }
    
                public DateTape()
                {
                    InitializeComponent();
                }
    
                private void Layout()
                {
                    int dayCount = (EndDate - StartDate).Days;
                    double max = 0;
                    DateTime current = StartDate;
                    ColumnDefinition columnDefinition;
                    Border border;
                    TextBlock textBlock;
                    Binding binding;
                    Size infinity = new Size(double.PositiveInfinity, double.PositiveInfinity);
                    Thickness bottomThickness = (Thickness)Resources["bottomThickness"],
                              topThickness = (Thickness)Resources["topThickness"];
                    mainGrid.ColumnDefinitions.Clear();
                    for (int i = 0; i <= dayCount; i++, current += TimeSpan.FromDays(1))
                    {
                        mainGrid.ColumnDefinitions.Add(columnDefinition = new ColumnDefinition());
                        // Add a day
                        border = new Border();
                        textBlock = new TextBlock();
                        textBlock.Text = current.Day.ToString();
                        border.Child = textBlock;
                        binding = new Binding();
                        binding.Source = bottomThickness;
                        border.SetBinding(Border.BorderThicknessProperty, binding);
                        mainGrid.Children.Add(border);
                        border.Measure(infinity);
                        max = Math.Max(max, border.DesiredSize.Width);
                        Grid.SetRow(border, 2);
                        Grid.SetColumn(border, i);
                    }
                    foreach (ColumnDefinition cd in mainGrid.ColumnDefinitions)
                    {
                        cd.MinWidth = max;
                    }
                }
    
                private static void OnDatesChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
                {
                    (d as DateTape).Layout();
                }
    

    编辑:

    我找到了一种不使用多个布局传递的方法,方法是在将每个 Border 项目添加到 Grid 并跟踪最大宽度时查询它们的 DesiredSize。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-02-05
      • 1970-01-01
      • 1970-01-01
      • 2011-10-08
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多