我正在尝试编写一个简单的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;
结果如下:
我无法使按钮拉伸以适应宽度,而我尝试使用Grid
代替StackPanel
则毫无结果。
然后,作为一个可选的改进,我会很感激如何调整它的建议,如果有这么多的按钮,它们不能正确地适合在一条线上或比一个阈值窄,它将包裹到一个新的线(因此,如果从1行到2行,按钮高度减半。
我想强调一下,我想知道如何使用 WPF方式。我意识到我可以使用窗口调整大小的消息并显式调整控件的大小,这就是我用MFC或WinForms完成它的方式,但是从我读过的内容来看,这不是用WPF完成的事情。
答案 0 :(得分:52)
将项目控件的面板替换为UniformGrid,这将调整所有子项的大小,以便所有内容完全适合:
<ItemsControl>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Rows="1"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
答案 1 :(得分:2)
我能够建立在Nir的答案上,以实现我的可选标准,允许WPF管理的多行拉伸。
首先,您必须能够更改模板 UniformGrid 的属性。为此,您需要存储对它的引用。有multiple methods for accomplishing this。我选择处理 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 事件并根据您希望的任何条件调整rows参数。
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的答案一样管理拉伸,但允许您显式调整行数。上面的代码给出了这个结果:
(动画样本here)
更新2009/08/28:
我正在调整我的学习应用程序,以便ItemsControl
位于单独的DataTemplate
ResourceDictionary
中。但是,Loaded
等事件无法在外部ResourceDictionary
XAML文件中处理,因为它没有代码隐藏(通常)。因此,我需要使用不同的技术缓存对UniformGrid
的引用。
我改为使用Alan Haigh's FindItemsPanel
method (10th reply)。首先,我将ItemsControl
替换为:
<ContentPresenter x:Name="contentpresenterButtons" Content="{Binding obscolButtons}" />
然后在我的ResourceDictionary
中,我将ItemsControl
放入DataTemplate
:
<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
中的事件处理程序。
答案 2 :(得分: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;
}
}