文章目录
- 背景
- 效果预览
- 方案设计
- 分析
- 基本布局
- 添加控件自定义属性
- 添加属性值监听
- 获取点数据
- 全部代码
- HorizontalLineContent.xaml
- HorizontalLineContent.xaml.cs
- DirectionAlignment.cs
- ContentDirectionAlignment.cs
- 使用方法
背景
因为项目开发需要,要在WPF上绘制TCP的交互过程图,所以现在需要一个箭头控件,并且在箭头中间还可以加入文字,所以开发了这个HorizontalLineContent
控件,后续可能还要开发垂直版本。😁
效果预览
方案设计
一开始设计的实现逻辑其实是有两种的:
-
Polygon x 1 + Label x 1
然后通过设置层级Index,让文本控件覆盖在图形上,但是有个致命的缺点,就是文本控件不能设置背景颜色为透明色,不然图形就会和文字重叠,所以没有采用该方案。 -
Polygon x 2 + Label x 1
通过计算Label的渲染宽度,然后计算两边图形的点数据,然后绘制图形,虽然该方案比上一个要繁琐一点,但是效果会好很多,后面也可以方便扩展其它的属性,比如:整体旋转、单独图形旋转、单独文字旋转等。
我这里目前只考虑了如下几个要素:
- 直线大小
- 控件颜色,这里没有做Text和箭头颜色的分开
- 文本位置
- 箭头方向
- 箭头宽度和高度
核心的几点逻辑是:
- 我分为了两个Polygon去绘制图形,一个在左边,一个在右边,通过设置箭头方向然后确定哪一个Polygon去绘制箭头,另一个去绘制直线。
- 文本控件在中间水平居中,通过监听自定义控件属性Text的变化,然后重新计算文本控件的宽度,然后绘制控件的点数据。
- 我这里将控件的Foreground属性绑定在了Polygon的Fill属性上,实现图形跟文字一起变色,如果需要单独控制文本和图形的颜色,可以拆开处理。
分析
基本布局
首先我们肯定是需要一个Label控件对文本内容进行显示,其次是需要一个能调整上中下位置的Grid,还需要两个Polygon去绘制图形。
所以基本样式就有了
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
<RowDefinition Height="Auto"></RowDefinition>
</Grid.RowDefinitions>
<Polygon Grid.Row="1" x:Name="pol_left" VerticalAlignment="Center" Fill="Black" Panel.ZIndex="1">
<Polygon.Points>
<Point X="0" Y="0"></Point>
<Point X="35" Y="0"></Point>
<Point X="35" Y="4"></Point>
<Point X="0" Y="4"></Point>
</Polygon.Points>
</Polygon>
<Polygon Grid.Row="1" x:Name="pol_right" VerticalAlignment="Center" Fill="Black" Panel.ZIndex="1">
<Polygon.Points>
<Point X="65" Y="0"></Point>
<Point X="100" Y="0"></Point>
<Point X="100" Y="4"></Point>
<Point X="65" Y="4"></Point>
</Polygon.Points>
</Polygon>
<Label Grid.Row="1" x:Name="txt_text"
FontFamily="Consolas" Padding="5 0 5 0"
VerticalAlignment="Center" HorizontalAlignment="Center" Panel.ZIndex="2"></Label>
</Grid>
在设计器中的效果如下图:
添加控件自定义属性
// 内容
public new object Content
{
get { return (string)GetValue(ContentProperty); }
set { SetValue(ContentProperty, value); }
}
public static new readonly DependencyProperty ContentProperty =
DependencyProperty.Register("Content", typeof(object), typeof(HorizontalLineContent), new PropertyMetadata(string.Empty));
// 箭头方向
public DirectionAlignment Direction
{
get { return (DirectionAlignment)GetValue(DirectionProperty); }
set { SetValue(DirectionProperty, value); }
}
public static readonly DependencyProperty DirectionProperty =
DependencyProperty.Register("Direction", typeof(DirectionAlignment), typeof(HorizontalLineContent), new PropertyMetadata(DirectionAlignment.None));
// 文本位置
public ContentDirectionAlignment ContentDirection
{
get { return (ContentDirectionAlignment)GetValue(ContentDirectionProperty); }
set { SetValue(ContentDirectionProperty, value); }
}
public static readonly DependencyProperty ContentDirectionProperty =
DependencyProperty.Register("ContentDirection", typeof(ContentDirectionAlignment), typeof(HorizontalLineContent), new PropertyMetadata(ContentDirectionAlignment.Center));
// 直线宽度
public double LineSize
{
get { return (double)GetValue(LineSizeProperty); }
set { SetValue(LineSizeProperty, value); }
}
public static readonly DependencyProperty LineSizeProperty =
DependencyProperty.Register("LineSize", typeof(double), typeof(HorizontalLineContent), new PropertyMetadata(4.0));
// 箭头宽度
public double ArrowWidth
{
get { return (double)GetValue(ArrowWidthProperty); }
set { SetValue(ArrowWidthProperty, value); }
}
public static readonly DependencyProperty ArrowWidthProperty =
DependencyProperty.Register("ArrowWidth", typeof(double), typeof(HorizontalLineContent), new PropertyMetadata(10.0));
// 箭头高度
public double ArrowHeight
{
get { return (double)GetValue(ArrowHeightProperty); }
set { SetValue(ArrowHeightProperty, value); }
}
public static readonly DependencyProperty ArrowHeightProperty =
DependencyProperty.Register("ArrowHeight", typeof(double), typeof(HorizontalLineContent), new PropertyMetadata(12.0));
添加属性值监听
// 监听整体控件宽度属性变化
ActualWidthPropertyDescriptor = DependencyPropertyDescriptor.FromProperty(ActualWidthProperty, typeof(Label));
ActualWidthPropertyDescriptor.AddValueChanged(txt_text, (o, e) =>
{
RefreshUI();
});
// 监听文本内容属性变化
ContentPropertyDescriptor = DependencyPropertyDescriptor.FromProperty(ContentProperty, typeof(HorizontalLineContent));
ContentPropertyDescriptor.AddValueChanged(this, (o, e) =>
{
RefreshUI();
});
// 监听箭头方向属性变化
DirectionPropertyDescriptor = DependencyPropertyDescriptor.FromProperty(DirectionProperty, typeof(HorizontalLineContent));
DirectionPropertyDescriptor.AddValueChanged(this, (o, e) =>
{
RefreshUI();
});
// 监听文本位置属性变化
ContentDirectionPropertyDescriptor = DependencyPropertyDescriptor.FromProperty(ContentDirectionProperty, typeof(HorizontalLineContent));
ContentDirectionPropertyDescriptor.AddValueChanged(this, (o, e) =>
{
RefreshUI();
});
// 监听直线宽度属性变化
LineSizePropertyDescriptor = DependencyPropertyDescriptor.FromProperty(LineSizeProperty, typeof(HorizontalLineContent));
LineSizePropertyDescriptor.AddValueChanged(this, (o, e) =>
{
RefreshUI();
});
// 监听箭头高度属性变化
ArrowHeightPropertyDescriptor = DependencyPropertyDescriptor.FromProperty(ArrowHeightProperty, typeof(HorizontalLineContent));
ArrowHeightPropertyDescriptor.AddValueChanged(this, (o, e) =>
{
RefreshUI();
});
// 监听箭头宽度属性变化
ArrowWidthPropertyDescriptor = DependencyPropertyDescriptor.FromProperty(ArrowWidthProperty, typeof(HorizontalLineContent));
ArrowWidthPropertyDescriptor.AddValueChanged(this, (o, e) =>
{
RefreshUI();
});
获取点数据
public List<Point> GetPoints(DirectionAlignment direction, double left, double mid_left, double mid_right, double right)
{
var points = new List<Point>();
if (ContentDirection != ContentDirectionAlignment.Center && ContentDirection != ContentDirectionAlignment.None)
{
mid_left = mid_right = this.ActualWidth / 2.0;
}
var mid_width = this.ActualWidth / 2.0;
var lineSize = LineSize < 1 ? 1 : LineSize;
var arrowWidth = ArrowWidth < 5 ? 5 : ArrowWidth;
var arrowHeight = ArrowHeight < 6 ? 6 : ArrowHeight;
if (arrowHeight < lineSize)
{
arrowHeight = lineSize;
}
var lineSize_0 = 0; // 0
var lineSize_1 = arrowHeight / 2.0 - lineSize / 2.0; // 4
var lineSize_2 = arrowHeight / 2.0; // 6
var lineSize_3 = arrowHeight / 2.0 + lineSize / 2.0; // 8
var lineSize_4 = arrowHeight; // 12
switch (direction)
{
case DirectionAlignment.None:
// Left Points
points.Add(new Point(0, lineSize_0));
points.Add(new Point(mid_left, lineSize_0));
points.Add(new Point(mid_left, lineSize));
points.Add(new Point(0, lineSize));
// Right Points
points.Add(new Point(mid_right, lineSize_0));
points.Add(new Point(right, lineSize_0));
points.Add(new Point(right, lineSize));
points.Add(new Point(mid_right, lineSize));
break;
case DirectionAlignment.Left:
// Left Points
points.Add(new Point(mid_left, lineSize_1));
points.Add(new Point(arrowWidth, lineSize_1));
points.Add(new Point(arrowWidth, lineSize_0));
points.Add(new Point(0, lineSize_2));
points.Add(new Point(arrowWidth, lineSize_4));
points.Add(new Point(arrowWidth, lineSize_3));
points.Add(new Point(mid_left, lineSize_3));
// Right Points
points.Add(new Point(mid_right, lineSize_0));
points.Add(new Point(right, lineSize_0));
points.Add(new Point(right, lineSize));
points.Add(new Point(mid_right, lineSize));
break;
case DirectionAlignment.Right:
// Left Points
points.Add(new Point(0, lineSize_0));
points.Add(new Point(mid_left, lineSize_0));
points.Add(new Point(mid_left, lineSize));
points.Add(new Point(0, lineSize));
// Right Points
points.Add(new Point(mid_right, lineSize_1));
points.Add(new Point(right - arrowWidth, lineSize_1));
points.Add(new Point(right - arrowWidth, lineSize_0));
points.Add(new Point(right, lineSize_2));
points.Add(new Point(right - arrowWidth, lineSize_4));
points.Add(new Point(right - arrowWidth, lineSize_3));
points.Add(new Point(mid_right, lineSize_3));
break;
}
return points;
}
全部代码
共4个文件
HorizontalLineContent.xaml
<Window x:Class="WpfApp3.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApp3"
mc:Ignorable="d" FontFamily="微软雅黑"
Title="MainWindow" Height="450" Width="1024">
<StackPanel Margin="20">
<Grid>
<TextBlock Grid.Row="0" HorizontalAlignment="Left" Text="客户端"></TextBlock>
<TextBlock Grid.Row="0" HorizontalAlignment="Right" Text="服务端"></TextBlock>
</Grid>
<local:HorizontalLineContent ContentDirection="TopLeft" LineSize="2" ArrowHeight="6" ArrowWidth="5" Direction="Right"
Content="文本位置【Top】,直线宽度【2】,箭头方向【None(默认)】"></local:HorizontalLineContent>
<local:HorizontalLineContent Margin="0 20 0 0" LineSize="4" ArrowHeight="12" ArrowWidth="10" Direction="Left" Foreground="Red"
Content="文本位置【None、Center】,直线宽度【4(默认)】,箭头方向【None】,ArrowHeight【12(默认)】,ArrowWidth【10(默认)】"></local:HorizontalLineContent>
<local:HorizontalLineContent Margin="0 20 0 0" ContentDirection="Bottom" Direction="Right" Foreground="Green"
Content="文本位置【Bottom】,Foreground【Green】"></local:HorizontalLineContent>
<local:HorizontalLineContent Margin="0 20 0 0" FontSize="16" ContentDirection="TopLeft" Direction="Right">
<local:HorizontalLineContent.Content>
<StackPanel Orientation="Horizontal">
<TextBlock Text="All Default" VerticalAlignment="Center"></TextBlock>
<StackPanel Margin="10 0 0 0">
<Button Content="【ASN.1】"></Button>
<Line Height="5"></Line>
<Button Content="【证书】"></Button>
</StackPanel>
</StackPanel>
</local:HorizontalLineContent.Content>
</local:HorizontalLineContent>
</StackPanel>
</Window>
HorizontalLineContent.xaml.cs
using System.Collections.Generic;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Shapes;
#region 文件版本信息
/*
* 创建者:Zekang Hao
* 邮箱:admin@haozekang.com
* 创建时间:2024/6/27 15:11:07
* 版本:1.0.0.0
* 描述:HorizontalLineContent.xaml 的交互逻辑
*/
#endregion
namespace WpfApp3
{
public partial class HorizontalLineContent : UserControl
{
private DependencyPropertyDescriptor ActualWidthPropertyDescriptor;
private DependencyPropertyDescriptor ContentPropertyDescriptor;
private DependencyPropertyDescriptor DirectionPropertyDescriptor;
private DependencyPropertyDescriptor ContentDirectionPropertyDescriptor;
private DependencyPropertyDescriptor LineSizePropertyDescriptor;
private DependencyPropertyDescriptor ArrowWidthPropertyDescriptor;
private DependencyPropertyDescriptor ArrowHeightPropertyDescriptor;
public new object Content
{
get { return (string)GetValue(ContentProperty); }
set { SetValue(ContentProperty, value); }
}
public static new readonly DependencyProperty ContentProperty =
DependencyProperty.Register("Content", typeof(object), typeof(HorizontalLineContent), new PropertyMetadata(string.Empty));
public DirectionAlignment Direction
{
get { return (DirectionAlignment)GetValue(DirectionProperty); }
set { SetValue(DirectionProperty, value); }
}
// Using a DependencyProperty as the backing store for Direction. This enables animation, styling, binding, etc...
public static readonly DependencyProperty DirectionProperty =
DependencyProperty.Register("Direction", typeof(DirectionAlignment), typeof(HorizontalLineContent), new PropertyMetadata(DirectionAlignment.None));
public ContentDirectionAlignment ContentDirection
{
get { return (ContentDirectionAlignment)GetValue(ContentDirectionProperty); }
set { SetValue(ContentDirectionProperty, value); }
}
// Using a DependencyProperty as the backing store for TextDirection. This enables animation, styling, binding, etc...
public static readonly DependencyProperty ContentDirectionProperty =
DependencyProperty.Register("ContentDirection", typeof(ContentDirectionAlignment), typeof(HorizontalLineContent), new PropertyMetadata(ContentDirectionAlignment.Center));
public double LineSize
{
get { return (double)GetValue(LineSizeProperty); }
set { SetValue(LineSizeProperty, value); }
}
// Using a DependencyProperty as the backing store for LineSize. This enables animation, styling, binding, etc...
public static readonly DependencyProperty LineSizeProperty =
DependencyProperty.Register("LineSize", typeof(double), typeof(HorizontalLineContent), new PropertyMetadata(4.0));
public double ArrowWidth
{
get { return (double)GetValue(ArrowWidthProperty); }
set { SetValue(ArrowWidthProperty, value); }
}
// Using a DependencyProperty as the backing store for ArrowWidth. This enables animation, styling, binding, etc...
public static readonly DependencyProperty ArrowWidthProperty =
DependencyProperty.Register("ArrowWidth", typeof(double), typeof(HorizontalLineContent), new PropertyMetadata(10.0));
public double ArrowHeight
{
get { return (double)GetValue(ArrowHeightProperty); }
set { SetValue(ArrowHeightProperty, value); }
}
// Using a DependencyProperty as the backing store for ArrowHeight. This enables animation, styling, binding, etc...
public static readonly DependencyProperty ArrowHeightProperty =
DependencyProperty.Register("ArrowHeight", typeof(double), typeof(HorizontalLineContent), new PropertyMetadata(12.0));
public HorizontalLineContent()
{
this.DataContext = this;
InitializeComponent();
txt_text.SetBinding(
Label.ContentProperty,
new Binding
{
Path = new PropertyPath(nameof(Content)),
UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged,
Mode = BindingMode.OneWay
}
);
txt_text.SetBinding(
ForegroundProperty,
new Binding
{
Path = new PropertyPath(nameof(Foreground)),
UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged,
Mode = BindingMode.OneWay
}
);
pol_left.SetBinding(
Polygon.FillProperty,
new Binding
{
Path = new PropertyPath(nameof(Foreground)),
UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged,
Mode = BindingMode.OneWay
}
);
pol_right.SetBinding(
Polygon.FillProperty,
new Binding
{
Path = new PropertyPath(nameof(Foreground)),
UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged,
Mode = BindingMode.OneWay
}
);
ActualWidthPropertyDescriptor = DependencyPropertyDescriptor.FromProperty(ActualWidthProperty, typeof(Label));
ActualWidthPropertyDescriptor.AddValueChanged(txt_text, (o, e) =>
{
RefreshUI();
});
ContentPropertyDescriptor = DependencyPropertyDescriptor.FromProperty(ContentProperty, typeof(HorizontalLineContent));
ContentPropertyDescriptor.AddValueChanged(this, (o, e) =>
{
RefreshUI();
});
DirectionPropertyDescriptor = DependencyPropertyDescriptor.FromProperty(DirectionProperty, typeof(HorizontalLineContent));
DirectionPropertyDescriptor.AddValueChanged(this, (o, e) =>
{
RefreshUI();
});
ContentDirectionPropertyDescriptor = DependencyPropertyDescriptor.FromProperty(ContentDirectionProperty, typeof(HorizontalLineContent));
ContentDirectionPropertyDescriptor.AddValueChanged(this, (o, e) =>
{
RefreshUI();
});
LineSizePropertyDescriptor = DependencyPropertyDescriptor.FromProperty(LineSizeProperty, typeof(HorizontalLineContent));
LineSizePropertyDescriptor.AddValueChanged(this, (o, e) =>
{
RefreshUI();
});
ArrowHeightPropertyDescriptor = DependencyPropertyDescriptor.FromProperty(ArrowHeightProperty, typeof(HorizontalLineContent));
ArrowHeightPropertyDescriptor.AddValueChanged(this, (o, e) =>
{
RefreshUI();
});
ArrowWidthPropertyDescriptor = DependencyPropertyDescriptor.FromProperty(ArrowWidthProperty, typeof(HorizontalLineContent));
ArrowWidthPropertyDescriptor.AddValueChanged(this, (o, e) =>
{
RefreshUI();
});
}
private void UserControl_SizeChanged(object sender, SizeChangedEventArgs e)
{
RefreshUI();
}
private void RefreshUI()
{
if (pol_left == null || pol_right == null || txt_text == null)
{
return;
}
double control_middle = this.ActualWidth / 2.0;
double txt_width_middle = txt_text.ActualWidth / 2.0;
double mid_left = control_middle - txt_width_middle;
double mid_right = control_middle + txt_width_middle;
if (Direction != DirectionAlignment.None && ContentDirection == ContentDirectionAlignment.Center)
{
if (mid_left < 10)
{
pol_left.Visibility = Visibility.Collapsed;
pol_right.Visibility = Visibility.Collapsed;
}
else
{
pol_left.Visibility = Visibility.Visible;
pol_right.Visibility = Visibility.Visible;
}
}
switch (ContentDirection)
{
case ContentDirectionAlignment.None:
case ContentDirectionAlignment.Center:
txt_text.Padding = new Thickness(0, 0, 0, 0);
txt_text.SetValue(Grid.RowProperty, 1);
break;
case ContentDirectionAlignment.Top:
case ContentDirectionAlignment.TopLeft:
case ContentDirectionAlignment.TopRight:
if (Direction == DirectionAlignment.None)
{
txt_text.Padding = new Thickness(0, 0, 0, 4);
}
else
{
txt_text.Padding = new Thickness(0, 0, 0, 0);
}
txt_text.SetValue(Grid.RowProperty, 0);
break;
case ContentDirectionAlignment.Bottom:
case ContentDirectionAlignment.BottomLeft:
case ContentDirectionAlignment.BottomRight:
if (Direction == DirectionAlignment.None)
{
txt_text.Padding = new Thickness(0, 4, 0, 0);
}
else
{
txt_text.Padding = new Thickness(0, 0, 0, 0);
}
txt_text.SetValue(Grid.RowProperty, 2);
break;
}
switch (ContentDirection)
{
case ContentDirectionAlignment.TopLeft:
case ContentDirectionAlignment.BottomLeft:
txt_text.HorizontalAlignment = HorizontalAlignment.Left;
break;
case ContentDirectionAlignment.TopRight:
case ContentDirectionAlignment.BottomRight:
txt_text.HorizontalAlignment = HorizontalAlignment.Right;
break;
default:
txt_text.HorizontalAlignment = HorizontalAlignment.Center;
break;
}
pol_left.Points.Clear();
pol_right.Points.Clear();
var points = GetPoints(Direction, 0, mid_left, mid_right, this.ActualWidth);
if (Direction == DirectionAlignment.None)
{
for ( int i = 0; i < 4; i++)
{
pol_left.Points.Add(points[i]);
}
for ( int i = 4; i < 8; i++)
{
pol_right.Points.Add(points[i]);
}
}
else if (Direction == DirectionAlignment.Left)
{
for (int i = 0; i < 7; i++)
{
pol_left.Points.Add(points[i]);
}
for (int i = 7; i < 11; i++)
{
pol_right.Points.Add(points[i]);
}
}
else if(Direction == DirectionAlignment.Right)
{
for (int i = 0; i < 4; i++)
{
pol_left.Points.Add(points[i]);
}
for (int i = 4; i < 11; i++)
{
pol_right.Points.Add(points[i]);
}
}
}
public List<Point> GetPoints(DirectionAlignment direction, double left, double mid_left, double mid_right, double right)
{
var points = new List<Point>();
if (ContentDirection != ContentDirectionAlignment.Center && ContentDirection != ContentDirectionAlignment.None)
{
mid_left = mid_right = this.ActualWidth / 2.0;
}
var mid_width = this.ActualWidth / 2.0;
var lineSize = LineSize < 1 ? 1 : LineSize;
var arrowWidth = ArrowWidth < 5 ? 5 : ArrowWidth;
var arrowHeight = ArrowHeight < 6 ? 6 : ArrowHeight;
if (arrowHeight < lineSize)
{
arrowHeight = lineSize;
}
var lineSize_0 = 0; // 0
var lineSize_1 = arrowHeight / 2.0 - lineSize / 2.0; // 4
var lineSize_2 = arrowHeight / 2.0; // 6
var lineSize_3 = arrowHeight / 2.0 + lineSize / 2.0; // 8
var lineSize_4 = arrowHeight; // 12
switch (direction)
{
case DirectionAlignment.None:
// Left Points
points.Add(new Point(0, lineSize_0));
points.Add(new Point(mid_left, lineSize_0));
points.Add(new Point(mid_left, lineSize));
points.Add(new Point(0, lineSize));
// Right Points
points.Add(new Point(mid_right, lineSize_0));
points.Add(new Point(right, lineSize_0));
points.Add(new Point(right, lineSize));
points.Add(new Point(mid_right, lineSize));
break;
case DirectionAlignment.Left:
// Left Points
points.Add(new Point(mid_left, lineSize_1));
points.Add(new Point(arrowWidth, lineSize_1));
points.Add(new Point(arrowWidth, lineSize_0));
points.Add(new Point(0, lineSize_2));
points.Add(new Point(arrowWidth, lineSize_4));
points.Add(new Point(arrowWidth, lineSize_3));
points.Add(new Point(mid_left, lineSize_3));
// Right Points
points.Add(new Point(mid_right, lineSize_0));
points.Add(new Point(right, lineSize_0));
points.Add(new Point(right, lineSize));
points.Add(new Point(mid_right, lineSize));
break;
case DirectionAlignment.Right:
// Left Points
points.Add(new Point(0, lineSize_0));
points.Add(new Point(mid_left, lineSize_0));
points.Add(new Point(mid_left, lineSize));
points.Add(new Point(0, lineSize));
// Right Points
points.Add(new Point(mid_right, lineSize_1));
points.Add(new Point(right - arrowWidth, lineSize_1));
points.Add(new Point(right - arrowWidth, lineSize_0));
points.Add(new Point(right, lineSize_2));
points.Add(new Point(right - arrowWidth, lineSize_4));
points.Add(new Point(right - arrowWidth, lineSize_3));
points.Add(new Point(mid_right, lineSize_3));
break;
}
return points;
}
}
}
DirectionAlignment.cs
#region 文件版本信息
/*
* 创建者:Zekang Hao
* 邮箱:admin@haozekang.com
* 创建时间:2024/6/27 17:01:16
* 版本:1.0.0.0
* 描述:
*/
#endregion
namespace WpfApp3
{
/// <summary>
/// 描述
/// </summary>
public enum DirectionAlignment
{
None,
Left,
Right,
}
}
ContentDirectionAlignment.cs
#region 文件版本信息
/*
* 创建者:Zekang Hao
* 邮箱:admin@haozekang.com
* 创建时间:2024/6/28 11:17:07
* 版本:1.0.0.0
* 描述:
*/
#endregion
namespace WpfApp3
{
/// <summary>
/// 描述
/// </summary>
public enum ContentDirectionAlignment
{
None,
Top,
Center,
Bottom,
TopLeft,
TopRight,
BottomLeft,
BottomRight,
}
}
使用方法
<Window x:Class="WpfApp3.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApp3"
mc:Ignorable="d" FontFamily="微软雅黑"
Title="MainWindow" Height="450" Width="1024">
<StackPanel Margin="20">
<Grid>
<TextBlock Grid.Row="0" HorizontalAlignment="Left" Text="客户端"></TextBlock>
<TextBlock Grid.Row="0" HorizontalAlignment="Right" Text="服务端"></TextBlock>
</Grid>
<local:HorizontalLineContent ContentDirection="TopLeft" LineSize="2" ArrowHeight="6" ArrowWidth="5" Direction="Right"
Content="文本位置【Top】,直线宽度【2】,箭头方向【None(默认)】"></local:HorizontalLineContent>
<local:HorizontalLineContent Margin="0 20 0 0" LineSize="4" ArrowHeight="12" ArrowWidth="10" Direction="Left" Foreground="Red"
Content="文本位置【None、Center】,直线宽度【4(默认)】,箭头方向【None】,ArrowHeight【12(默认)】,ArrowWidth【10(默认)】"></local:HorizontalLineContent>
<local:HorizontalLineContent Margin="0 20 0 0" ContentDirection="Bottom" Direction="Right" Foreground="Green"
Content="文本位置【Bottom】,Foreground【Green】"></local:HorizontalLineContent>
<local:HorizontalLineContent Margin="0 20 0 0" FontSize="16" ContentDirection="TopLeft" Direction="Right">
<local:HorizontalLineContent.Content>
<StackPanel Orientation="Horizontal">
<TextBlock Text="All Default" VerticalAlignment="Center"></TextBlock>
<StackPanel Margin="10 0 0 0">
<Button Content="【ASN.1】"></Button>
<Line Height="5"></Line>
<Button Content="【证书】"></Button>
</StackPanel>
</StackPanel>
</local:HorizontalLineContent.Content>
</local:HorizontalLineContent>
</StackPanel>
</Window>