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

How to compare height and width in binding?

<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="0.1*"></RowDefinition>
<RowDefinition Height="0.8*"></RowDefinition>
<RowDefinition Height="0.1*"></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.1*"></ColumnDefinition>
<ColumnDefinition Width="0.8*"></ColumnDefinition>
<ColumnDefinition Width="0.1*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Border Grid.Column="1" Grid.Row="1">
<Rectangle Name=R></Rectangle>
</Border>
</Grid>


I must make sure the Rectangle is a squre.

If Border's width > Border's height,then the Rectangle's height and width equal Border's height.

If Border's width < Border's height,then the Rectangle's height and width equal Border's width.

The Border is no use but just to explain the column's width and row'height which I want to bind.

Now how can I set this binding?

Please help me,thank you.



----------------------------------------------



PS:I posted this question to WPF tag mistakenly,and thanks @grek40 taught me to use MultiBinding and IMultiValueConverter.

I am very sorry about it and now I corrected the tag to UWP.

However, I found that uwp had cancel the MultiBinding and IMultiValueConverter.


I searched google and someone said can use DependencyProperty instead of MultiBinding and IMultiValueConverter.

But I don't konw how to use the DependencyProperty in this project beaucase it is not just to combine some text but decide width and height and use which is the minimum.



To Which@grek40 requires:
If there is a button to deal with it,here is the code:

private void Button_Click(object sender, RoutedEventArgs e)
{
if (R.Width > R.Height)
{
R.Width = R.Height;
}
else
{
R.Height = R.Width;
}
}

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