wpf 如何水平对齐按钮并与 xaml windows 手机平均分布
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/26373285/
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
How to align buttons horizontally and spread equally with xaml windows phone
提问by Thierry
I have an ObservableCollection which contains ViewModel which in turns defines my buttons definitions.
我有一个 ObservableCollection,它包含 ViewModel,它依次定义我的按钮定义。
I've been at it for hours, reading articles after articles but to no avail. I've tried using a Listbox and this is the closest I've got to. My buttons are getting build horizontally but assuming I'm displaying 3 buttons, I want one displayed on the left, one displayed in the middle and one displayed on the right.
我已经研究了几个小时,读了一篇又一篇的文章,但无济于事。我试过使用列表框,这是我最接近的。我的按钮正在水平构建,但假设我显示 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>
As you can see, I set the column dynamically using a property from my ViewModel but I no longer have a grid as I couldn't get it to work, but ideally I'd like to use a grid so that I can specify in which Column to set the button.
如您所见,我使用 ViewModel 中的属性动态设置了列,但我不再有网格,因为我无法让它工作,但理想情况下我想使用网格,以便我可以指定其中列设置按钮。
When I use a StackPanel, it works but the buttons are right next to each other rather than being split evenly through the entire width of the screen.
当我使用 StackPanel 时,它可以工作,但按钮彼此相邻,而不是在整个屏幕宽度上均匀分割。
I've done something similar to the above using ItemsControland using a grid, and I can see each button getting added but they overlap each other in row 0, col 0. If I bind the row to the Column property for testing purposes, it build it correctly but my buttons are displayed on different rows which is not what I want. I want each button to be aligned horizontally.
我已经使用ItemsControl和使用网格做了与上面类似的事情,我可以看到每个按钮都被添加,但它们在第 0 行、第 0 列中相互重叠。如果我将行绑定到 Column 属性以进行测试,它会构建它正确但我的按钮显示在不同的行上,这不是我想要的。我希望每个按钮水平对齐。
How can I achieve this? I know I could just hard code 3 buttons and just change their icons and text and handle the relevant code by passing the relevant button as binded parameter, but ideally I'd like to build the buttons dynamically in a grid and position them using the column.
我怎样才能做到这一点?我知道我可以硬编码 3 个按钮,只需更改它们的图标和文本并通过将相关按钮作为绑定参数传递来处理相关代码,但理想情况下我想在网格中动态构建按钮并使用列定位它们.
Note that the number of column would be fixed i.e. 3, as I'll never have more than this.
请注意,列数将是固定的,即 3,因为我永远不会超过这个数。
Thanks.
谢谢。
采纳答案by Thierry
I eventually found the answer to my problem in an article I found on the web.
我最终在网上找到的一篇文章中找到了问题的答案。
You can check it out here: Using Grids with ItemsControl in XAML
您可以在这里查看:在 XAML 中使用带有 ItemsControl 的网格
In short, you need to subclass the itemsControl and you need overwrite the GetContainerForItemOverride method which will take care of copying the "data" of the ItemTemplate to the ContentPresenter. In this instance, the row and column, but for my requirement, it is just the Column, since my row will always be 0.
简而言之,您需要对 itemsControl 进行子类化,并且需要覆盖 GetContainerForItemOverride 方法,该方法将负责将 ItemTemplate 的“数据”复制到 ContentPresenter。在这种情况下,行和列,但对于我的要求,它只是列,因为我的行将始终为 0。
Here is core part of the code if you don't want to check the full article which resolve the problem of setting controls horizontally in a grid using ItemsControl but note the article takes care of creating rows & columns dynamically as well, which I'm not interested in for my project.
如果您不想查看使用 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;
}
}
The final xaml looks like this:
最终的 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>
Once I used the new control, my buttons were correctly placed inside the grid, and therefore were evenly spaced out as the grid took care of that wit the ColumnDefinitions.
一旦我使用了新控件,我的按钮就被正确地放置在网格内,因此当网格通过 ColumnDefinitions 处理这些问题时,它们被均匀地间隔开。
If anyone knows how to achieve the same without having to create a new control and overriding the method (in other words, pure XAML), please post it as I'd be very interested to see how this can be done.
如果有人知道如何在不必创建新控件和覆盖方法(换句话说,纯 XAML)的情况下实现相同的目标,请发布它,因为我很想知道如何做到这一点。
Thanks and thank you to Robert Garfoot for sharing this great code!
感谢并感谢 Robert Garfoot 分享这么棒的代码!
PS: Note that I've simplified my xaml in order to create a test sample without any style on the buttons, so these are rather large if you try based on this sample.
PS:请注意,我已经简化了我的 xaml,以便在按钮上创建一个没有任何样式的测试示例,因此如果您基于此示例进行尝试,这些示例会相当大。
UPDATE:
更新:
Small typo correction but my grid column definition was defined as
小的错字更正,但我的网格列定义被定义为
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
but as @OmegaMan suggested, to be evenly spread, it should have been defined as
但正如@OmegaMan 所建议的,要均匀分布,它应该被定义为
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
回答by ΩmegaMan
but ideally I'd like to use a grid so that I can specify in which Column to set the button.
但理想情况下,我想使用网格,以便我可以指定在哪个列中设置按钮。
In any Xaml variant, why not just use that Grid, such as shown below, where the Gridis set to consumes all the horizontal space.
在任何 Xaml 变体中,为什么不直接使用它Grid,如下所示,其中Grid设置为消耗所有水平空间。
Then with the grid's center column to be star sizedand to have the rest of the remaining space be consumedafter button 1 and button 3, which auto size into their own spaces:
然后将网格的中心列设为星号大小,并在按钮 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>
If that fails, set button one`s horizontal alignment to be Left and button three's as 'right'.
如果失败,将按钮一的水平对齐设置为左,按钮三的水平对齐设置为“右”。
As an aside with the list box, it may not be stretching to the whole horizontal size of the screen. Check out my answer to a WP8 sizing issue: ListBoxItem HorizontalContentAlignment.
作为列表框的旁白,它可能不会拉伸到屏幕的整个水平尺寸。查看我对 WP8 大小问题的回答: ListBoxItem HorizontalContentAlignment。
回答by spujia
I was able to accomplish this with a stackpanel inside of a grid, avoiding columns altogether. If you set the stackepanel's HorizontalAlignment to "center", it will center itself inside the grid and grow as buttons are added, still staying centered inside of the grid. Then it's just a matter of margins to have the buttons equally spaced:
我能够通过网格内的堆栈面板完成此操作,完全避免使用列。如果您将 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>

