如何水平对齐按钮并与xaml windows phone平分传播

时间:2014-10-15 01:58:45

标签: wpf xaml windows-phone-7 windows-phone-8

我有一个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,因为我将永远不会超过此数。

感谢。

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的Horizo​​ntalAlignment设置为“ 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>