在我的Metro应用程序中,我有一个包含一定数量项目的数据源(比如25)。我有一个ListView,显示这些项目。我的问题是ListView的大小允许它显示6.5项,所以它显示的最后一项减少了一半。如果分辨率发生变化,则可能会显示4个项目,或8.2项目,或其他任何内容。我想要的是ListView准确显示适合控件高度的项目数,而不是剪切最后一项。
现在,我看到两个可能的半解决方案,其中没有一个是最佳解决方案:
将ListView的高度设置为固定高度,该高度是项目大小的倍数。这不会随着分辨率的变化而扩展。
限制数据源中的项目数。这也不会缩放。
所以我的问题是,如何让ListView只显示完整的项目(所有边缘都在视口/列表视图中的项目),并隐藏其余部分?
提前致谢!
答案 0 :(得分:3)
ListView继承自ItemsControl, 因此,一个更优化的解决方案包括在ItemsPanel中注入自定义面板(通过自定义剪裁显示覆盖测量)
像这样的事情(对不起,我没有尝试编译):protected override Size MeasureOverride(Size constraint)
{
if (this.VisualChildrenCount <= 0)
return base.MeasureOverride(constraint);
var size = ne Size(constraint.Width,0);
for(int i = 0; i < this.visualChildrenCount; i++)
{
child.Measure(size);
if(size.height + child.desiredSize > constraint.height)
break;
size.Height += child.DesiredSize;
}
return size;
}
答案 1 :(得分:3)
我的最终解决方案是结合@NovitchiS和@JesuX的建议。
我创建了一个堆栈面板覆盖,并听取了LayoutUpdated事件。我的最终解决方案:
class HeightLimitedStackPanel : StackPanel
{
public HeightLimitedStackPanel() : base()
{
this.LayoutUpdated += OnLayoutUpdated;
}
double GetSizeOfVisibleChildren(double parentHeight)
{
double currentSize = 0;
bool hasBreaked = false;
for (int i = 0; i < Children.Count; i++)
{
var child = Children[i];
if (currentSize + child.DesiredSize.Height > parentHeight)
{
hasBreaked = true;
break;
}
currentSize += child.DesiredSize.Height;
}
if (hasBreaked) return currentSize;
return parentHeight;
}
double ParentHeight
{
get
{
ItemsPresenter parent = VisualTreeHelper.GetParent(this) as ItemsPresenter;
if (parent == null)
return 0;
return parent.ActualHeight;
}
}
double previousHeight = 0;
int previousChildCount = 0;
protected void OnLayoutUpdated(object sender, object e)
{
double height = ParentHeight;
if (height == previousHeight && previousChildCount == Children.Count) return;
previousHeight = height;
previousChildCount = Children.Count;
this.Height = GetSizeOfVisibleChildren(height);
}
}
答案 2 :(得分:0)
@JesuX的答案是更好的方法 - 如果正确完成的话。以下ListView
子类对我来说很好用:
public sealed class IntegralItemsListView : ListView
{
protected override Size MeasureOverride(Size availableSize)
{
Size size = base.MeasureOverride(availableSize);
double height = 0;
if (Items != null)
{
for (int i = 0; i < Items.Count; ++i)
{
UIElement itemContainer = (UIElement)ContainerFromIndex(i);
if (itemContainer == null)
{
break;
}
itemContainer.Measure(availableSize);
double childHeight = itemContainer.DesiredSize.Height;
if (height + childHeight > size.Height)
{
break;
}
height += childHeight;
}
}
size.Height = height;
return size;
}
}
有一点需要注意 - 如果你将IntegralItemsListView
放入Grid
,它会有
VerticalAlignment="Stretch"
默认情况下,这会破坏此课程的目的。
另外:如果物品高度均匀,显然可以简化方法:
protected override Size MeasureOverride(Size availableSize)
{
Size size = base.MeasureOverride(availableSize);
size.Height = (int)(size.Height / ItemHeight) * ItemHeight;
return size;
}