2009-08-13 173 views
21

我正在尝试编写一个简单的WPF学习项目,它在可调整大小的主窗口内创建一组按钮。每个集合中的条目将有一个Button,并且该集合的内容在运行时可能会有所不同。我希望按钮填满整个窗口(例如,100%宽度的1个按钮,宽度50%的2个按钮,宽度33%的3个按钮等)。什么我至今写一个简化版本是:拉伸控件填充ItemsControl

<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; 

这导致了这个:

alt text

我已经无法使按钮被拉伸以适应宽度和我的尝试使用Grid而不是StackPanel是徒劳的。

然后,作为一个可选的改进,我将不胜感激关于如何调整它的建议,以便如果有太多的按钮,他们无法适合一条线或窄于阈值,它会包装到一个新的线(如果从1行到2行,则将按钮高度减半)。

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

回答

48

更换的项目控制的一个UniformGrid面板,这将大小所有的孩子,所以一切完全适合:

<ItemsControl> 
    <ItemsControl.ItemsPanel> 
     <ItemsPanelTemplate> 
      <UniformGrid Rows="1"/> 
     </ItemsPanelTemplate> 
    </ItemsControl.ItemsPanel> 
</ItemsControl> 
+0

这正是我需要的主要目标,谢谢。 – Gregyski 2009-08-13 15:07:23

+0

感谢Nir的回答,我能够完成可选标准。详情在我发布到这个问题的答案中。在Meta上推荐我这样处理这种情况。 http://meta.stackexchange.com/questions/14306/my-improved-answer-based-on-anothers-accepted-answer-for-my-own-question – Gregyski 2009-08-17 23:53:43

+0

谢谢!这正是我所缺少的将项目及其面板均匀分布在列表框中的缺失。 – 2013-03-15 01:47:50

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; 
    } 
} 
+0

我编辑我的帖子只有20分钟之前,你回应解释说,我想避免明确设置宽度。对不起,我应该首先考虑包括这一要求。如果要使用WrapPanel,则可以根据我的第二要求明确地管理像这样的维度(以及处理调整大小消息)。谢谢。 – Gregyski 2009-08-13 15:11:14

2

我是能够建立在尼尔回答履行我的可选标准允许多行WPF管理拉伸。

首先你必须能够改变模板的属性UniformGrid。为此,您需要存储对其的引用。有multiple methods for accomplishing this。我选择处理加载的事件UniformGrid并在那时存储引用。

<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来管理尼尔回答拉伸一样,但可以让你明确调整的行数。上面的代码给出了这样的结果:

alt text

(动画样本here


更新2009/08/28:

我调整我的学习应用程序,以便ItemsControl在单独的ResourceDictionary中位于DataTemplate中。但是,诸如Loaded的事件无法在外部ResourceDictionary XAML文件中处理,因为它没有代码隐藏(通常)。因此,我需要使用不同的技术来缓存对UniformGrid的引用。我想用Alan Haigh's FindItemsPanel method (10th reply)。首先,我取代了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 
} 

这与我以前的解决方案一样,但不需要0123中的事件处理程序。

相关问题