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;武汉星起航明确…

学习笔记——动态路由——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;猜猜心里数字 嵌套语句 猜…

Pytest+Allure+Yaml+PyMsql+Jenkins+Gitlab接口自动化(四)Jenkins配置

一、背景 Jenkins&#xff08;本地宿主机搭建&#xff09; 拉取GitLab(服务器)代码到在Jenkins工作空间本地运行并生成Allure测试报告 二、框架改动点 框架主运行程序需要先注释掉运行代码&#xff08;可不改&#xff0c;如果运行报allure找不到就直接注释掉&#xff09; …