WPF ItemsControl 水平方向并填充父项?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/16512476/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-13 08:46:41  来源:igfitidea点击:

WPF ItemsControl horizontal orientation and fill parent?

c#.netwpfxamluser-interface

提问by Alex Hope O'Connor

I am trying to horizontally place the items in an ItemControl whilst making them fill the parent control.

我试图将项目水平放置在 ItemControl 中,同时使它们填充父控件。

Here is my XAMl:

这是我的 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>

The two variations I have tried for ItemsControl.ItemsPanelare:

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

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

and:

和:

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

However neither achieve the desired result, the StackPanelcompresses all the items and the DockPanelwill either fill the space of the parent control with a large portion of space dedicated to the last item or not fill the parent space depending on the value of LastChildFill.

然而,两者都没有达到预期的结果,StackPanel压缩所有项目,并且DockPanel将使用专用于最后一个项目的大部分空间填充父控件的空间,或者不填充父空间,具体取决于 的值LastChildFill

So how can I layout the items of my ItemsControlhorizontally and have them fill the space of the parent control?

那么如何ItemsControl水平布局我的项目并让它们填充父控件的空间?

I ended up creating this custom control as sugested in the answer:

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

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

采纳答案by lisp

So you want to proportionally stretch the items. If it is achievable at all with standard Panels, it's with Grid (which can have proportional columns), this would require setting ColumnDefinitions after the ItemSource changes.

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

It's simple with a custom Panel:

使用自定义面板很简单:

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>

回答by lisp

UniformGriddoes the job.

UniformGrid做这项工作。

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