WPF自定义控件,实现含有箭头的文本或内容控件

文章目录

    • 背景
    • 效果预览
    • 方案设计
    • 分析
      • 基本布局
      • 添加控件自定义属性
      • 添加属性值监听
      • 获取点数据
    • 全部代码
      • HorizontalLineContent.xaml
      • HorizontalLineContent.xaml.cs
      • DirectionAlignment.cs
      • ContentDirectionAlignment.cs
    • 使用方法

背景

因为项目开发需要,要在WPF上绘制TCP的交互过程图,所以现在需要一个箭头控件,并且在箭头中间还可以加入文字,所以开发了这个HorizontalLineContent控件,后续可能还要开发垂直版本。😁

在这里插入图片描述

效果预览

在这里插入图片描述

在这里插入图片描述

方案设计

一开始设计的实现逻辑其实是有两种的:

  1. Polygon x 1 + Label x 1
    然后通过设置层级Index,让文本控件覆盖在图形上,但是有个致命的缺点,就是文本控件不能设置背景颜色为透明色,不然图形就会和文字重叠,所以没有采用该方案。

  2. Polygon x 2 + Label x 1
    通过计算Label的渲染宽度,然后计算两边图形的点数据,然后绘制图形,虽然该方案比上一个要繁琐一点,但是效果会好很多,后面也可以方便扩展其它的属性,比如:整体旋转、单独图形旋转、单独文字旋转等。

我这里目前只考虑了如下几个要素:

  • 直线大小
  • 控件颜色,这里没有做Text和箭头颜色的分开
  • 文本位置
  • 箭头方向
  • 箭头宽度和高度

核心的几点逻辑是:

  1. 我分为了两个Polygon去绘制图形,一个在左边,一个在右边,通过设置箭头方向然后确定哪一个Polygon去绘制箭头,另一个去绘制直线。
  2. 文本控件在中间水平居中,通过监听自定义控件属性Text的变化,然后重新计算文本控件的宽度,然后绘制控件的点数据。
  3. 我这里将控件的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; // 0var lineSize_1 = arrowHeight / 2.0 - lineSize / 2.0; // 4var lineSize_2 = arrowHeight / 2.0; // 6var lineSize_3 = arrowHeight / 2.0 + lineSize / 2.0; // 8var lineSize_4 = arrowHeight; // 12switch (direction){case DirectionAlignment.None:// Left Pointspoints.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 Pointspoints.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 Pointspoints.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 Pointspoints.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 Pointspoints.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 Pointspoints.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 的交互逻辑*/
#endregionnamespace 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; // 0var lineSize_1 = arrowHeight / 2.0 - lineSize / 2.0; // 4var lineSize_2 = arrowHeight / 2.0; // 6var lineSize_3 = arrowHeight / 2.0 + lineSize / 2.0; // 8var lineSize_4 = arrowHeight; // 12switch (direction){case DirectionAlignment.None:// Left Pointspoints.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 Pointspoints.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 Pointspoints.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 Pointspoints.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 Pointspoints.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 Pointspoints.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* 描述:*/
#endregionnamespace 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* 描述:*/
#endregionnamespace 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>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/864763.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【neo4j图数据库】入门实践篇

探索数据之间的奥秘&#xff1a;Neo4j图数据库引领新纪元 在数字化浪潮汹涌的今天&#xff0c;数据已成为企业最宝贵的资产之一。然而&#xff0c;随着数据量的爆炸性增长和数据关系的日益复杂&#xff0c;传统的关系型数据库在处理诸如社交网络、推荐系统、生物信息学等高度互…

代码随想录算法训练营第四十一天| 322. 零钱兑换、279.完全平方数、139.单词拆分

322. 零钱兑换 题目链接&#xff1a;322. 零钱兑换 文档讲解&#xff1a;代码随想录 状态&#xff1a;能想到凑足总额为j - coins[i]的最少个数为dp[j - coins[i]]&#xff0c;但没想到加上一个钱币coins[i]即dp[j - coins[i]] 1就是dp[j]&#xff08;考虑coins[i]&#xff09…

IDEA 好用的插件,必备的插件

1. GitToolBox 菜单栏显示git分支信息 2.MyBatisx 快速定位找到sql的xml文件 3.RestfulToolkit-fix 快速定位接口的插件 默认快捷键: CtrlAltN 4.EasyCamelQSM 字符串转驼峰 默认快捷键: Ctrl Alt Q 5.Maven Helper 检查maven冲突&#xff0c;图形化展示maven依赖的插…

Conan安装与C++第三方环境配置保姆级图文教程(附速查字典)

目录 1 什么是Conan&#xff1f;2 Conan安装与配置3 Conan的常见操作3.1 搜索指定包3.2 安装指定包3.3 本地包管理3.4 查看项目依赖 4 Conan构建项目案例 1 什么是Conan&#xff1f; Conan是一个开源的C/C包管理器&#xff0c;用于管理和构建C/C项目所需的依赖库。传统上&…

【启明智显分享】2.8寸触摸串口屏SC05 Plus应用于智能血压计

2.8寸SC05 Plus串口触摸屏&#xff0c;带WIFI/蓝牙 我国高血压流行病调查显示&#xff0c;成人高血压患病率为27.9&#xff05;、知晓率为46.9&#xff05;、治疗率为40.7&#xff05;、控制率为15.3&#xff05;。由此可见高血压的患病率高&#xff0c;但知晓率和治疗率低&…

【微信小程序开发实战项目】——如何制作一个属于自己的花店微信小程序(1)

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;开发者-曼亿点 &#x1f468;‍&#x1f4bb; hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍&#x1f4bb; 本文由 曼亿点 原创 &#x1f468;‍&#x1f4bb; 收录于专栏&#xff1a…

高危行业的安全守护者,顶坚防爆手机无惧挑战

高危行业的安全守护者&#xff0c;防爆手机以卓越性能&#xff0c;无惧极端挑战&#xff0c;为每一位前线工作者筑起坚不可摧的安全防线。石油勘探的深邃海洋、化工生产的复杂车间、矿山的幽深隧道……这些高危行业中&#xff0c;每一步都需谨慎前行&#xff0c;每一刻都需安全…

基于springboot的校园商铺管理系统

功能结构图&#xff1a; 实现图&#xff1a; 后台功能&#xff1a; 商品管理 公告管理 前台页面 详情 订单 我的订单

SciencePub学术刊源 | 7月SCI/SSCI/EI/CNKI刊源表已更新!(内含TOP及CCF推荐)

【SciencePub学术】我处SciencePub学术2024年7月SCI/SSCI/EI/CNKI刊源表已更新&#xff01;内含多本中科院TOP、CCF推荐以及进展超顺的优质期刊&#xff0c;最快1-3个月录用&#xff01; 计算机领域重点SCI 环境地质化学领域重点SCI 生物医学领域重点SCI 数学材料领域重点SCI 各…

同星TTS系列产品全新亮相:让开发测试变得更简单!

TTS系列产品 如果需要完整地测试 ECU&#xff0c;不仅需要将通信网络连接到测试系统&#xff0c;还需要连接 I/O 接口。同星的TTS测试系统将连接 I/O 通道所需的所有电路组件集成在一个模块中&#xff0c;可以极大地简化测试台架和HIL测试系统的设置&#xff0c;提高搭建和测试…

武汉星起航:跨境电商领域的领航者,助力合作伙伴全球布局

在跨境电商的汹涌浪潮中&#xff0c;武汉星起航电子商务有限公司如同一颗璀璨的明星&#xff0c;自2017年起便以亚马逊自营店铺为核心业务&#xff0c;不断积累实战运营经验&#xff0c;逐步建立了自己在市场中的稳固地位。随着2020年公司的正式成立&#xff0c;武汉星起航明确…

基于微信小程序的优鲜易购平台设计与实现

系统摘要 随着网络科技的迅速发展以及社会大众消费习惯的转变,微信小程序逐渐以其便捷性和易用性引起了人们的广泛关注。本文意在研发设计并实现一种基于微信小程序开发的优鲜商品易购系统,即一个专注于生鲜产品网上选购服务的买菜网站,利用SpringBoot和Vue.js的技术栈…

学习笔记——动态路由——IS-IS中间系统到中间系统(背景)

一、IS-IS技术背景 1、前言 IS-IS最初是国际标准化组织ISO(the International Organization for Standardization)为它的无连接网络协议CLNP(ConnectionLess Network Protocol)设计的一种动态路由协议。 和OSPF一样&#xff0c;IS-IS也是一种基于链路状态并使用最短路径优先…

浅谈制造企业如何借力EHS,让安全管理上新台阶

当今商业环境中&#xff0c;企业管理不仅关注经济效益&#xff0c;更将目光投向了长远发展的基石——EHS&#xff08;环境Environment、健康Health、安全Safety&#xff09;管理体系。这一体系的崛起&#xff0c;标志着企业管理理念的一次深刻变革&#xff0c;它如同企业的守护…

Chisel学习笔记(1)——Chisel安装与Verilog代码仿真

参考链接&#xff1a; https://www.chisel-lang.org/docs/installation 使用Chisel语言编写硬件描述语言&#xff0c;相比于使用Verilog会更加地灵敏快捷&#xff0c;Coding效率更高&#xff0c;但似乎debug会出现一些小问题。但新工具还是要尝试一下才知道好不好用。 1 安装C…

构建RAG+nebula graph(知识图谱KG)

目标&#xff1a;通过利用 LlamaIndex 和 NebulaGraph 为费城费城人队&#xff08;Philadelphia Phillies&#xff09;构建一个RAG流程&#xff0c;深入探讨知识图谱。 NebulaGraph 是市场上最好的知识图谱数据库之一。它是开源的、分布式的&#xff0c;并且能够处理具有亿万边…

【linux】网络基础(2)——udp协议

文章目录 引言udp协议的特点udp的头部结构UDP的工作原理简单的UDP网络程序套接字的认识udp服务端代码udp客户端代码服务端运行 引言 用户数据报协议&#xff08;User Datagram Protocol, UDP&#xff09;是一种无连接的传输层协议。它是因特网协议家族的一部分&#xff0c;定义…

C语言的数据结构:图的基本概念

前言 之前学过了其它的数据结构&#xff0c;如&#xff1a; 集合 \color{#5ecffd}集合 集合 —— 数据元素属于一个集合。 线型结构 \color{#5ecffd}线型结构 线型结构 —— 一个对一个&#xff0c;如线性表、栈、队列&#xff0c;每一个节点和其它节点之间的关系 一个对一个…

超酷的打字机效果?分享 1 段优质 CSS 代码片段!

大家好&#xff0c;我是大澈&#xff01; 本文约 900 字&#xff0c;整篇阅读约需 1 分钟。 每日分享一段优质代码片段。 今天分享一段优质 CSS 代码片段&#xff0c;实现打字机般的效果或其他类似的离散动画效果。 老规矩&#xff0c;先阅读代码片段并思考&#xff0c;再看代…

Python入门 2024/7/2

目录 格式化的精度控制 字符串格式化 对表达式进行格式化 小练习&#xff08;股票计算小程序&#xff09; 数据输入 布尔类型和比较运算符 if语句 小练习&#xff08;成人判断&#xff09; if-else语句 if-elif-else语句 练习&#xff1a;猜猜心里数字 嵌套语句 猜…