22

我正在尝试编写一个简单的 WPF 学习项目,它在可调整大小的主窗口中创建一组按钮。集合中的每个条目都有Button一个,并且该集合的内容在运行时可能会有所不同。我希望按钮填满整个窗口(例如 1 个按钮 @ 100% 宽度、2 个按钮 @ 50% 宽度、3 个按钮 @ 33% 宽度等,所有这些都在 100% 高度)。到目前为止,我所写的简化版本是:

<ItemsControl x:Name="itemscontrolButtons" ItemsSource="{Binding}">
  <ItemsControl.ItemTemplate>
    <DataTemplate>
      <Button Tag="{Binding}">
        <TextBlock Text="{Binding}" />
      </Button>
    </DataTemplate>
  </ItemsControl.ItemTemplate>
  <ItemsControl.ItemsPanel>
    <ItemsPanelTemplate>
      <StackPanel Orientation="Horizontal" />
    </ItemsPanelTemplate>
  </ItemsControl.ItemsPanel>
</ItemsControl>
...    
List<string> listButtonTexts = new List<string>() { "Button1", "Button2" };
...
itemscontrolButtons.DataContext = listButtonTexts;

这导致:

替代文字

我一直无法使按钮拉伸以适应宽度,我尝试使用 aGrid而不是StackPanel徒劳无功。

然后,作为一项可选的改进,我会很感激有关如何调整它的建议,以便如果有太多按钮以至于它们不能正确地放在一行上或者比阈值窄,它将换行到一个新行上(从而减半如果从 1 行变为 2 行,则为按钮高度)。

我想强调一下,我想知道如何以WPF 方式做到这一点。我意识到我可以使用窗口调整大小消息并显式调整控件的大小,这就是我使用 MFC 或 WinForms 所做的事情,但从我所读到的内容来看,这并不是 WPF 应该如何做的事情。

4

3 回答 3

56

用 UniformGrid 替换项目控件的面板,这将调整所有子项的大小,以便一切都完全适合:

<ItemsControl>
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <UniformGrid Rows="1"/>
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
</ItemsControl>
于 2009-08-13T08:39:24.040 回答
2

我能够以 Nir ​​的回答为基础来满足我的可选标准,允许 WPF 管理的多行拉伸。

首先,您必须能够更改模板UniformGrid的属性。为此,您需要存储对它的引用。有多种方法可以实现这一点。我选择处理UniformGrid的Loaded事件并在那时存储一个引用。

<ItemsControl ItemsSource="{Binding}">
  <ItemsControl.ItemsPanel>
    <ItemsPanelTemplate>
      <UniformGrid Rows="1" Loaded="UniformGrid_Loaded" />
    </ItemsPanelTemplate>
  </ItemsControl.ItemsPanel>
</ItemsControl>

在后面的代码中:

UniformGrid uniformgridButtons;
private void UniformGrid_Loaded(object sender, RoutedEventArgs e)
{
  uniformgridButtons = sender as UniformGrid;
}

然后,处理SizeChanged事件并根据您希望的任何标准调整行参数。

private void Window_SizeChanged(object sender, SizeChangedEventArgs e)
{
  if ((uniformgridButtons != null) && (this.Width > 0))
  {
    // Set row count according to your requirements
    uniformgridButtons.Rows = (int)(1 + ((this.MinWidth * iButtonCount) / this.Width));
  }
}

因此,这允许 WPF 像 Nir ​​的答案一样管理拉伸,但允许您显式调整行数。上面的代码给出了这个结果:

替代文字

(此处为动画示例)


2009 年 8 月 28 日更新:

我正在调整我的学习应用程序,以便ItemsControlDataTemplate单独的ResourceDictionary. Loaded但是,无法在外部 XAML 文件中处理诸如此类的事件,ResourceDictionary因为它没有代码隐藏(通常)。因此,我需要缓存对UniformGrid使用不同技术的引用。

我改为使用Alan Haigh 的FindItemsPanel方法(第 10 次回复)。首先,我将其替换为ItemsControl

<ContentPresenter x:Name="contentpresenterButtons" Content="{Binding obscolButtons}" />

然后在我的,ResourceDictionary我把:ItemsControlDataTemplate

<DataTemplate DataType="{x:Type local:Buttons}">
  <ItemsControl ... 
</DataTemplate>

最后,我存储了对模板的引用,UniformGrid如下所示:

private void Window_Loaded(object sender, RoutedEventArgs e) {
  uniformgridButtons = FindItemsPanel<UniformGrid>(contentpresenterButtons);
  // Also call the code in Window_SizeChanged which I put in another method
}

这与我之前的解决方案一样工作,但不需要在ResourceDictionary.

于 2009-08-17T23:45:52.843 回答
0
<!-- width must be explicitly set for this example -->
<StackPanel 
    Name="MyStack" 
    Orientation="Horizontal"
    Width="250"
    Load="Window_Loaded"> 
    <Button/>
    <Button/>
    <Button/>
</StackPanel>

public void Window_Loaded(object sender, RoutedEventArgs e)
{
    UIElementCollection elements = MyStack.Children;
    int count = elements.Count;

    foreach (UIElement element in elements)
    {
        if (element is Button)
            ((Button)element).Width = MyStack.Width / count;
    }
}
于 2009-08-13T06:09:11.863 回答