3

私の Metro アプリケーションには、特定の数 (たとえば 25) のアイテムを含むデータ ソースがあります。これらのアイテムを表示する ListView があります。私の問題は、ListView のサイズが、たとえば 6.5 アイテムを表示できるサイズであるため、表示される最後のアイテムが半分になることです。解像度が変わると、4 項目、または 8.2 項目などを表示する可能性があります。私が望むのは、最後の項目を切り取るのではなく、ListView がコントロールの高さに収まる正確な項目数を表示することです。

現在、2 つの解決策が考えられますが、いずれも最適ではありません。

  1. ListView の高さを、アイテム サイズの倍数である固定の高さに設定します。これは、解像度の変更には対応しません。

  2. データ ソース内の項目数を制限します。これもスケーリングしません。

私の質問は、ListView に完全なアイテム (すべてのエッジがビューポート/リストビュー内にあるアイテム) のみを表示し、残りを非表示にするにはどうすればよいですか?

4

3 に答える 3

4

ListView は ItemsControl を継承するため、さらに最適化されたソリューションの 1 つは、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;
}
于 2012-09-11T08:24:08.273 に答える
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);
    }
}
于 2012-09-14T07:24:18.123 に答える
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;
    }
}

1 つの注意点 - をIntegralItemsListViewに挿入するGridと、

VerticalAlignment="Stretch"

デフォルトでは、このクラスの目的に反します。

また、アイテムの高さが均一である場合、メソッドは明らかに単純化できます。

protected override Size MeasureOverride(Size availableSize)
{
    Size size = base.MeasureOverride(availableSize);
    size.Height = (int)(size.Height / ItemHeight) * ItemHeight;
    return size;
}
于 2016-01-20T13:30:52.837 に答える