我有一个ObservableCollection,其中包含ViewModel,后者依次定义了我的按钮定义。
我已经呆了好几个小时了,看完一篇又一篇的文章,但无济于事。我尝试过使用列表框,这是我所需要的最接近的列表框。我的按钮正在水平构建,但是假设我要显示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,因为我再也不会超过此数目。
谢谢。
我最终在网上找到了一篇文章,找到了解决问题的方法。
您可以在此处进行检查:在XAML中将网格与ItemsControl一起使用
简而言之,您需要将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),请发布它,因为我非常想知道如何实现。
感谢并感谢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>
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句