gpt4 book ai didi

.net - WPF WrapPanel 中某些项目的高度为 *

转载 作者:行者123 更新时间:2023-12-02 06:10:50 25 4
gpt4 key购买 nike

如何制作一个包含某些高度为 * 的项目的 WrapPanel?

我一直在试图解决一个看似简单的问题。我想要一个控件(或一些 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 中更难实现)。

更新了赏金

<小时/>

Melak 的解决方案

我设法弄清楚如何在我的 IPy 应用程序中使用 Meleak 的解决方案:

1) 我使用 cscWrapGridPanel.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>

alt text

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 的作用

alt text

关于.net - WPF WrapPanel 中某些项目的高度为 *,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4598377/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com