【问题标题】:GridView with 2 columns, fill width具有 2 列的 GridView,填充宽度
【发布时间】:2014-06-02 09:30:55
【问题描述】:

我想要实现的结果非常简单,一个包含 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>

结果如下:

正如所见,它成功地提供了 2 列宽度相等,但 GridView.ItemTemlate 中的 Grid 并没有填满每列的整个宽度。我尝试在GridGridView 本身上设置HorizontalAlignment="Stretch",但没有成功。有人知道这样做吗?

【问题讨论】:

    标签: xaml gridview windows-runtime windows-phone-8.1


    【解决方案1】:

    你可以试试这个:

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

    您可以尝试的另一件事是在GridView 上收到SizeChanged 事件时手动设置ItemWidth/ItemHeight

    如果由于某种原因上述方法不起作用 - 您也可以按照我在下面所做的操作,并在 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
    }
    

    【讨论】:

    • 谢谢。不幸的是,第一个建议没有奏效。但是如果 ItemsPanel 从 WrapGrid 更改为 ItemsWrapGrid,第二个是可能的。
    • 你好,你能解释一下吗?我不明白
    • 您希望我扩展哪一部分?
    • 尝试了基于 ListViewItem 的 ListView 的类似技术,将 Horizo​​ntalAlignment 设置为 Stretch,但没有奏效。这曾经在 Silverlight 中工作!
    • 也试试 Horizo​​ntalContentAlignment?
    【解决方案2】:

    我使用的解决方案基于 Filip Skakuns 的建议,但通过使用此行为制作可重用的用户控件,实现方式略有不同。用户控件具有(除其他外)ColumnsItemsSource 属性。我更改了ItemsWrapGridItemWidth 而不是ItemTemplate 的宽度,并直接在SizeChanged 事件处理程序中执行此操作。

    我还需要使用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;
                }
            }
        }
    }
    

    【讨论】:

    • 这是一个不错的解决方案,但不幸的是,由于某种原因,它在设计时模式下表现不佳。
    【解决方案3】:

    我能够解决一些非常相似的问题,只需将 Item Width 绑定到父 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 中手动定义 ListVewItems 时起作用。但是,当基于 ItemSource 的绑定创建项目时,这不起作用。事实上,我什么也没看到。
    • 这不是真的。这是一段工作代码,其中我们确实通过 ItemsSource 的绑定创建了项目(仔细观察,ListView 绑定到 Devices 可观察集合)。也许如果你将它绑定到一个可观察的集合,然后将项目添加到这个集合而不是直接通过代码定义 ItemsSource 绑定?
    • 由于某种原因,我得到了相同的结果,宽度和高度绑定不起作用。我正在为 itemsource 使用 ObservableCollection。
    【解决方案4】:

    或者,您可以使用 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;
        }
    

    示例

    【讨论】:

      【解决方案5】:

      我的解决办法是:

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-04-16
        • 1970-01-01
        • 2022-01-25
        • 1970-01-01
        • 1970-01-01
        • 2012-10-22
        相关资源
        最近更新 更多