c# - WPF 矩形边框与两条破折号的连接线的角

标签 c# wpf xaml

在我的 WPF 应用程序中,我想为 dag 设置 reactangle 的样式并拖放文件。这个盒子的外观应该是这样的。

What i want

有可能在 XAML 中实现这个结果吗?

到目前为止,我已经设法做到了这一点。

What I currently have

问题出在角 I。角的外观应该像两条破折号的连接线。例如,左下角 - “L”可以调整 reactangle 的大小。

这是我当前的代码,是在这个答案的帮助下创建的:
How can I achieve a dashed or dotted border in WPF?

<Rectangle 
        Fill="LightGray"
        AllowDrop="True"
        Stroke="#FF000000"
        StrokeThickness="2" 
        StrokeDashArray="5 4"
        SnapsToDevicePixels="True"
        MinHeight="200"
        MinWidth="200"
        />

最佳答案

要在 WPF 中获得这些漂亮的 L 形角,您必须分别绘制水平和垂直边框,因为两者的 StrokeDashArray 不会(总是)相同。

您对 StrokeDashArray 的要求是:

  • 每一行都应该以破折号开始和结束
  • 破折号的长度应该保持不变
  • 应通过拉伸(stretch)破折号之间的空间来填充多余/缺失的距离

要获得绘制一条线所需的精确长度,您必须计算虚线中的线数 (+1) 和空格,例如像这样:

private IEnumerable<double> GetDashArray(double length)
{
    double useableLength = length - StrokeDashLine;
    int lines = (int)Math.Round(useableLength/(StrokeDashLine + StrokeDashSpace));
    useableLength -= lines*StrokeDashLine;

    double actualSpacing = useableLength/lines;

    yield return StrokeDashLine / StrokeThickness;
    yield return actualSpacing / StrokeThickness;
} 

将其包装在自定义控件中,您将得到如下内容:

Dashed Rectangle with L-shaped corners

<local:NiceCornersControl Fill="LightGray" Stroke="Black" 
  StrokeThickness="2" StrokeDashLine="5" StrokeDashSpace="5">
    <TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" 
      Text="Drop files here"/>
</local:NiceCornersControl>

您应该注意的几件事:

  • 要让您的线在矩形“内部”,您需要将它们偏移 StrokeThickness/2
  • DashStyle 将随您的 StrokeThickness 缩放
  • 对于半透明笔触颜色,这可能看起来很奇怪

控件的完整代码:

using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;

namespace InsertNamespaceHere
{
    public class NiceCornersControl : ContentControl
    {
        public static readonly DependencyProperty StrokeProperty = DependencyProperty.Register(
            "Stroke", typeof(Brush), typeof(NiceCornersControl), new PropertyMetadata(default(Brush), OnVisualPropertyChanged));

        public Brush Stroke
        {
            get { return (Brush)GetValue(StrokeProperty); }
            set { SetValue(StrokeProperty, value); }
        }

        public static readonly DependencyProperty StrokeThicknessProperty = DependencyProperty.Register(
            "StrokeThickness", typeof(double), typeof(NiceCornersControl), new PropertyMetadata(default(double), OnVisualPropertyChanged));

        public double StrokeThickness
        {
            get { return (double)GetValue(StrokeThicknessProperty); }
            set { SetValue(StrokeThicknessProperty, value); }
        }

        public static readonly DependencyProperty StrokeDashLineProperty = DependencyProperty.Register(
            "StrokeDashLine", typeof(double), typeof(NiceCornersControl), new PropertyMetadata(default(double), OnVisualPropertyChanged));

        public double StrokeDashLine
        {
            get { return (double)GetValue(StrokeDashLineProperty); }
            set { SetValue(StrokeDashLineProperty, value); }
        }

        public static readonly DependencyProperty StrokeDashSpaceProperty = DependencyProperty.Register(
            "StrokeDashSpace", typeof(double), typeof(NiceCornersControl), new PropertyMetadata(default(double), OnVisualPropertyChanged));

        public double StrokeDashSpace
        {
            get { return (double)GetValue(StrokeDashSpaceProperty); }
            set { SetValue(StrokeDashSpaceProperty, value); }
        }

        public static readonly DependencyProperty FillProperty = DependencyProperty.Register(
            "Fill", typeof(Brush), typeof(NiceCornersControl), new PropertyMetadata(default(Brush), OnVisualPropertyChanged));

        public Brush Fill
        {
            get { return (Brush)GetValue(FillProperty); }
            set { SetValue(FillProperty, value); }
        }

        private static void OnVisualPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ((NiceCornersControl)d).InvalidateVisual();
        }

        public NiceCornersControl()
        {
            SnapsToDevicePixels = true;
            UseLayoutRounding = true;
        }

        protected override void OnRender(DrawingContext drawingContext)
        {
            double w = ActualWidth;
            double h = ActualHeight;
            double x = StrokeThickness / 2.0;

            Pen horizontalPen = GetPen(ActualWidth - 2.0 * x);
            Pen verticalPen = GetPen(ActualHeight - 2.0 * x);

            drawingContext.DrawRectangle(Fill, null, new Rect(new Point(0, 0), new Size(w, h)));

            drawingContext.DrawLine(horizontalPen, new Point(x, x), new Point(w - x, x));
            drawingContext.DrawLine(horizontalPen, new Point(x, h - x), new Point(w - x, h - x));

            drawingContext.DrawLine(verticalPen, new Point(x, x), new Point(x, h - x));
            drawingContext.DrawLine(verticalPen, new Point(w - x, x), new Point(w - x, h - x));
        }

        private Pen GetPen(double length)
        {
            IEnumerable<double> dashArray = GetDashArray(length);
            return new Pen(Stroke, StrokeThickness)
            {
                DashStyle = new DashStyle(dashArray, 0),
                EndLineCap = PenLineCap.Square,
                StartLineCap = PenLineCap.Square,
                DashCap = PenLineCap.Flat
            };
        }

        private IEnumerable<double> GetDashArray(double length)
        {
            double useableLength = length - StrokeDashLine;
            int lines = (int)Math.Round(useableLength / (StrokeDashLine + StrokeDashSpace));
            useableLength -= lines * StrokeDashLine;
            double actualSpacing = useableLength / lines;

            yield return StrokeDashLine / StrokeThickness;
            yield return actualSpacing / StrokeThickness;
        }
    }
}

关于c# - WPF 矩形边框与两条破折号的连接线的角,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42341592/

相关文章:

c# - 如何在编译器中查找导致异常的文件?

c# - CancellationToken 并未取消所有任务

c# - WPF 文本框插入符消失

c# - WPF Dispatcher 的 InvokeAsync 和 BeginInvoke 有什么区别

c# - 使用 WPF C# 中的多个控件组合创建自定义控件

c# - 为什么@User.IsInRole在_Layout.cshtml中总是返回false

c# - 使用 Graph Api 针对租户进行角色计数

c# - 在while循环中替代线程 sleep

c# - 由于对象的当前状态,操作无效。当我删除按钮时

wpf - 如何在 WPF 中右对齐 'help' 菜单项?