在容器中创建 n 个可变大小的按钮
Creating n number of variable sized buttons in a container
我需要创建 UI 如下(一种标签云控件)
- n 个按钮(数量将在运行时确定)
- 每个按钮将根据其内容具有不同的宽度
- 最多连续 3 个按钮
我尝试了以下操作
- VariableSizedWrapGrid 作为 GridView 的 ItemsPanel(它需要 RowSpan
和 ColumnSpan 被指定这是不可行的,因为宽度是
在运行时确定)
- 水平方向的 StackPanel(所有按钮排成一行)
有什么想法吗?
基本上,VariableSizedWrapGrid 以相同的大小对待它的所有子项。您可以使用 ColumnSpan 和 RowSpan 来扩展 child 的区域。
另一种方法是创建一个 WrapPanel 用户控件,然后使用它来代替 VariableSizedWrapGrid。这将按照您的描述调整输出。
Here 是一篇关于如何根据您的要求创建 WrapPanel 的精彩博文。
我基于此博客创建了一个 TagsPanel
以用于我的一个应用程序。关键是遍历项目并获取实际大小并根据面板的可用宽度进行设置。见下文。
public class TagsPanel : Panel
{
protected override Size MeasureOverride(Size availableSize)
{
// Just take up all of the width
Size finalSize = new Size { Width = availableSize.Width };
double x = 0;
double rowHeight = 0d;
foreach (var child in Children)
{
// Tell the child control to determine the size needed
child.Measure(availableSize);
x += child.DesiredSize.Width;
if (x > availableSize.Width)
{
// this item will start the next row
x = child.DesiredSize.Width;
// adjust the height of the panel
finalSize.Height += rowHeight;
rowHeight = child.DesiredSize.Height;
}
else
{
// Get the tallest item
rowHeight = Math.Max(child.DesiredSize.Height, rowHeight);
}
}
// Add the final height
finalSize.Height += rowHeight;
return finalSize;
}
protected override Size ArrangeOverride(Size finalSize)
{
Rect finalRect = new Rect(0, 0, finalSize.Width, finalSize.Height);
double rowHeight = 0;
foreach (var child in Children)
{
if ((child.DesiredSize.Width + finalRect.X) > finalSize.Width)
{
// next row!
finalRect.X = 0;
finalRect.Y += rowHeight;
rowHeight = 0;
}
// Place the item
child.Arrange(new Rect(finalRect.X, finalRect.Y, child.DesiredSize.Width, child.DesiredSize.Height));
// adjust the location for the next items
finalRect.X += child.DesiredSize.Width;
rowHeight = Math.Max(child.DesiredSize.Height, rowHeight);
}
return finalSize;
}
}
并在如下 GridView
中使用它。
<GridView ItemsSource="{Binding tags}" >
<GridView.ItemTemplate>
<DataTemplate>
<Button Content="{Binding ''}" Margin="5"/>
</DataTemplate>
</GridView.ItemTemplate>
<GridView.ItemsPanel>
<ItemsPanelTemplate>
<local:TagsPanel/>
</ItemsPanelTemplate>
</GridView.ItemsPanel>
</GridView>
我需要创建 UI 如下(一种标签云控件)
- n 个按钮(数量将在运行时确定)
- 每个按钮将根据其内容具有不同的宽度
- 最多连续 3 个按钮
我尝试了以下操作
- VariableSizedWrapGrid 作为 GridView 的 ItemsPanel(它需要 RowSpan 和 ColumnSpan 被指定这是不可行的,因为宽度是 在运行时确定)
- 水平方向的 StackPanel(所有按钮排成一行)
有什么想法吗?
基本上,VariableSizedWrapGrid 以相同的大小对待它的所有子项。您可以使用 ColumnSpan 和 RowSpan 来扩展 child 的区域。
另一种方法是创建一个 WrapPanel 用户控件,然后使用它来代替 VariableSizedWrapGrid。这将按照您的描述调整输出。
Here 是一篇关于如何根据您的要求创建 WrapPanel 的精彩博文。
我基于此博客创建了一个 TagsPanel
以用于我的一个应用程序。关键是遍历项目并获取实际大小并根据面板的可用宽度进行设置。见下文。
public class TagsPanel : Panel
{
protected override Size MeasureOverride(Size availableSize)
{
// Just take up all of the width
Size finalSize = new Size { Width = availableSize.Width };
double x = 0;
double rowHeight = 0d;
foreach (var child in Children)
{
// Tell the child control to determine the size needed
child.Measure(availableSize);
x += child.DesiredSize.Width;
if (x > availableSize.Width)
{
// this item will start the next row
x = child.DesiredSize.Width;
// adjust the height of the panel
finalSize.Height += rowHeight;
rowHeight = child.DesiredSize.Height;
}
else
{
// Get the tallest item
rowHeight = Math.Max(child.DesiredSize.Height, rowHeight);
}
}
// Add the final height
finalSize.Height += rowHeight;
return finalSize;
}
protected override Size ArrangeOverride(Size finalSize)
{
Rect finalRect = new Rect(0, 0, finalSize.Width, finalSize.Height);
double rowHeight = 0;
foreach (var child in Children)
{
if ((child.DesiredSize.Width + finalRect.X) > finalSize.Width)
{
// next row!
finalRect.X = 0;
finalRect.Y += rowHeight;
rowHeight = 0;
}
// Place the item
child.Arrange(new Rect(finalRect.X, finalRect.Y, child.DesiredSize.Width, child.DesiredSize.Height));
// adjust the location for the next items
finalRect.X += child.DesiredSize.Width;
rowHeight = Math.Max(child.DesiredSize.Height, rowHeight);
}
return finalSize;
}
}
并在如下 GridView
中使用它。
<GridView ItemsSource="{Binding tags}" >
<GridView.ItemTemplate>
<DataTemplate>
<Button Content="{Binding ''}" Margin="5"/>
</DataTemplate>
</GridView.ItemTemplate>
<GridView.ItemsPanel>
<ItemsPanelTemplate>
<local:TagsPanel/>
</ItemsPanelTemplate>
</GridView.ItemsPanel>
</GridView>