19

高さだけを拡大縮小し、コンテンツを水平方向に拡大するビューボックス(または同様のもの)を作成したいと思います。

私がこれを行う場合:

<Viewbox>
  <StackPanel>
    <Button>Foo</Button>
    <Button>Bar</Button>
  </StackPanel>
</Viewbox>

それから私はこれを手に入れます:


(出典:excastle.com

両方のボタンにHorizo​​ntalAlignment="Center"があるかのように機能し、結果をスケーリングします。しかし、Horizo​​ntalAlignment="Center"は必要ありません。次のように、Horizo​​ntalAlignment="Stretch"が必要です。


(出典:excastle.com

そのため、コンテンツの目的の高さを読み取り、高さのみに基づいてスケーリング係数を計算してから、スケーリングされたコンテンツを水平方向に拡大できるようにします。

ビューボックスやサードパーティのパネルを使用してこれを実現する方法はありますか?

4

5 に答える 5

18

WPF にはそのようなコントロール インクルードはありませんが、問題なく自分で作成できます。これは、仕様を持つカスタム ViewboxPanel です。

public class ViewboxPanel : Panel
{
    private double scale;

    protected override Size MeasureOverride(Size availableSize)
    {
        double height = 0;
        Size unlimitedSize = new Size(double.PositiveInfinity, double.PositiveInfinity);
        foreach (UIElement child in Children)
        {
            child.Measure(unlimitedSize);
            height += child.DesiredSize.Height;
        }
        scale = availableSize.Height / height;

        return availableSize;
    }

    protected override Size ArrangeOverride(Size finalSize)
    {
        Transform scaleTransform = new ScaleTransform(scale, scale);
        double height = 0;
        foreach (UIElement child in Children)
        {
            child.RenderTransform = scaleTransform;
            child.Arrange(new Rect(new Point(0, scale * height), new Size(finalSize.Width / scale, child.DesiredSize.Height)));
            height += child.DesiredSize.Height;
        }

        return finalSize;
    }
}

次のように使用します。

<local:ViewboxPanel>
    <Button>Foo</Button>
    <Button>Bar</Button>
</local:ViewboxPanel>

確かにいくつかの作業が必要ですが、これで始めることができます。

于 2010-12-28T05:55:31.943 に答える
4

幅が正しく機能するようにするには:

protected override Size MeasureOverride(Size availableSize)
    {
        double height = 0;
        Size unlimitedSize = new Size(double.PositiveInfinity, double.PositiveInfinity);
        foreach (UIElement child in Children)
        {
            child.Measure(unlimitedSize);
            height += child.DesiredSize.Height;
        }
        scale = availableSize.Height / height;

        foreach (UIElement child in Children)
        {
            unlimitedSize.Width = availableSize.Width / scale;
            child.Measure(unlimitedSize);
        }           

        return availableSize;
    }
于 2011-02-01T18:56:57.557 に答える
0

答えは「簡単ではない」と確信しています。

これはうまくいくように見えるが、ちょっと不格好なアイデアです:

  1. StackPanelをUserControlにスローします(UserControl1以下の例)。

  2. このUserControlの2つのコピーをコンテナー(以下の例ではグリッド)に配置します。

    a。最初のコピーを上/左に揃えて、デフォルトのサイズのままにします。このコピーは厳密に測定目的であり、可視性を非表示に設定する必要があります。

    b。2番目のコピーをビューボックス内に配置します。このコピーは、ユーザーが実際に目にするものです。

  3. MultiValueConverterでMultiBindingを使用して、2番目のUserControlの幅を調整し、ビューボックスによって展開されるに正しいアスペクト比になるようにします。

マークアップは次のとおりです。

<Grid>
    <local:UserControl1 x:Name="RawControl" HorizontalAlignment="Left" VerticalAlignment="Top" Visibility="Hidden" />
    <Viewbox>
        <local:UserControl1>
            <local:UserControl1.Width>
                <MultiBinding Converter="{StaticResource WidthAdjuster}">
                    <Binding ElementName="RawControl" Path="ActualHeight" />
                    <Binding RelativeSource="{RelativeSource AncestorType=Grid}" Path="ActualWidth" />
                    <Binding RelativeSource="{RelativeSource AncestorType=Grid}" Path="ActualHeight" />
                </MultiBinding>
            </local:UserControl1.Width>
        </local:UserControl1>
    </Viewbox>
</Grid>

これがMultiValueConverterです

public class WidthAdjuster : IMultiValueConverter
{
    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
    {
        var rawHeight = (double)values[0];
        var containerWidth = (double)values[1];
        var containerHeight = (double)values[2];
        var ratio = containerWidth / containerHeight;
        return rawHeight * ratio;
    }

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

525x350コンテナの結果

代替テキスト

于 2010-12-28T05:44:36.557 に答える
0

ほぼ同様の問題がありました。私のパネルは、そのすべての子に合わせて、タムを一列に並べて伸ばし、パネルを均一に埋める必要がありました。上記のアルゴリズムは、レンダリング変換を使用して要素をスケーリングします。問題は、render transform が子自体を引き伸ばすが、margin を無視することです。マージンが高く、スケール係数が 1 未満の場合、要素はパネルから脱落します。その軸の余白に応じて RenderTransform のスケールを修正し、配置に同じスケール係数を使用する必要があります。私が使用したMeasureOverrideは

protected override Size MeasureOverride(Size availableSize)
{
    double width = 0; double maxHeight = 0; double mY=0; double mX=0;
    Size unlimitedSize = new Size(double.PositiveInfinity, double.PositiveInfinity);
    foreach (UIElement child in Children)
    {
        child.Measure(unlimitedSize);
        width += child.DesiredSize.Width;
        maxHeight = Math.Max(maxHeight, child.DesiredSize.Height);

        FrameworkElement cld = child as FrameworkElement;
        mY = cld.Margin.Top + cld.Margin.Bottom;
        mX = cld.Margin.Left + cld.Margin.Right;
    }

    double scaleX = availableSize.Width / width;
    double scaleY = availableSize.Height / maxHeight;
    //That is scale for arranging
    positionScaling = Math.Min(scaleX, scaleY); 

    try
    {
        // Let FrameworkElement hight be Xn. mY = Element.Margin.Top + Element.Margin.bottom.
        // DesiredSize includes margin therefore:
        // (Yn + mY) * scaleY = availableSize.Height
        // But render transform doesn't scales margin. Actual render height with margin will be
        // Yn * RenderScaleY + mY = availableSize.Height;
        // We must find render transform scale coeff like this:

        double yn = availableSize.Height / scaleY - mY;
        scaleY = (availableSize.Height - mY) / yn;

        double xn = availableSize.Width / scaleX - mX;
        scaleX = (availableSize.Width - mX) / xn;


        scale = Math.Min(scaleX, scaleY); //scale to use in RenderTransform   
        // In my project all children are similar in size and margin, algorithm BREAKS otherwise!!!
    }
    catch { scale = 1; }

    return availableSize;
}

繰り返しますが、私のプロジェクトでは、すべての子はサイズとマージンが似ていますが、そうでない場合はアルゴリズムが壊れます。

于 2014-03-23T10:14:04.583 に答える