如何创建方形按钮?

时间:2017-08-15 01:23:40

标签: c# xaml uwp uwp-xaml

感谢@Justin XL和@ grek40对我的帮助 我必须为我的英语不好而道歉,这让很多人感到烦恼 而且我认为我需要改进这个问题以帮助其他任何人。

这是最新的:
我需要像这样制作一个方形按钮: enter image description here


我的程序是一个全屏程序,不同的设备有不同的窗口大小 因此,我的方形按钮应该可以调整大小,我也想制作一个反应性用户界面 现在我该如何制作方形按钮? 谢谢。

3 个答案:

答案 0 :(得分:3)

像这样的 UI逻辑在其代码隐藏中生活是完全没问题的。在大多数情况下,我甚至认为它更有效率。

在您的示例中,使用以下代码<{1}}将Rectangle变为非常容易

<强> XAML

<Border x:Name="MyBorder"
        Grid.Column="1"
        Grid.Row="1"
        SizeChanged="MyBorder_SizeChanged">
    <Rectangle x:Name="MyRectangle"
               Fill="LightBlue" />
</Border>

<强>代码隐藏

private void MyBorder_SizeChanged(object sender, SizeChangedEventArgs e)
{
    if (MyBorder.ActualWidth > MyBorder.ActualHeight)
    {
        MyRectangle.Width = MyRectangle.Height = MyBorder.ActualHeight;
    }
    else if (MyBorder.ActualWidth < MyBorder.ActualHeight)
    {
        MyRectangle.Height = MyRectangle.Height = MyBorder.ActualWidth;
    }
}

但我们可以改善吗?由于您需要正方形Button,因此最有必要创建SquareButton并将其直接插入Grid

因此,可以将XAML简化为更易读的版本

<local:SquareButton Grid.Column="1" Grid.Row="1" />

然后您只需要实现自定义控件,如下所示

SquareButton课程

[TemplatePart(Name = PART_Root, Type = typeof(Border))]
[TemplatePart(Name = PART_ContentHost, Type = typeof(Border))]
public sealed class SquareButton : Button
{
    private const string PART_Root = "Root";
    private const string PART_ContentHost = "ContentHost";

    public SquareButton()
    {
        DefaultStyleKey = typeof(SquareButton);
    }

    protected override void OnApplyTemplate()
    {
        base.OnApplyTemplate();

        var root = (Border)GetTemplateChild(PART_Root);
        var contentHost = (Border)GetTemplateChild(PART_ContentHost);

        root.SizeChanged += (s, e) =>
        {
            if (root.ActualWidth > root.ActualHeight)
            {
                contentHost.Width = contentHost.Height = root.ActualHeight;
            }
            else if (root.ActualWidth < root.ActualHeight)
            {
                contentHost.Height = contentHost.Height = root.ActualWidth;
            }
        };
    }
}

SquareButton样式Themes/Generic.xaml

<Style TargetType="local:SquareButton">
    <Setter Property="Background"
            Value="{ThemeResource SystemControlBackgroundBaseLowBrush}" />
    <Setter Property="Foreground"
            Value="{ThemeResource SystemControlForegroundBaseHighBrush}" />
    <Setter Property="BorderBrush"
            Value="{ThemeResource SystemControlForegroundTransparentBrush}" />
    <Setter Property="BorderThickness"
            Value="{ThemeResource ButtonBorderThemeThickness}" />
    <Setter Property="Padding"
            Value="8,4,8,4" />
    <Setter Property="HorizontalAlignment"
            Value="Stretch" />
    <Setter Property="VerticalAlignment"
            Value="Stretch" />
    <Setter Property="FontFamily"
            Value="{ThemeResource ContentControlThemeFontFamily}" />
    <Setter Property="FontWeight"
            Value="Normal" />
    <Setter Property="FontSize"
            Value="{ThemeResource ControlContentThemeFontSize}" />
    <Setter Property="UseSystemFocusVisuals"
            Value="True" />
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="local:SquareButton">
                <Border x:Name="Root">
                    <VisualStateManager.VisualStateGroups>
                        <VisualStateGroup x:Name="CommonStates">
                            <VisualState x:Name="Normal">
                                <Storyboard>
                                    <PointerUpThemeAnimation Storyboard.TargetName="ContentHost" />
                                </Storyboard>
                            </VisualState>
                            <VisualState x:Name="PointerOver">
                                <Storyboard>
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter"
                                                                   Storyboard.TargetProperty="BorderBrush">
                                        <DiscreteObjectKeyFrame KeyTime="0"
                                                                Value="{ThemeResource SystemControlHighlightBaseMediumLowBrush}" />
                                    </ObjectAnimationUsingKeyFrames>
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter"
                                                                   Storyboard.TargetProperty="Foreground">
                                        <DiscreteObjectKeyFrame KeyTime="0"
                                                                Value="{ThemeResource SystemControlHighlightBaseHighBrush}" />
                                    </ObjectAnimationUsingKeyFrames>
                                    <PointerUpThemeAnimation Storyboard.TargetName="ContentHost" />
                                </Storyboard>
                            </VisualState>
                            <VisualState x:Name="Pressed">
                                <Storyboard>
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentHost"
                                                                   Storyboard.TargetProperty="Background">
                                        <DiscreteObjectKeyFrame KeyTime="0"
                                                                Value="{ThemeResource SystemControlBackgroundBaseMediumLowBrush}" />
                                    </ObjectAnimationUsingKeyFrames>
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter"
                                                                   Storyboard.TargetProperty="BorderBrush">
                                        <DiscreteObjectKeyFrame KeyTime="0"
                                                                Value="{ThemeResource SystemControlHighlightTransparentBrush}" />
                                    </ObjectAnimationUsingKeyFrames>
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter"
                                                                   Storyboard.TargetProperty="Foreground">
                                        <DiscreteObjectKeyFrame KeyTime="0"
                                                                Value="{ThemeResource SystemControlHighlightBaseHighBrush}" />
                                    </ObjectAnimationUsingKeyFrames>
                                    <PointerDownThemeAnimation Storyboard.TargetName="ContentHost" />
                                </Storyboard>
                            </VisualState>
                            <VisualState x:Name="Disabled">
                                <Storyboard>
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentHost"
                                                                   Storyboard.TargetProperty="Background">
                                        <DiscreteObjectKeyFrame KeyTime="0"
                                                                Value="{ThemeResource SystemControlBackgroundBaseLowBrush}" />
                                    </ObjectAnimationUsingKeyFrames>
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter"
                                                                   Storyboard.TargetProperty="Foreground">
                                        <DiscreteObjectKeyFrame KeyTime="0"
                                                                Value="{ThemeResource SystemControlDisabledBaseMediumLowBrush}" />
                                    </ObjectAnimationUsingKeyFrames>
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter"
                                                                   Storyboard.TargetProperty="BorderBrush">
                                        <DiscreteObjectKeyFrame KeyTime="0"
                                                                Value="{ThemeResource SystemControlDisabledTransparentBrush}" />
                                    </ObjectAnimationUsingKeyFrames>
                                </Storyboard>
                            </VisualState>
                        </VisualStateGroup>
                    </VisualStateManager.VisualStateGroups>
                    <Border x:Name="ContentHost" Background="{TemplateBinding Background}">
                        <ContentPresenter x:Name="ContentPresenter"
                                          BorderBrush="{TemplateBinding BorderBrush}"
                                          BorderThickness="{TemplateBinding BorderThickness}"
                                          Content="{TemplateBinding Content}"
                                          ContentTransitions="{TemplateBinding ContentTransitions}"
                                          ContentTemplate="{TemplateBinding ContentTemplate}"
                                          Padding="{TemplateBinding Padding}"
                                          HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
                                          VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
                                          AutomationProperties.AccessibilityView="Raw" />
                    </Border>
                </Border>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

希望这有帮助!

答案 1 :(得分:2)

使用Rectangle.Stretch属性:

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

我认为这回答了创建矩形的实际问题,其中宽度和高度相同,矩形被拉伸到可用空间。

就绑定而言,MultiBindingWidth上的Height以及IMultiValueConverter实现返回所有输入值的最小值可能有效。但是,只有那些不提供自动拉伸的控件才需要它。

您可以使用附加属性为给定限制设置相同的宽度/高度:

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

使用适当的xmlns命名空间

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

涉及自定义控件作为方形间距内容包装的解决方案:

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

用法:

<Border x:Name="border" Grid.Column="1" Grid.Row="1">
    <local:SquareContentControl>
        <Rectangle Fill="Red"/>
    </local:SquareContentControl>
</Border>

答案 2 :(得分:1)

编辑2017/8/17仅适用于WPF,而不适用于UWP。

使用最小转换器:

public class MinConverter : IMultiValueConverter
{
    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
    {
        double result = double.NaN;
        if (values != null)
        {
            try
            {
                result = values.Cast<double>().Aggregate(double.PositiveInfinity, (a, b) => Math.Min(a, b));
            }
            catch (Exception)
            {
                result = double.NaN;
            }
        }
        return result;
    }

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

然后在你的xaml中设置矩形高度以匹配父的边界最小值(ActualHeight,ActualWidth)。矩形宽度只能绑定到Rectangle的ActualHeight

<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 x:Name="Bd" Grid.Column="1" Grid.Row="1">
        <Rectangle x:Name="R"
                   Width="{Binding Path=ActualHeight, Mode=OneWay, RelativeSource={RelativeSource Self}}">
           <Rectangle.Height>
              <MultiBinding Converter="converter:MinConverter">
                 <Binding ElementName="Bd" Path="ActualHeight"/>
                 <Binding ElementName="Bd" Path="ActualWidth"/>
              </MultiBinding>
           </Rectangle.Height>
        </Rectangle>
    </Border>
</Grid>