Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/wpf/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Wpf 使视口框垂直缩放但水平拉伸_Wpf_Viewbox - Fatal编程技术网

Wpf 使视口框垂直缩放但水平拉伸

Wpf 使视口框垂直缩放但水平拉伸,wpf,viewbox,Wpf,Viewbox,我想制作一个仅缩放其高度的Viewbox(或类似的东西),然后水平拉伸其内容 如果我这样做: <Viewbox> <StackPanel> <Button>Foo</Button> <Button>Bar</Button> </StackPanel> </Viewbox> 福 酒吧 然后我得到这个: (来源:) 它的作用就像两个按钮都具有HorizontalAlignm

我想制作一个仅缩放其高度的Viewbox(或类似的东西),然后水平拉伸其内容

如果我这样做:

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

福
酒吧
然后我得到这个:


(来源:)

它的作用就像两个按钮都具有HorizontalAlignment=“Center”,然后缩放结果。但我不想要水平对齐=“中心”;我想要HorizontalAlignment=“Stretch”,如下所示:

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

(来源:)

因此,我希望它读取其内容的所需高度,仅基于高度计算缩放因子,然后允许缩放内容水平拉伸


有没有办法使用Viewbox和/或某些第三方面板来实现这一点?

我很确定答案是“不容易”

这里有一个似乎可行但有点笨重的想法:

  • 将StackPanel放入一个UserControl(
    UserControl1
    ,在下面的示例中)

  • 将此UserControl的两个副本放入一个容器(下面示例中的网格)

    a。将第一份副本上/左对齐,使其保持默认大小。此副本仅用于测量,其可见性应设置为隐藏

    b。将第二个副本放置在视口框中。此副本是用户将实际看到的副本

  • 使用带有多值转换器的多重绑定来调整第二个UserControl的宽度,使其在被Viewbox展开之前具有正确的纵横比

  • 以下是标记:

    <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>
    
    525 x 350集装箱的结果

    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();
        }
    }
    

    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>
    
    
    福
    酒吧
    

    它确实需要一些工作,但这可能会让您开始工作。

    要保持宽度正常工作:

    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;
        }
    

    我也有类似的问题。我的嵌板必须适合所有的孩子,将tham排成一排并拉伸,使嵌板均匀填充。上面的算法使用渲染变换来缩放元素。问题是“渲染变换”会拉伸子对象本身,但会忽略边距。若边距较高且比例系数低于1,则元件会从面板中脱落。您必须根据该轴上的边距校正渲染变换的比例,并使用相同的比例系数进行排列。我用过的方法是

    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;
    }
    

    再一次:在我的项目中,所有的孩子在大小和边距上都是相似的,否则算法就会崩溃。

    感谢您提供了伟大的解决方案。我在方法
    protectedoverride Size MeasureOverride(Size availableSize)
    中添加了
    if(System.ComponentModel.DesignerProperties.GetIsInDesignMode(this)){availableSize=new Size(200200);}
    ,因此设计器可以正常工作而不会引发异常。