GridView带有2列,填满宽度

14

我想要实现的结果非常简单,就是一个带有2列的列表,两列宽度相等。在Windows Phone 7/8中,可以使用ListBoxWrapPanel作为ItemsPanel,并将ItemWidth设置为240(因为屏幕宽度为480)来轻松实现此目标。

现在我正在编写通用应用程序,但问题在于屏幕的宽度不能保证为480(即使对于手机也不是如此),因此我无法自由地设置ItemWidth以填充屏幕宽度。通过以下XAML,我已几乎实现了所需的效果:

<GridView ItemsSource="{Binding Results}" Margin="12">
    <GridView.ItemTemplate>
        <DataTemplate>
            <Grid>
                <Image Source="{Binding SampleImage}" />
            </Grid>
        </DataTemplate>
    </GridView.ItemTemplate>

    <GridView.ItemsPanel>
        <ItemsPanelTemplate>
            <WrapGrid MaximumRowsOrColumns="2" Orientation="Horizontal" HorizontalChildrenAlignment="Stretch" VerticalChildrenAlignment="Stretch">
            </WrapGrid>
        </ItemsPanelTemplate>
    </GridView.ItemsPanel>
</GridView>

这将产生以下结果: enter image description here

可以看到,它成功地生成了具有相等宽度的2列,但是在GridView.ItemTemplate中的Grid没有填满每个列的整个宽度。我已尝试在GridGridView上设置HorizontalAlignment="Stretch",但都没有成功。有人知道如何解决这个问题吗?

5个回答

16

我的解决方案是:

<GridView ItemsSource="{Binding Results}" Margin="12"
                       SizeChanged="GridView_SizeChanged"
                       x:Name="MyGridView">
<GridView.ItemTemplate>
    <DataTemplate>
        <Grid>
            <Image Source="{Binding SampleImage}" />
        </Grid>
    </DataTemplate>
</GridView.ItemTemplate>

<GridView.ItemContainerStyle>
            <Style TargetType="GridViewItem">
                <Setter Property="HorizontalContentAlignment" Value="Stretch"/>
                <Setter Property="HorizontalAlignment" Value="Stretch"/>
                <Setter Property="VerticalContentAlignment" Value="Stretch"/>
                <Setter Property="VerticalAlignment" Value="Stretch"/>
            </Style>
</GridView.ItemContainerStyle>
</GridView>

后台代码:

private void GridView_SizeChanged(object sender, SizeChangedEventArgs e)
    {
        var panel = (ItemsWrapGrid)MyGridView.ItemsPanelRoot;
        panel.ItemWidth =panel.ItemHeight= e.NewSize.Width / 2;
    }

7
你可以尝试以下方法:
<GridView.ItemContainerStyle>
    <Style
        TargetType="GridViewItem">
        <Setter
            Property="HorizontalAlignment"
            Value="Stretch" />
        <Setter
            Property="VerticalAlignment"
            Value="Stretch" />
    </Style>
 </GridView.ItemContainerStyle>

你可以尝试手动设置GridViewItemWidth / ItemHeight,每当你获得SizeChanged事件时。
如果以上方法无效,你也可以按照我下面所做的,在SizeChanged事件上更新DoubleViewModel资源的Value
<UserControl.Resources>
    <viewModels:DoubleViewModel
        x:Key="ItemWidth"
        Value="120" />
    <viewModels:DoubleViewModel
        x:Key="ItemHeight"
        Value="120" />
</UserControl.Resources>

...

<ItemsControl.ItemTemplate>
    <DataTemplate>
        <local:YourItemTemplateControl
            Width="{Binding Value, Source={StaticResource ItemWidth}}"
            Height="{Binding Value, Source={StaticResource ItemHeight}}" />
    </DataTemplate>
</ItemsControl.ItemTemplate>

DoubleViewModel是什么:

public class DoubleViewModel : BindableBase
{
    #region Value
    /// <summary>
    /// Backing field for the Value property.
    /// </summary>
    private double value;

    /// <summary>
    /// Gets or sets a value indicating the value.
    /// </summary>
    public double Value
    {
        get { return this.value; }
        set { this.SetProperty(ref this.value, value); }
    }
    #endregion
}

1
谢谢。不幸的是第一个建议没有起作用。但是如果将ItemsPanel从WrapGrid更改为ItemsWrapGrid,则第二个建议是可行的。 - Johan Falk
你好,能否再解释详细一些呢?我不太明白。 - garenyondem
你想要我在哪个方面进行扩展? - Filip Skakun
尝试了类似的技术,基于ListViewItem设置HorizontalAlignment为Stretch,但是没有起作用。这在Silverlight中曾经有效! - Klaus Nji
1
也尝试使用HorizontalContentAlignment吗? - Filip Skakun

6
我使用的解决方案基于Filip Skakun的建议,但采用了稍微不同的实现方式,创建了一个可重复使用的用户控件。该用户控件具有(除其他属性外)ColumnsItemsSource属性。我通过在SizeChanged事件处理程序中直接更改ItemsWrapGridItemWidth而非ItemTemplate的宽度来实现这一点。
为了使其工作,我还需要使用ItemsWrapGrid而不是WrapGrid。最终用户控件的XAML如下:
<UserControl
    x:Class="MyProject.CustomControls.ColumnGridView"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    x:Name="ControlRoot">

    <Grid DataContext="{Binding ElementName=ControlRoot}">
        <GridView ItemsSource="{Binding ItemsSource}" ItemTemplate="{Binding ItemTemplate}">
            <GridView.ItemsPanel>
                <ItemsPanelTemplate>
                    <ItemsWrapGrid Orientation="Horizontal" SizeChanged="ItemsWrapGrid_SizeChanged" />
                </ItemsPanelTemplate>
            </GridView.ItemsPanel>
        </GridView>
    </Grid>
</UserControl>

下面是与之对应的代码:

using System;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;

namespace MyProject.CustomControls
{
    public sealed partial class ColumnGridView : UserControl
    {
        public static readonly DependencyProperty ItemTemplateProperty =
            DependencyProperty.Register("ItemTemplate", typeof(DataTemplate), typeof(ColumnGridView), new PropertyMetadata(null));

        public DataTemplate ItemTemplate
        {
            get { return (DataTemplate)GetValue(ItemTemplateProperty); }
            set { SetValue(ItemTemplateProperty, value); }
        }

        public static readonly DependencyProperty ItemsSourceProperty =
            DependencyProperty.Register("ItemsSource", typeof(object), typeof(ColumnGridView), new PropertyMetadata(null));

        public object ItemsSource
        {
            get { return (object)GetValue(ItemsSourceProperty); }
            set { SetValue(ItemsSourceProperty, value); }
        }

        public static readonly DependencyProperty ColumnsProperty =
            DependencyProperty.Register("Columns", typeof(int), typeof(ColumnGridView), new PropertyMetadata(1));

        public int Columns
        {
            get { return (int)GetValue(ColumnsProperty); }
            set
            {
                if (value <= 0) throw new ArgumentOutOfRangeException("Columns must be greater than 0");
                SetValue(ColumnsProperty, value);
            }
        }

        public ColumnGridView()
        {
            this.InitializeComponent();
        }

        private void ItemsWrapGrid_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            ItemsWrapGrid itemsWrapGrid = sender as ItemsWrapGrid;
            if (itemsWrapGrid != null)
            {
                itemsWrapGrid.ItemWidth = e.NewSize.Width / Columns;
            }
        }
    }
}

这是一个不错的解决方案,但出于某些原因,在设计时模式下表现不佳,遗憾。 - Sevenate

4
我曾经遇到过类似的问题,解决方法是将项目宽度绑定到父元素的实际宽度上,代码如下:

Item Width="{Binding ElementName=ParentControl, Path=ActualWidth}"

<ListView Name="allDevicesListView" d:DataContext="{d:DesignData /SampleData/VeraServerSampleData.xaml}" ItemsSource="{Binding Devices}">
<ListView.ItemTemplate>
    <DataTemplate>
        <StackPanel Orientation="Horizontal" Width="{Binding ElementName=allDevicesListView, Path=ActualWidth}">
            <Grid Width="{Binding ElementName=allDevicesListView, Path=ActualWidth}">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="2*"/>
                    <ColumnDefinition Width="*"/>
                </Grid.ColumnDefinitions>
                <TextBlock Text="{Binding Name}" FontSize="24" Grid.Column="0" Margin="0,0,14.333,0" />
                <local:VeraDeviceControl VeraDeviceCategory="DimmableLight" Width="auto" Grid.Column="1"/>
            </Grid>
        </StackPanel>
    </DataTemplate>
</ListView.ItemTemplate>


当在XAML中手动定义ListViewItems时,这似乎是有效的。然而,当项目基于来自ItemSource的绑定创建时,这就不起作用了。事实上,我根本什么都看不到。 - Klaus Nji
这不是真的。这是一段工作代码,其中我们确实有通过ItemsSource绑定创建的项(仔细看,ListView被绑定到Devices可观察集合)。也许如果您将其绑定到可观察集合,然后向该集合添加项,而不是直接通过代码定义ItemsSource绑定? - Vinicius
由于某些原因,我得到了相同的结果,宽度和高度绑定不起作用。而且我正在使用ObservableCollection作为itemsource。 - joe

0

或者您可以使用WrapGrid的Loaded-Event来设置至少ItemWidth

XAML

<Grid Background="LightGreen">

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

    <Grid.RowDefinitions>
        <RowDefinition Height="auto" />
        <RowDefinition Height="auto" />
    </Grid.RowDefinitions>

    <Grid Grid.Row="0" Grid.Column="0" Name="MyGrid" Background="Red">

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

        <TextBlock Grid.Column="0" />
        <TextBlock Grid.Column="1" Text="I.O" />
        <TextBlock Grid.Column="2" Text="N.V" />
        <TextBlock Grid.Column="3" Text="n.I.O" />
    </Grid>

    <Grid Grid.Row="0" Grid.Column="1" Background="Aqua">

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

        <TextBlock Grid.Column="0" />
        <TextBlock Grid.Column="1" Text="I.O" />
        <TextBlock Grid.Column="2" Text="N.V" />
        <TextBlock Grid.Column="3" Text="n.I.O" />
    </Grid>

    <GridView Grid.Row="1"  Grid.ColumnSpan="2"
              Background="LightBlue"
              HorizontalAlignment="Stretch"
              ItemsSource="{Binding Details}"
              ItemContainerStyle="{StaticResource GridViewItemStyleIOhneHover}"
              ItemTemplateSelector="{StaticResource MyProtokollElementDataTemplateSelector}">
        <GridView.ItemsPanel>
            <ItemsPanelTemplate>
                <WrapGrid Orientation="Horizontal"
                          HorizontalAlignment="Stretch"
                          MaximumRowsOrColumns="2"
                          HorizontalChildrenAlignment="Stretch"
                          VerticalChildrenAlignment="Stretch" Loaded="MyWrapGrid_Loaded">
                </WrapGrid>
            </ItemsPanelTemplate>
        </GridView.ItemsPanel>
    </GridView>
</Grid>

代码后台

    private void MyWrapGrid_Loaded(object sender, RoutedEventArgs e)
    {
        var wg = sender as WrapGrid;
        wg.ItemWidth = MyGrid.ActualWidth;
    }

例子

enter image description here


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