【发布时间】:2011-06-03 15:48:51
【问题描述】:
如何制作包含高度为 * 的某些项目的 WrapPanel?
我一直在尝试解决一个看似简单的问题。我想要一个控件(或一些 XAML 布局魔术),其行为类似于具有某些高度为 * 的行的网格,但支持列的换行。地狱;称它为 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 中更难实现)。
更新了赏金
Meleak 的解决方案
我设法弄清楚如何在我的 IPy 应用程序中使用 Meleak 的解决方案:
1) 我将WrapGridPanel.cs 编译成带有csc 的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() 算法可以优化吗?可以不那么频繁地调用它吗?也许正如 Nicholas 所建议的那样,覆盖 MeasureOverride 和 ArrangeOverride 会表现得更好?
更新:根据 VS2010 Instrumentation Profiler,RecalcMatrix() 中 97% 的时间花在 Clear() 和 Add() 上。就地修改每个元素将是一个巨大的性能改进。我自己也在努力,但修改别人的代码总是很困难...... http://i.stack.imgur.com/tMTWU.png
更新:性能问题已基本解决。谢谢梅莱克!
如果您想尝试一下,这里是我的实际应用程序 UI 的一部分的模型,采用 XAML 格式。 http://pastebin.com/2EWY8NS0
【问题讨论】:
-
您应该能够接受代码隐藏解决方案,只需在 IronPython 解决方案中引用该 .Net 类型。
-
@siz:是的,但我不确定如何让代码隐藏“编译”,可以这么说,以便能够从 IPy 引用它。
-
@Aphex:我会调查你的问题。它肯定可以优化。
-
@Aphex:用优化版本更新了我的代码。应该快得多。我接下来看看另一个问题
-
@Aphex:问题是保证金,我没有考虑到这一点。我会解决的
标签: .net wpf visual-studio wpf-controls