Melon NG Melon NG - 2 years ago 73
C# Question

How to create a square button?

Thanks for @Justin XL and @grek40 help me so much.

I must apologize for my poor English that troubles everyone so much.

And I think I need to improve this question to help any others in the furture.

Here is the newest:

I need to make a square button like this:
enter image description here



My programme is a fullscreen programme that different device has different window's size.

So my square button should be can resizeable also beaucase I want to make a Reactive UI.

And now how can I make a square button?

Thank you.

Answer Source

Use the Rectangle.Stretch property:

<Rectangle Fill="Red" Stretch="Uniform"></Rectangle>

I think this answers the actual question of creating a rectangle where width and height are the same and the rectangle is stretched to the available space.

In terms of binding, a MultiBinding on both Width and Height with an IMultiValueConverter implementation that returns the minimum of all input values might work. However, it's only needed for controls that don't provide automated stretching.


You can use attached properties to set the same width/height for a given limit:

public static class SquareSize
{
    public static double GetWidthLimit(DependencyObject obj)
    {
        return (double)obj.GetValue(WidthLimitProperty);
    }

    public static void SetWidthLimit(DependencyObject obj, double value)
    {
        obj.SetValue(WidthLimitProperty, value);
    }

    public static readonly DependencyProperty WidthLimitProperty = DependencyProperty.RegisterAttached(
        "WidthLimit", typeof(double), typeof(SquareSize),
        new FrameworkPropertyMetadata(double.PositiveInfinity, new PropertyChangedCallback(OnWidthLimitChanged)));

    private static void OnWidthLimitChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        UpdateSize(d, (double)e.NewValue, GetHeightLimit(d));
    }



    public static double GetHeightLimit(DependencyObject obj)
    {
        return (double)obj.GetValue(HeightLimitProperty);
    }

    public static void SetHeightLimit(DependencyObject obj, double value)
    {
        obj.SetValue(HeightLimitProperty, value);
    }

    public static readonly DependencyProperty HeightLimitProperty = DependencyProperty.RegisterAttached(
        "HeightLimit", typeof(double), typeof(SquareSize),
        new FrameworkPropertyMetadata(double.PositiveInfinity, new PropertyChangedCallback(OnHeightLimitChanged)));

    private static void OnHeightLimitChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        UpdateSize(d, GetWidthLimit(d), (double)e.NewValue);
    }



    private static void UpdateSize(DependencyObject d, double widthLimit, double heightLimit)
    {
        double resultSize = Math.Min(widthLimit, heightLimit);
        d.SetCurrentValue(FrameworkElement.WidthProperty, resultSize);
        d.SetCurrentValue(FrameworkElement.HeightProperty, resultSize);
    }
}

Use with appropriate xmlns namespace

<Border x:Name="border" Grid.Column="1" Grid.Row="1">
    <Rectangle
        Fill="Red"
        local:SquareSize.WidthLimit="{Binding ElementName=border,Path=ActualWidth}"
        local:SquareSize.HeightLimit="{Binding ElementName=border,Path=ActualHeight}"/>
</Border>

A solution involving a custom control as wrapper for square-spaced content:

public class SquareContentControl : ContentControl
{
    protected override Size ArrangeOverride(Size arrangeBounds)
    {
        var sizeLimit = Math.Min(arrangeBounds.Width, arrangeBounds.Height);
        if (VisualChildrenCount > 0)
        {
            var child = GetVisualChild(0) as UIElement;
            if (child != null)
            {
                child.Arrange(new Rect(new Point((arrangeBounds.Width - sizeLimit) / 2, (arrangeBounds.Height - sizeLimit) / 2), new Size(sizeLimit, sizeLimit)));
                return arrangeBounds;
            }
        }
        return base.ArrangeOverride(arrangeBounds);
    }

    protected override Size MeasureOverride(Size constraint)
    {
        var sizeLimit = Math.Min(constraint.Width, constraint.Height);
        if (VisualChildrenCount > 0)
        {
            var child = GetVisualChild(0) as UIElement;
            if (child != null)
            {
                child.Measure(new Size(sizeLimit, sizeLimit));
                return child.DesiredSize;
            }
        }
        return base.MeasureOverride(constraint);
    }
}

Usage:

<Border x:Name="border" Grid.Column="1" Grid.Row="1">
    <local:SquareContentControl>
        <Rectangle Fill="Red"/>
    </local:SquareContentControl>
</Border>
Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download