【问题标题】:How can I draw a border with squared corners in wpf?如何在 wpf 中绘制带有方角的边框?
【发布时间】:2010-09-10 04:56:05
【问题描述】:

你知道,就像太空堡垒纸一样!我已经尝试了几次,但现在我很难过。我还没有走几何路线,所以我会尽可能地解释这一点。

我希望边框变大,但包含固定大小的角,就像 CornerRadius 一样。我希望它们不是圆角,而是锥形,例如:

/---------\
|         |
|         |
\_________/

我已经做了两次尝试:

  1. 我的第一次尝试是试图操纵一个边界类。这是行不通的,因为拉伸形状会破坏几何形状和比例。
  2. 第二次尝试更加开箱即用。字面上地。我创建了一个 3x3 网格并用 4 个边框填充它,每个边框的厚度分别为 2,0,0,0 - 0,2,0,0 - 0,0,2,0 和 0,0,0,2。最后一步,是用一条线连接边界。我的问题就在这里......

第一次尝试

<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
   <Grid>
      <Grid.Resources>
         <Style x:Key="MyPoly" TargetType="Polygon">
            <Setter Property="Points">
               <Setter.Value>
                  <PointCollection>
                     <Point X="0.10" Y="0.01"/>
                     <Point X="0.50" Y="0.01"/>
                     <Point X="0.60" Y="0.10"/>
                     <Point X="0.60" Y="0.50"/>
                     <Point X="0.50" Y="0.60"/>
                     <Point X="0.10" Y="0.60"/>
                     <Point X="0.01" Y="0.50"/>
                     <Point X="0.01" Y="0.10"/>
                  </PointCollection>
               </Setter.Value>
            </Setter>
         </Style>
      </Grid.Resources>
      <Border
         Width="100"
         Height="100"
         BorderBrush="Black"
         BorderThickness="3"
         CornerRadius="5"/>
      <Grid Width="400"
            Height="300">
         <Polygon
            Stroke="Purple"
            StrokeThickness="2"
            Style="{StaticResource MyPoly}" Stretch="Fill">
            <Polygon.Fill>
               <SolidColorBrush Color="Blue" Opacity="0.4"/>
            </Polygon.Fill>
            <Polygon.LayoutTransform>
               <ScaleTransform ScaleX="1" ScaleY="1"/>
            </Polygon.LayoutTransform>
         </Polygon>
      </Grid>
   </Grid>
</Page>

第二次尝试

<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" SnapsToDevicePixels="True">
    <Grid>
        <Grid.Resources>
        </Grid.Resources>
        <Grid Width="200" Height="350" SnapsToDevicePixels="True">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="10"/>
                <ColumnDefinition Width="*"/>
                <ColumnDefinition Width="10"/>
            </Grid.ColumnDefinitions>
            <Grid.RowDefinitions>
                <RowDefinition Height="10"/>
                <RowDefinition Height="*"/>
                <RowDefinition Height="10"/>
            </Grid.RowDefinitions>
            <Border Grid.Column="0" Grid.Row="1" Margin="0" BorderBrush="Red" BorderThickness="2,0,0,0" Padding="0" SnapsToDevicePixels="True"/>
            <Border BorderThickness="1" BorderBrush="Black">
                <Line SnapsToDevicePixels="True" Stretch="Fill" Stroke="Red" StrokeThickness="2" X1="0" X2="1" Y1="1" Y2="0">
                </Line>
            </Border>
            <Border Grid.Column="1" Grid.Row="0" BorderBrush="Red" BorderThickness="0,2,0,0" SnapsToDevicePixels="True"/>
            <Border Grid.Column="2" Grid.Row="1" BorderBrush="Red" BorderThickness="0,0,2,0" SnapsToDevicePixels="True"/>
            <Border Grid.Column="1" Grid.Row="2" BorderBrush="Red" BorderThickness="0,0,0,2" SnapsToDevicePixels="True"/>
        </Grid>
    </Grid>
</Page>

线设置为缩放到网格大小。将 Line 属性设置为 X1="0" X2="1" Y1="1" Y2="0" 并使用 Stretch="Fill" 将 Line 扩展到边缘。然而,它最终看起来像这样:

(很烦人,我不能发布图片,我需要去回答别人的问题以获得一些代表。所以请转至此链接查看该行,或将上述 XAML 粘贴到 Kaxaml 中。) http://img375.imageshack.us/img375/1996/border1.png

我在承载 Line 的 Grid 元素周围画了一个洋红色边框,以使问题更加明显。

如何扩展线条以真正填补空白(例如通过扩大网格内的可绘制区域),或者,有更好的方法吗?

此外,变换会扭曲线条,使其变粗。我尝试扩大规模,但没有一致性。线上的端盖看起来同样糟糕(例如三角形)。

最后,这个方法还是有缺陷的,因为我希望以后能够设置角的大小,所以将行/列的边缘宽度设置为 10 似乎是一个绊脚石。绑定到属性可能会解决这个问题,不过我从来没有在样式中这样做过。

感谢您的阅读,汤姆

【问题讨论】:

    标签: wpf graphics line border


    【解决方案1】:

    WPF 边框继承自 Decorator 类。编写自己的装饰器非常容易。下面一个用“塞进”的角在一个孩子周围画了一个边框。

    class FunkyBorder : Decorator
    {
        public Brush BorderBrush
        {
            get { return (Brush)GetValue(BorderBrushProperty); }
            set { SetValue(BorderBrushProperty, value); }
        }
    
        public static readonly DependencyProperty BorderBrushProperty =
            DependencyProperty.Register("BorderBrush", 
                                        typeof(Brush), 
                                        typeof(FunkyBorder), 
                                        new UIPropertyMetadata(Brushes.Transparent));
    
        protected override void OnRender(DrawingContext drawingContext)
        {
            // TODO, make pen thickness and corner width (currently 10) into dependency properties.
            // Also, handle case when border don't fit into given space without overlapping.
    
            if (_pen.Brush != BorderBrush)
            {
                _pen.Brush = BorderBrush;
            }
    
            drawingContext.DrawLine(_pen, new Point(0, 10), new Point(10, 0));
            drawingContext.DrawLine(_pen, new Point(10, 0), new Point(ActualWidth - 10, 0));
            drawingContext.DrawLine(_pen, new Point(ActualWidth - 10, 0), new Point(ActualWidth, 10));
            drawingContext.DrawLine(_pen, new Point(0, 10), new Point(0, ActualHeight - 10));
            drawingContext.DrawLine(_pen, new Point(ActualWidth, 10), new Point(ActualWidth, ActualHeight - 10));
            drawingContext.DrawLine(_pen, new Point(0, ActualHeight - 10), new Point(10, ActualHeight));
            drawingContext.DrawLine(_pen, new Point(10, ActualHeight), new Point(ActualWidth - 10, ActualHeight));
            drawingContext.DrawLine(_pen, new Point(ActualWidth - 10, ActualHeight), new Point(ActualWidth, ActualHeight - 10));
        }
    
        private Pen _pen = new Pen(Brushes.Transparent, 2);
    }
    

    这样使用:

       <BorderTest:FunkyBorder BorderBrush="Red">
            <TextBlock Text="Hello" />
        </BorderTest:FunkyBorder>
    

    【讨论】:

    • 您好华尔街,感谢您的回复。这看起来很全面。明天早上我回到编程模式时,我会试一试,让你知道我的进展如何。我希望采用“all xaml”路线,这样我就可以换掉边框样式,但现在忘记了,这可能就可以了!
    • 将其作为一个类实现的优势将更容易重用。如果您只想让一些 Xaml 显示相同类型的边框,您可以在 Xaml 中定义 8 行。将它们放在一个包含一个单元格的网格中,并使用网格中的 ActualHeight 和 ActualWidth。这就是我如何计算出后面代码的坐标。生成的可视化树将是相同的。
    • 好的,我刚刚玩了一场,这绝对是要走的路。在纯 xaml 中执行此操作比有用更尴尬,因为在没有 IValueConverter 的情况下执行偏移和诸如 ActualHeight 之类的事情很棘手。我稍微修改了您的代码,以包括 CornerWidthOffset DP,以及边缘的三角形笔帽,以减少间隙效果,如我的原始图像所示。 (在我当前的示例中,0.299 可以很好地填充孔。交换边框可以这样完成:pavanpodila.spaces.live.com/Blog/…。似乎工作得很好。再次感谢!
    • 到目前为止我所做的一切都在这里codescratch.net/files/cornerborder.zip。我希望其他人能发现这很有用:)
    【解决方案2】:

    为避免最后出现令人讨厌的中断,您可以使用多边形或折线:

        <Polygon
            Stroke="Red"
            StrokeThickness="2"
            Points="
                0,1 1,0
                1,0 20,0
                20,0 21,1
                21,1 21,20
                21,20 20,21
                20,21 1,21
                1,21 0,20
                0,1 1,0
            "
            Stretch="Fill"
            />
    

    我选择的宽度是任意的...

    【讨论】:

    • 谢谢梅林,我刚刚玩过这个,但我不能让它玩得很好。明天我会再来一次。这条线完全超出了它的界限,方形位看起来很奇怪,不过感谢您的回复。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-09-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多