WPF ItemsControl水平方向布局并填充父容器?

6

我想让ItemControl中的项水平排列,并使它们填充父控件。

这是我的XAML代码:

             <ItemsControl ItemsSource="{Binding AnnualWeatherViewModels}" Visibility="{Binding IsAnnualWeatherViewModels, Converter={StaticResource VisibilityConverter}}">
                <ItemsControl.ItemsPanel>
                    <ItemsPanelTemplate>
                        <StackPanel Orientation="Horizontal"></StackPanel>
                    </ItemsPanelTemplate>
                </ItemsControl.ItemsPanel>
                <ItemsControl.ItemTemplate>
                    <DataTemplate>
                        <V:AerosolSimpleWeatherCharacteristicsView DataContext="{Binding}"></V:AerosolSimpleWeatherCharacteristicsView>
                    </DataTemplate>
                </ItemsControl.ItemTemplate>
            </ItemsControl>

我尝试过两种不同的ItemsControl.ItemsPanel变体:

<StackPanel Orientation="Horizontal"></StackPanel>

并且:

<DockPanel LastChildFill="False"></DockPanel>

然而,无论是使用StackPanel还是DockPanel,都无法达到预期的效果。 StackPanel会压缩所有项目,DockPanel将填满父控件的空间,但最后一个项目将占用大部分空间,或者根据LastChildFill的值来决定是否填充父空间。

那么,我该如何水平布置ItemsControl中的项目并使它们填充父控件的空间呢?

最终,我按照答案中建议的创建了这个自定义控件:

public partial class StretchingPanel : Grid
    {
        public static readonly DependencyProperty OrientationProperty =
            DependencyProperty.Register("Orientation", typeof(Orientation), typeof(StretchingPanel), new UIPropertyMetadata(System.Windows.Controls.Orientation.Horizontal));

        public static readonly DependencyProperty FillFirstItemProperty =
            DependencyProperty.Register("FillFirstItem", typeof(bool), typeof(StretchingPanel), new UIPropertyMetadata(true));

        public static readonly DependencyProperty FillFirstItemFactorProperty =
            DependencyProperty.Register("FillFirstItemFactor", typeof(double), typeof(StretchingPanel), new UIPropertyMetadata(1.8));

        public Orientation Orientation
        {
            get
            {
                return (Orientation)GetValue(OrientationProperty);
            }
            set
            {
                SetValue(OrientationProperty, value);
            }
        }

        public bool FillFirstItem
        {
            get
            {
                return (bool)GetValue(FillFirstItemProperty);
            }
            set
            {
                SetValue(FillFirstItemProperty, value);
            }
        }

        public double FillFirstItemFactor
        {
            get
            {
                return (double)GetValue(FillFirstItemFactorProperty);
            }
            set
            {
                SetValue(FillFirstItemFactorProperty, value);
            }
        }

        protected override void OnVisualChildrenChanged(DependencyObject visualAdded, DependencyObject visualRemoved)
        {
            if (Orientation == System.Windows.Controls.Orientation.Horizontal)
            {
                ColumnDefinitions.Clear();
                for (int i = 0; i < Children.Count; ++i)
                {
                    var column = new ColumnDefinition();
                    if (i == 0 && FillFirstItem)
                        column.Width = new GridLength(FillFirstItemFactor, GridUnitType.Star);
                    ColumnDefinitions.Add(column);
                    Grid.SetColumn(Children[i], i);
                }
            }
            else
            {
                RowDefinitions.Clear();
                for (int i = 0; i < Children.Count; ++i)
                {
                    var row = new RowDefinition();
                    if (i == 0 && FillFirstItem)
                        row.Height = new GridLength(FillFirstItemFactor, GridUnitType.Star);
                    RowDefinitions.Add(row);
                    Grid.SetRow(Children[i], i);
                }
            }
            base.OnVisualChildrenChanged(visualAdded, visualRemoved);
        }

        public StretchingPanel()
        {
            InitializeComponent();
        }
    }

DataContext="{Binding}"属性是多余的,请将其删除。这相当于以下C#代码:this.DataContext = this.DataContext; - Federico Berasategui
同时,使用 /> 结尾 XAML 元素也是非常方便的。例如, <V:AerosolSimpleWeatherCharacteristicsView DataContext="{Binding}"></V:AerosolSimpleWeatherCharacteristicsView> 可以简化为 <V:AerosolSimpleWeatherCharacteristicsView/> - Federico Berasategui
2个回答

13

UniformGrid做这个工作。

        <ItemsPanelTemplate>
            <UniformGrid Rows="1"/>
        </ItemsPanelTemplate>

被添加到ItemsControl的控件大小并不相同,需要按照每个控件的基础进行处理。UniformGrid试图使它们的大小都相同,结果会扭曲一切。 - Alex Hope O'Connor
1
只是想说这正是我所需要的。我以前从未听说过UniformGrid,感觉自己错过了很多简单解决方案的可能性。谢谢! - HDL_CinC_Dragon

4

所以你想要按比例拉伸项目。如果标准面板能够实现,那么可以使用Grid(可以具有比例列),这将需要在ItemSource更改后设置ColumnDefinitions。

使用自定义面板很简单:

class ProportionallyStretchingPanel : Panel
{
    protected override Size MeasureOverride(Size availableSize)
    {
        foreach (UIElement child in InternalChildren)
            child.Measure(availableSize);
        return availableSize;
    }

    protected override Size ArrangeOverride(Size availableSize)
    {
        double widthSum = 0.0;
        foreach (UIElement child in InternalChildren)
        {
            widthSum += child.DesiredSize.Width;
        }
        double x = 0.0;
        foreach (UIElement child in InternalChildren)
        {
            double proportionalWidth = child.DesiredSize.Width / widthSum * availableSize.Width;
            child.Arrange(
                new Rect(
                    new Point(x, 0.0),
                    new Point(x + proportionalWidth, availableSize.Height)));
            x += proportionalWidth;
        }
        return availableSize;
    }
}

<ItemsPanelTemplate>
    <local:ProportionallyStretchingPanel"/>
</ItemsPanelTemplate>

你是对的,唯一的方法是创建一个自定义面板,所以我创建了一个网格面板,详见我的更新问题。 - Alex Hope O'Connor

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接