GridView с двумя столбцами, шириной заливки
Результат, который я хочу достичь, довольно прост, список из 2 столбцов, имеющих равную ширину. В Windows Phone 7/8 это может быть легко достигнуто с помощью ListBox
с WrapPanel
как 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 столбца с равной шириной, НО Grid
в GridView.ItemTemlate
не заполняет всю ширину каждого столбца. Я попытался установить HorizontalAlignment="Stretch"
как на Grid
, так и на GridView
без каких-либо успехов. Кто-нибудь имеет представление об этом?
Ответы
Ответ 1
Вы можете попробовать следующее:
<GridView.ItemContainerStyle>
<Style
TargetType="GridViewItem">
<Setter
Property="HorizontalAlignment"
Value="Stretch" />
<Setter
Property="VerticalAlignment"
Value="Stretch" />
</Style>
</GridView.ItemContainerStyle>
Другое, что вы могли бы попробовать, - вручную установить ItemWidth
/ItemHeight
всякий раз, когда вы получаете событие SizeChanged
на GridView
.
Если по какой-то причине это не работает, вы также можете сделать то, что я делаю ниже, и обновить Value
ресурсов DoubleViewModel
на событиях SizeChanged
:
<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
}
Ответ 2
Мое решение:
<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;
}
Ответ 3
Решение, которое я использовал, было основано на предложении Филиппа Скакунса, но небольшая другая реализация, сделав для этого многопользовательский User Control. Пользовательский контроль имеет (среди прочих) Columns
и ItemsSource
свойства. Я изменяю ItemWidth
ItemsWrapGrid
вместо ширины 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;
}
}
}
}
Ответ 4
Мне удалось решить что-то очень похожее, просто привязывая 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>
Ответ 5
В качестве альтернативы вы можете использовать Loaded-Event из вашего WrapGrid
, чтобы установить как минимум 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>
Codebehind
private void MyWrapGrid_Loaded(object sender, RoutedEventArgs e)
{
var wg = sender as WrapGrid;
wg.ItemWidth = MyGrid.ActualWidth;
}
Пример
![enter image description here]()