- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我一直在试图解决一个看似简单的问题。我想要一个控件(或一些 XAML 布局魔法),其行为类似于具有一些高度为 * 的行的网格,但支持列的换行。 hell ;称之为 WrapGrid。 :)
这是一个可视化的模型。想象一下这样定义的网格:
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="400">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Button Grid.Row="0" MinHeight="30">I'm auto-sized.</Button>
<Button Grid.Row="1" MinHeight="90">I'm star-sized.</Button>
<Button Grid.Row="2" MinHeight="30">I'm auto-sized.</Button>
<Button Grid.Row="3" MinHeight="90">I'm star-sized, too!</Button>
<Button Grid.Row="4" MinHeight="30">I'm auto-sized.</Button>
<Button Grid.Row="5" MinHeight="30">I'm auto-sized.</Button>
</Grid>
</Window>
我希望这个面板做的是当项目不能变得比它的minHeight更小时,将项目包装到一个附加列中。这是我制作的一些模型的可怕MSPaint,详细说明了这个过程。
回想一下 XAML,自动调整大小的按钮的 minHeights 为 30,星形按钮的 minHeights 为 90。
这个模型只是两个并排的网格,我在设计器中手动移动按钮。可以想象,这可以通过编程来完成,并作为一种复杂的解决方案。
如何做到这一点?我会接受任何解决方案,无论是通过 xaml 还是有一些代码隐藏(尽管如果可能的话,我更喜欢纯 XAML,因为 xaml 代码隐藏在 IronPython 中更难实现)。
更新了赏金
<小时/>我设法弄清楚如何在我的 IPy 应用程序中使用 Meleak 的解决方案:
1) 我使用 csc
将 WrapGridPanel.cs
编译为 DLL:
C:\Projects\WrapGridTest\WrapGridTest>csc /target:library "WrapGridPanel.cs" /optimize /reference:"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.0\PresentationFramework.dll" /reference:"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.0\PresentationCore.dll" /reference:"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.0\WindowsBase.dll" /reference:"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.0\System.Xaml.dll"
更新:添加了 /optimize
开关,这会带来小幅性能提升
2) 我使用以下行将其添加到应用程序的 xaml 中。
xmlns:local="clr-namespace:WrapGridTest;assembly=WrapGridPanel.dll"
这运行得很好,但它破坏了设计者。我还没有真正找到解决方法,这看起来是 VS2010 中的一个错误。因此,作为一种解决方法,为了能够使用设计器,我只需在运行时以编程方式添加 WrapGridPanel:
clr.AddReference("WrapGridPanel.dll")
from WrapGridTest import WrapGridPanel
wgp = WrapGridPanel()
调整大小时性能缓慢:
在我的 IronPython 应用程序中,调整包含此 WrapGridPanel 的窗口大小既慢又麻烦。 RecalcMatrix()
算法可以优化吗?也许可以减少调用它的频率吗?也许正如尼古拉斯建议的那样,覆盖 MeasureOverride 和 ArrangeOverride 会表现更好?
更新:根据 VS2010 Instrumentation Profiler,RecalcMatrix() 中 97% 的时间都花在 Clear() 和 Add() 上。就地修改每个元素将带来巨大的性能提升。我自己正在尝试,但修改别人的代码总是很困难...... /image/tMTWU.png
如果您想尝试一下,这里是我的实际应用程序 UI 的一部分的模型,采用 XAML 格式。 http://pastebin.com/2EWY8NS0
最佳答案
更新
优化了 RecalcMatrix
,以便仅在需要时重建 UI。除非必要,否则它不会接触 UI,因此速度应该快得多。
再次更新
修复了使用 Margin
我认为您所看到的基本上是一个具有水平方向的 WrapPanel
,其中每个元素都是 1 列Grid
。 Column 中的每个元素都有一个相应的 RowDefinition
,其中 Height
属性与其子元素上设置的附加属性 ("WrapHeight"
) 相匹配。该面板必须位于 Grid
本身中,并具有 Height="*"
和 Width="Auto"
因为子项应该被定位由可用的高度
决定,而不关心可用的宽度
。
我对此进行了实现,并将其称为 WrapGridPanel
。你可以像这样使用它
<local:WrapGridPanel>
<Button MinHeight="30" local:WrapGridPanel.WrapHeight="Auto">I'm auto-sized.</Button>
<Button MinHeight="90" local:WrapGridPanel.WrapHeight="*">I'm star-sized.</Button>
<Button MinHeight="30" local:WrapGridPanel.WrapHeight="Auto">I'm auto-sized.</Button>
<Button MinHeight="90" local:WrapGridPanel.WrapHeight="*">I'm star-sized, too!</Button>
<Button MinHeight="30" local:WrapGridPanel.WrapHeight="Auto">I'm auto-sized.</Button>
<Button MinHeight="30" local:WrapGridPanel.WrapHeight="Auto">I'm auto-sized.</Button>
</local:WrapGridPanel>
WrapGridPanel.cs
[ContentProperty("WrapChildren")]
public class WrapGridPanel : Grid
{
private WrapPanel m_wrapPanel = new WrapPanel();
public WrapGridPanel()
{
ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1.0, GridUnitType.Auto) } );
RowDefinitions.Add(new RowDefinition { Height = new GridLength(1.0, GridUnitType.Star) } );
Children.Add(m_wrapPanel);
WrapChildren = new ObservableCollection<FrameworkElement>();
WrapChildren.CollectionChanged += WrapChildren_CollectionChanged;
DependencyPropertyDescriptor actualHeightDescriptor
= DependencyPropertyDescriptor.FromProperty(WrapGridPanel.ActualHeightProperty,
typeof(WrapGridPanel));
if (actualHeightDescriptor != null)
{
actualHeightDescriptor.AddValueChanged(this, ActualHeightChanged);
}
}
public static void SetWrapHeight(DependencyObject element, GridLength value)
{
element.SetValue(WrapHeightProperty, value);
}
public static GridLength GetWrapHeight(DependencyObject element)
{
return (GridLength)element.GetValue(WrapHeightProperty);
}
public ObservableCollection<FrameworkElement> WrapChildren
{
get { return (ObservableCollection<FrameworkElement>)base.GetValue(WrapChildrenProperty); }
set { base.SetValue(WrapChildrenProperty, value); }
}
void ActualHeightChanged(object sender, EventArgs e)
{
RecalcMatrix();
}
void WrapChildren_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
RecalcMatrix();
}
List<List<FrameworkElement>> m_elementList = null;
private bool SetupMatrix()
{
m_elementList = new List<List<FrameworkElement>>();
double minHeightSum = 0;
m_elementList.Add(new List<FrameworkElement>());
int column = 0;
if (WrapChildren.Count > 0)
{
foreach (FrameworkElement child in WrapChildren)
{
double tempMinHeight = 0.0;
if (WrapGridPanel.GetWrapHeight(child).GridUnitType != GridUnitType.Star)
{
tempMinHeight = Math.Max(child.ActualHeight, child.MinHeight) + child.Margin.Top + child.Margin.Bottom;
}
else
{
tempMinHeight = child.MinHeight + child.Margin.Top + child.Margin.Bottom;
}
minHeightSum += tempMinHeight;
if (minHeightSum > ActualHeight)
{
minHeightSum = tempMinHeight;
m_elementList.Add(new List<FrameworkElement>());
column++;
}
m_elementList[column].Add(child);
}
}
if (m_elementList.Count != m_wrapPanel.Children.Count)
{
return true;
}
for (int i = 0; i < m_elementList.Count; i++)
{
List<FrameworkElement> columnList = m_elementList[i];
Grid wrapGrid = m_wrapPanel.Children[i] as Grid;
if (columnList.Count != wrapGrid.Children.Count)
{
return true;
}
}
return false;
}
private void RecalcMatrix()
{
if (ActualHeight == 0 || SetupMatrix() == false)
{
return;
}
Binding heightBinding = new Binding("ActualHeight");
heightBinding.Source = this;
while (m_elementList.Count > m_wrapPanel.Children.Count)
{
Grid wrapGrid = new Grid();
wrapGrid.SetBinding(Grid.HeightProperty, heightBinding);
m_wrapPanel.Children.Add(wrapGrid);
}
while (m_elementList.Count < m_wrapPanel.Children.Count)
{
Grid wrapGrid = m_wrapPanel.Children[m_wrapPanel.Children.Count - 1] as Grid;
wrapGrid.Children.Clear();
m_wrapPanel.Children.Remove(wrapGrid);
}
for (int i = 0; i < m_elementList.Count; i++)
{
List<FrameworkElement> columnList = m_elementList[i];
Grid wrapGrid = m_wrapPanel.Children[i] as Grid;
wrapGrid.RowDefinitions.Clear();
for (int j = 0; j < columnList.Count; j++)
{
FrameworkElement child = columnList[j];
GridLength wrapHeight = WrapGridPanel.GetWrapHeight(child);
Grid.SetRow(child, j);
Grid parentGrid = child.Parent as Grid;
if (parentGrid != wrapGrid)
{
if (parentGrid != null)
{
parentGrid.Children.Remove(child);
}
wrapGrid.Children.Add(child);
}
RowDefinition rowDefinition = new RowDefinition();
rowDefinition.Height = new GridLength(Math.Max(1, child.MinHeight), wrapHeight.GridUnitType);
wrapGrid.RowDefinitions.Add(rowDefinition);
}
}
}
public static readonly DependencyProperty WrapHeightProperty =
DependencyProperty.RegisterAttached("WrapHeight",
typeof(GridLength),
typeof(WrapGridPanel),
new FrameworkPropertyMetadata(new GridLength(1.0, GridUnitType.Auto)));
public static readonly DependencyProperty WrapChildrenProperty =
DependencyProperty.Register("WrapChildren",
typeof(ObservableCollection<FrameworkElement>),
typeof(WrapGridPanel),
new UIPropertyMetadata(null));
}
更新
修复了多个星号大小的列问题。
这里有新的示例应用程序:http://www.mediafire.com/?28z4rbd4pp790t2
更新
一张图片试图解释 WrapGridPanel
的作用
关于.net - WPF WrapPanel 中某些项目的高度为 *,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4598377/
我正在尝试使用包含艺术品的无缝 ImageButtons 创建 WrapPanel。我将以下 ContentTemplate 放在一起,希望它能提供所需的无缝外观;然而,每个按钮周围都有一条细白线。任
有没有人有我可以在 WPF 应用程序中使用的功能虚拟化 WrapPanel? 我已经在 http://virtualwrappanel.codeplex.com/ 下载并尝试了实现.但是,我收到以下异
我的 WP7 应用程序中显示了一个 toolkit:WrapPanel,我有 5 个项目,第一行只有足够的空间容纳 3 个项目,我希望包装面板将 3 个项目放在第一行,然后第二行的 2 居中。 目前看
WPF 4 是否还包含一个虚拟化的 WrapPanel,或者从现有面板派生一个是否容易。我想制作一个地址 View ,例如 outlook。 最佳答案 我认为不可能实现具有完全虚拟化(双向)的 Wra
我正在尝试实现一个与标准 WrapPanel 类似的自定义控件,但它允许您指定页眉和页脚。从视觉上看,这就是我想要完成的: 我创建了一个自定义控件,似乎为页眉和页脚项目留出了空间,但我无法让它们在视觉
有没有办法将列表按钮动态绑定(bind)到 WrapPanel 及其事件? 最佳答案 我不太确定这对你想做的事情是否正确,但听起来很相似: WPF - Fill a WrapPanel from a
我有一个列表框,其中包含三种不同大小的项目。项目的高度如下: 178x100px 100x100 像素 100x178px 我想要项目之间没有填充或边距的布局。 但是我得到了这个结果: 不同高度/宽度
我有一个垂直的 WarpPanel,它在运行时填充了控件。控件的类型和数量在运行时确定。它适用于具有固定高度的控件,但根据其内容扩展的控件(例如列表框)通常会创建一个新列。我需要以某种方式强制面板将控
我读过一些 WPF/silverlight 控件,我真的很喜欢其中的一些。我希望 android 可以拥有的面板之一是 WrapPanel(当然是作为布局)。还有其他人遇到过一些实现它的代码吗? 它布
我对 WPF 非常陌生。 我有一个非常简单的问题。 我有一个堆栈面板 spTerminalBox。
我有以下 XAML: /*other content*/ /*other conten
我非常习惯使用 WPF,但我最近开始使用 html 构建网站。 我想用 html 列出一些东西(比方说,每个东西都包含一张图片和一段描述),它们的行为就好像它们在 WPF 包装面板中一样。 我想我几乎
我在 WPF 中有以下布局 使用 MVVM 并绑定(bind)列表框项目源。我在网格中使用 wrapPanel,并禁用了滚动功能,因此网格行高将根据列表框内容增长和收缩。一切正常。
我在 WPF 中使用 WrapPanel 来显示图像。 在调整表单大小时,这些图像试图占用最大的空闲空间,但是当图片几乎可以填满空间时,WrapPanel 的末尾会出现一个比较大的间隙。 我想要做的是
我正在尝试实现相当于 WinForms ListView及其View属性设置为 View.List .从视觉上看,以下工作正常。我的 Listbox 中的文件名从上到下,然后换行到新列。 这是我正在使
我在这里有一个自定义 View ,它有一个垂直方向的 Wrappanel 问题是它不显示水平滚动条... 这是代码的链接... Code for what i am trying 我的自定义 View
有没有办法填充 Silverlight 工具包的 WrapPanel通过绑定(bind)到 ObservableCollection ?到目前为止,我看到的所有示例,包括工具包示例本身,都填充了 Wr
如何向 WPF 中的 wrappanel 控件添加滚动条。由于没有滚动条,我的一些控件正在横向切断。 最佳答案 在这种情况下,ScrollViewer 会对您有所帮助。否则,您需要使用 ScrollB
如何制作一个包含某些高度为 * 的项目的 WrapPanel? 我一直在试图解决一个看似简单的问题。我想要一个控件(或一些 XAML 布局魔法),其行为类似于具有一些高度为 * 的行的网格,但支持列的
我有一个显示项目的环绕面板,但我无法让滚动条正常工作,有什么问题吗?
我是一名优秀的程序员,十分优秀!