简体   繁体   English

创建具有约束比例的可调整大小的Button控件网格的最佳方法(Silverlight .XAML,WinRT)

[英]Best way to create a resizable Grid of Button control with constrained proportions (Silverlight. XAML, WinRT)

Writing a WinRT app in XAML/C# where I'd like a simple grid of square shaped buttons. 在XAML / C#中编写一个WinRT应用程序,我想要一个简单的方形按钮网格。 The number of buttons is fixed currently, however in future there will be more added as I create more content. 按钮的数量目前是固定的,但是随着我创建更多内容,将来会增加更多。

Having to handle all UI resizes (snapped, filled, portrait, etc) and resolutions I ran into problems with the UIContainer (I was using a Grid then switched the WrapGrid ) simply resizing the buttons automatically because I do not know of any way to constrain the aspect ratio and having square buttons is important to my UI. 必须处理所有UI调整大小(拍摄,填充,纵向等)和分辨率我遇到了UIContainer的问题(我使用Grid然后切换WrapGrid )只是自动调整按钮大小,因为我不知道有什么方法可以约束纵横比和方形按钮对我的UI很重要。

Is there a way to constrain the aspect ratio / proportions of the Width and Height of a button control? 有没有办法约束按钮控件的宽度和高度的宽高比/比例? If so, I'm assuming it would be to create a custom control, but other than creating styles and data templates I'm really just out of my depth. 如果是这样,我假设它将创建一个自定义控件,但除了创建样式和数据模板,我真的只是我的深度。

Any suggestions on the best way to attack this problem? 有关解决此问题的最佳方法的任何建议?

You can create a simple decorator control that would override ArrangeOverride and always arrange itself into a square, like this: 您可以创建一个简单的装饰器控件,它将覆盖ArrangeOverride并始终将自身ArrangeOverride正方形,如下所示:

public class SquareDecorator : ContentControl
{
    public SquareDecorator()
    {
        VerticalAlignment = VerticalAlignment.Stretch;
        HorizontalAlignment = HorizontalAlignment.Stretch;
        VerticalContentAlignment = VerticalAlignment.Stretch;
        HorizontalContentAlignment = HorizontalAlignment.Stretch;
    }

    protected override Size MeasureOverride(Size availableSize)
    {
        var baseSize = base.MeasureOverride(availableSize);

        double sideLength = Math.Max(baseSize.Width, baseSize.Height);

        return new Size(sideLength, sideLength);
    }

    protected override Size ArrangeOverride(Size finalSize)
    {
        double sideLength = Math.Min(finalSize.Width, finalSize.Height);

        var result = base.ArrangeOverride(new Size(sideLength, sideLength));

        return result;
    }
}

Now you can wrap your buttons with this decorator: 现在你可以用这个装饰器包装你的按钮:

<z:SquareDecorator>
    <Button Content="I'm Square"
            VerticalAlignment="Stretch"
            HorizontalAlignment="Stretch" />
</z:SquareDecorator>

I'm assuming you can't just set height and width to a fixed size (on the button itself or in a style for the button). 我假设您不能只将高度和宽度设置为固定大小(按钮本身或按钮的样式)。

I tried doing this in Silverlight: 我尝试在Silverlight中这样做:

<Button Height={Binding ActualWidth, RelativeSource={RelativeSource Self}}/>

But it doesn't want to work. 但它不想工作。 Don't know why. 不知道为什么。 It might work in WinRT. 它可能在WinRT中有效。

Alternatively, you can create a custom Panel to arrange and size your buttons. 或者,您可以创建自定义面板来排列和调整按钮大小。 Should not be difficult given your simple requirements. 鉴于您的简单要求,应该不难。 It involves implementing just two functions and knowledge of basic arithmetic. 它涉及实现两个基本算术的功能和知识。 Here is an example that creates a UniformGrid . 这是一个创建UniformGrid的示例

I don't think a UserControl or deriving from Button would be better choices. 我不认为UserControl或从Button派生是更好的选择。

Here's my version of Pavlo's answer. 这是我的Pavlo的答案版本。 It is more efficient and elegant than deriving from ContentControl (which must use a ControlTemplate, adds other elements to the visual tree, and has tons of other unneeded functionality). 它比从ContentControl派生更有效和优雅(ContentControl必须使用ControlTemplate,将其他元素添加到可视树中,并具有大量其他不需要的功能)。 I also believe it is more correct, because MeasureOverride returns the correct desired size. 我也相信它更正确,因为MeasureOverride返回正确的所需大小。

public class SquareDecorator : Panel
{
    protected override Size MeasureOverride(Size availableSize)
    {
        if( Children.Count == 0 )   return base.MeasureOverride(availableSize);
        if( Children.Count > 1 )    throw new ArgumentOutOfRangeException("SquareDecorator should have one child");

        Children[0].Measure(availableSize);
        var sideLength = Math.Max(Children[0].DesiredSize.Width, Children[0].DesiredSize.Height);
        return new Size(sideLength, sideLength);
    }

    protected override Size ArrangeOverride(Size finalSize)
    {
        if( Children.Count == 0 )   return base.ArrangeOverride(finalSize);
        if( Children.Count > 1 )    throw new ArgumentOutOfRangeException("SquareDecorator should have one child");

        double sideLength = Math.Min(finalSize.Width, finalSize.Height);
        Children[0].Arrange(new Rect(0, 0, sideLength, sideLength));
        return new Size(sideLength, sideLength);
    }
}

Use it the same way (Button's Horizontal/VerticalAlignment must be stretch, but this is the default. Also note you can get useful effects if you set SquareDecorator's Horizontal/VerticalAlignment to non-stretch.): 以相同的方式使用它(Button的Horizo​​ntal / VerticalAlignment必须拉伸,但这是默认值。另请注意,如果将SquareDecorator的Horizo​​ntal / VerticalAlignment设置为非拉伸,则可以获得有用的效果。):

<z:SquareDecorator>
   <Button Content="I'm Square"/>
</z:SquareDecorator>

I would have derived from FrameworkElement, but it looks like neither Silverlight nor WinRT allow you to do that. 我会从FrameworkElement派生出来,但看起来Silverlight和WinRT都不允许你这样做。 (FrameworkElement is not sealed, but has no AddVisualChild method which makes it useless to derive from. Sigh, I hate .NET and/or Microsoft) (FrameworkElement没有密封,但没有AddVisualChild方法,这使得它无法派生。叹气,我讨厌.NET和/或微软)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM