我有一个ObservableCollection,它包含ViewModel,后者依次定义我的按钮定义。
我已经好几个小时了,在文章之后阅读文章却无济于事。我尝试过使用Listbox,这是我最接近的。我的按钮正在水平构建,但假设我显示3个按钮,我想要一个显示在左边,一个显示在中间,一个显示在右边。
<ListBox Grid.Row="2" ItemsSource="{Binding Links}">
<ListBox.ItemsPanel>
<ItemsPanelTemplate ScrollViewer.HorizontalScrollBarVisibility="Disabled">
<StackPanel Background="Beige" Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<Button Grid.Column="{Binding Column}"
Grid.Row="0"
Width="90"
Height="90">
<ContentControl>
<StackPanel Orientation="Vertical">
<Image Source="{Binding Image}" Width="36" Height="36"
Margin="5" Stretch="UniformToFill"
HorizontalAlignment="Center"/>
<TextBlock Text="{Binding Description}"
Foreground="#0F558E"
FontSize="18"
HorizontalAlignment="Center"/>
</StackPanel>
</ContentControl>
</Button>
</DataTemplate>
</ListBox.ItemTemplate>
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
正如您所看到的,我使用ViewModel中的属性动态设置列,但我不再有网格,因为我无法使其工作,但理想情况下我想使用网格这样我就可以指定在哪个列中设置按钮。
当我使用StackPanel时,它可以工作,但按钮彼此相邻,而不是在屏幕的整个宽度上均匀分割。
我使用ItemsControl
并使用网格完成了与上面类似的操作,我可以看到每个按钮都被添加但是它们在第0行,第0行中相互重叠。如果我绑定了行为了测试目的,它的Column属性,它正确构建它,但我的按钮显示在不同的行上,这不是我想要的。我希望每个按钮都水平对齐。
我怎样才能做到这一点?我知道我可以硬编码3个按钮,只需更改他们的图标和文本,并通过将相关按钮作为绑定参数来处理相关代码,但理想情况下我想在网格中动态构建按钮并使用它们定位它们专栏。
请注意,列的数量将是固定的,即3,因为我将永远不会超过此数。
感谢。
答案 0 :(得分:9)
但理想情况下我想使用网格,以便我可以在其中指定 用于设置按钮的列。
令人困惑的是,为什么你不能只使用那个网格,比如下面的半伪代码,网格占用了所有的水平空间。然后将网格的中心列设置为星号,并在按钮1和按钮3自动调整大小后将其余剩余空间用于其空间:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Button Grid.Column="0"/>
<Button Grid.Column="1" HorizontalAlignment="Center"/>
<Button Grid.Column="2"/>
</Grid>
如果失败,请将按钮1的水平对齐设置为左,按钮3设置为&#39;右&#39;。
作为旁边的列表框,它可能不会拉伸到整个屏幕的水平尺寸。看看我对WP8尺码问题的回答: ListBoxItem HorizontalContentAlignment
答案 1 :(得分:1)
我最终在网上找到的一篇文章中找到了我的问题的答案。
您可以在此处查看:Using Grids with ItemsControl in XAML
简而言之,您需要子类化itemsControl,并且需要覆盖GetContainerForItemOverride方法,该方法将负责将ItemTemplate的“数据”复制到ContentPresenter。在这个例子中,行和列,但根据我的要求,它只是列,因为我的行总是为0。
如果您不想查看解决使用ItemsControl在网格中水平设置控件问题的完整文章,那么这是代码的核心部分,但请注意文章负责创建行和放大器。列也是动态的,我对我的项目不感兴趣。
public class GridAwareItemsControl : ItemsControl
{
protected override DependencyObject GetContainerForItemOverride()
{
ContentPresenter container = (ContentPresenter)base.GetContainerForItemOverride();
if (ItemTemplate == null)
{
return container;
}
FrameworkElement content = (FrameworkElement)ItemTemplate.LoadContent();
BindingExpression rowBinding = content.GetBindingExpression(Grid.RowProperty);
BindingExpression columnBinding = content.GetBindingExpression(Grid.ColumnProperty);
if (rowBinding != null)
{
container.SetBinding(Grid.RowProperty, rowBinding.ParentBinding);
}
if (columnBinding != null)
{
container.SetBinding(Grid.ColumnProperty, columnBinding.ParentBinding);
}
return container;
}
}
最终的xaml看起来像这样:
<controls:GridAwareItemsControl ItemsSource="{Binding Links}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Grid Background="Pink">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
</Grid>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button
Grid.Column="{Binding Column}"
Grid.Row="0"
Width="120" Height="120">
<ContentControl>
<StackPanel Orientation="Vertical">
<Image Source="{Binding Image}" Width="36" Height="36" Margin="5"
Stretch="UniformToFill" HorizontalAlignment="Center"/>
<TextBlock Text="{Binding Description}" Foreground="#0F558E"
FontSize="18" HorizontalAlignment="Center"/>
</StackPanel>
</ContentControl>
</Button>
</DataTemplate>
</ItemsControl.ItemTemplate>
</controls:GridAwareItemsControl>
一旦我使用了新控件,我的按钮就被正确放置在网格中,因此在网格处理了ColumnDefinitions的情况下均匀分布。
如果有人知道如何在不创建新控件和覆盖方法(换句话说,纯XAML)的情况下实现相同目的,请发布它,因为我非常有兴趣看看如何做到这一点。 / p>
感谢Robert Garfoot分享这个优秀的代码!
PS:请注意,我已经简化了我的xaml,以便在按钮上创建没有任何样式的测试样本,因此如果您尝试基于此样本,这些样本相当大。
<强>更新强>
小错字修正但我的网格列定义定义为
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
但正如@OmegaMan建议的那样,要均匀分布,它应该被定义为
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
答案 2 :(得分:0)
我能够在网格内部使用堆栈面板来完成此操作,而完全避免使用列。如果将stackepanel的HorizontalAlignment设置为“ center”,它将在网格内居中并随着添加按钮而增长,但仍保持在网格内居中。然后,将按钮等距隔开只是一个边距问题:
<Grid>
<StackPanel
VerticalAlignment="Stretch"
HorizontalAlignment="Center"
Orientation="Horizontal"
>
<Button HorizontalAlignment="Center" Content="Add" Width="104" Height="32" Margin="24,0"/>
<Button HorizontalAlignment="Center" Content="Edit" Width="104" Height="32" Margin="24,0"/>
<Button HorizontalAlignment="Center" Content="Remove" Width="104" Height="32" Margin="24,0"/>
</StackPanel></Grid>