我去试了一下,结果一个要 paddleocr_sharp.dll ( GPU 推理加速要收费),一个要 ppocr.dll (教程里说:从官方 GitHub 仓库下载预编译的 Windows 版本(含 ppocr.dll ),但是 release 的包里没有这个 dll )
弄了一上午了,快放弃了,还不如 python
希望有懂这方面的来指导一下,小弟感恩不尽
]]>想起它骨子里的优雅、现代,却又务实
我欣赏,并且依赖
它有清晰的层次感,每一个类型都有其职责,每一次异步都流转自如
它不给我繁琐,却给我前所未有的效率
它的世界里没有边界的束缚,没有平台的隔阂,只有封装下的无限可能
它能在不失真的前提下演进出精彩,托管如云,却稳如泰山
C# ,我想你了
]]>问题描述:电脑通过串口读取硬件的数据,设备会连续不断返回数据,如果设备每秒返回 50 次数据,软件就不会闪退。如果设备返回数据的速度超过 200 次每秒,就有一定的概率会出现闪退的问题,闪退的频率大概就是 1-2 小时出现一次,偶尔会 10 分钟内连续出现两次。我换过不同的设备,只要是读取速度过快,都会出现相同的问题。
读取数据的代码片段是:
_serialPort = new SerialPort(); _serialPort.Parity = Parity.None; _serialPort.DataBits = 8; _serialPort.StopBits = StopBits.One; _serialPort.RtsEnable = true; _serialPort.Handshake = Handshake.None; _serialPort.ReadTimeout = 5; _serialPort.WriteTimeout = 5; _serialPort.ReceivedBytesThreshold = 1; _serialPort.DataReceived += OnSerialDataReceived; private async void OnSerialDataReceived(object sender, SerialDataReceivedEventArgs e){ var buffer = new byte[512]; // 最多读 10 字节 int numRead = await _serialPort.BaseStream.ReadAsync(buffer, 0, buffer.Length); }
闪退的时候报错信息:
[06/02/2025 01:20:02] InvalidOperationException: Argument_NativeOverlappedAlreadyFree at System.Threading.ThreadPoolBoundHandle.OnNativeIOCompleted(IntPtr instance, IntPtr context, IntPtr overlappedPtr, UInt32 ioResult, UIntPtr numberOfBytesTransferred, IntPtr ioPtr)
第一个帮助我解决问题的小伙伴,200 红包感谢。
]]>结果上生产环境后经常出现奇怪的输入内容没拦截掉
"测试".All(x=>char.IsLetterOrDigit(x))
最后发现原因出在 Cursor 生成的这行代码输入中文结果居然是 ture
混在一堆代码里面完全想不到这里能出问题,我手写的话根本不知道 C#有这个函数就不会出问题
C#这起得啥名太具迷惑性了,和 Python 的 rstrip 一样,rstrip 我是没用错过,但看过不止一个开源项目里面用错了
]]>今天在 Windows 上写了个小数据处理脚本,出于好奇去安装了一下 .NET 9 ,用 GPT 把 Python 转成了 C# 去跑,发现这东西跑起来飞快,比 Python 快了不止七八倍,CPU 也吃满了。
继而去查了一下 Debian 的 The Computer Language Benchmarks Game 。不看不知道,好家伙,现在 C# aot 都能在 CLBG 排到 Go 头上去了:
Language | elapsed secs / fastest |
---|---|
Intel C | 1.1 |
C | 1.3 |
C# aot | 1.5 |
Java | 1.5 |
Go | 1.6 |
虽然性能测试和 Java 差不多,但内存占用要少 50%~70%。试了一下 AOT 编译,编译出来就一个 4~5MB 可执行文件,体积很小也无依赖,额外开销基本和 Rust 、C++ 那些原生语言差不多无感。
但这可是带 GC 的「重型」语言啊,微软这几年的优化确实厉害。
所以感觉这语言挺有意思,准备最近多花时间当兴趣学习一下,但还是对微软的东西不是很放心。问问各位 C# 开发:C# 有什么特别明显缺点或者写起来卡手的地方吗? 提前谢谢大家。
]]>但是在使用 C#就没办法正常通讯
首先 我确认了线是没问题的,串口属性是没问题的 9600-8-n-1
byte[] command = new byte[] { 0xAA, 0x55, 0x12, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEE };
// 发送数据 serialPort.Write(command, 0, command.Length);
就很奇怪
]]>开发:vs2022 、Rider
]]>以上只是一个例子。其实用 visual studio 新建任何有依赖项的项目时都会面临这个问题。
GPT 让我用 nuget 对每个项目指定相应版本的包。但是当项目很多的时候会有大量重复的工作。
]]> var handler = new HttpClientHandler { AllowAutoRedirect = false, CookieCOntainer= new CookieContainer(), UseCookies = true, UseProxy = true, Proxy = new WebProxy("http://127.0.0.1:8888", false), ServerCertificateCustomValidatiOnCallback= (message, cert, chain, errors) => { return true; }, MaxAutomaticRedirectiOns= 1,
}; using HttpClient webclient = new(handler); webclient.DefaultRequestVersion = HttpVersion.Version20; webclient.Timeout = TimeSpan.FromSeconds(10);
webclient.DefaultRequestHeaders.Host = urls[1]; webclient.DefaultRequestHeaders.TryAddWithoutValidation("User-Agent", ua(mobile)); webclient.DefaultRequestHeaders.TryAddWithoutValidation("x-requested-with", "com.ct.client"); webclient.DefaultRequestHeaders.TryAddWithoutValidation("upgrade-insecure-requests", "1"); HttpResponseMessage respOnse= await webclient.GetAsync(urls[0]); 然后就一直没反应了
]]>首先做了一个小程序,读取了目录下的 100 个需要转换的文件的路径信息,然后 100 个依次进行转换,耗时 0.4* 100 = 40s
然后我把这个小程序复制了一个,成了小程序 2.
小程序和小程序 2 可以同时双开,进行文件转换。速度也加快了。
但是当我尝试在一个程序里面使用 task 或者多线程调用 DLL 里面的文件转换函数的时候,就报错了。DLL 内置了加密狗权限查阅功能,此时就异常了。但是很奇怪的是,小程序 1 和小程序 2 可以同时运行,没有出现机密狗权限的问题。
困扰我好久的问题,有大佬可以解答疑惑吗?
]]>private void decodeCurrentFrame()
{ if (graphics == null) { return; } //复制图像 this.graphics.CopyFromScreen(Screen.PrimaryScreen.Bounds.X, Screen.PrimaryScreen.Bounds.Y, 0, 0, new Size(width, height), CopyPixelOperation.SourceCopy); this.pictureBox1.Image = this.bitmapSrc; Stopwatch sw = new Stopwatch(); sw.Start(); Bitmap bitmap = (Bitmap)this.bitmapSrc.Clone(); //解码图片 Result[] results = reader.DecodeMultiple(bitmap); //读取识别出来的二维码 if (results != null) { foreach (Result result in results) { { Console.WriteLine("成功识别"); string cOntent= result.ToString(); if (content.Length <= 20) { return; } string prefix = content.Substring(0, 16); //获取文件前缀 string currentIndex = prefix.Substring(0, 8); //获取当前切片索引编号 string total = prefix.Substring(8); //获取总索引数 if (content.Contains("|")) { int prefixIndex = content.LastIndexOf("|"); int qrCurrentIndex = content.IndexOf("|"); currentIndex = content.Substring(0, qrCurrentIndex); string raw = content.Substring(prefixIndex + 1); cOntent= "0000000000000000" + raw; Console.WriteLine("旧版数据" + raw + "索引编号:" + currentIndex); } initResultMap(total); dealData(currentIndex, content.Substring(16)); checkResultMap(); } } } //统计数据 sw.Stop(); TimeSpan ts = sw.Elapsed; string costed = ts.TotalMilliseconds + "ms"; labelTickCost.Text = costed; }
pyhon 核心代码
def decodeDisplay(img):
global number barcodes = pyzbar.decode(img) for barcode in barcodes: barcodeData = barcode.data.decode() try: i = int(barcodeData[:8]) except ValueError: return img try: max = int(barcodeData[8:16]) except ValueError: return img ll = '' if not os.path.exists("temp/result" + str(i) + ".txt"): barcodeData = barcodeData[16:] with open("temp/result" + str(i) + ".txt", "w+") as f: f.write(barcodeData) number = number + 1 global sat if number == max: filecount = len(os.listdir('temp/result')) if number != filecount: number = filecount continue j = 1 while j <= number: with open("temp/result" + str(j) + ".txt", "r+") as f: txt = f.read() ll = ll + txt j = j + 1 global starttime ent = time.time() theLB.insert(END, "识别结束") theLB.see(END) with open("result/b64.txt", "w") as f: f.write(ll) temp = base64.b64decode(ll) with open("result/result.txt", "wb") as f: f.write(temp) if tkinter.messagebox.askyesno(title='识别成功', message='另存为'): old_path = tk.filedialog.askdirectory() shutil.copy("result/result.txt", old_path) theLB.insert(END, "识别成功") del_file() return img
]]>感觉应该是官方文档。但是当我打开这个页面搜索结果页时,发现标题后面都会显示个人作者名。打开这些作者名以后发现他们并没有显著的微软官方职位。所以这个网址的内容是否属于 C#官方文档?
或者这只是微软版的 CSDN ?如果这是微软版的 CSDN ,那么真正的官方 C#文档地址在哪里呢?
]]>见上图,用 vscode 调试 C# 为什么需要新建项目啊。项目下面有一堆文件。我用 matlab 学打个 hello word 。只需要一个代码文件就可以了。到了 C# 只新建一个.cs 文件什么也干不了。必须要 dotnet new console 新建项目
--------------------- 我发现一般讲代码的书或视频对此都是一代而过。只教怎么新建项目。不解释这些文件的作用和意义。我想先对这些文件的含义有个整体概念。因为我想在 vscode 里用 NUnit 跑个单元测试,体会一下书上的代码。没想到一上来就被这些项目文件给搞晕了。在 matlab 中只需要源代码,就可以跑起来,打断点,看结果。 关于这些文件,我想搞懂他们的作用,意义。对程序的编译运行有什么影响。背后的概念。有什么书籍或视频推荐么?科普向的。我自学!
]]>1 、这个类声明了一个属性 RPM ,显然希望 set 是 private ,我猜测这样声明会导致,get 是 public ?
2 、我知道 C++的 class 默认属性都是 private ,所以要显示声明 public ,C#也是如此?
3 、这个属性改成 int RPM{public get; private set; } 是不是可以达到同样的效果?
class Engine {
public int RPM{get; private set; }
}
]]>1 、负数值如果当前对象小于参数对象;
2 、正数值如果当前对象大于参数对象;
3 、零如果两个对象在比较时相等。
Sort 使用的算法依赖于使用元素的 CompareTo 方法来决定两个元素的次序。int 类型实现了 IComparable, 但是 MyClass 没有,因此当 Sort 尝试调用 MyClass 不存在的 CompareTo 方法时会抛出异常。
---------太好了,只要我的 Myclass 继承了 IComparable 接口。就可以愉快的使用 sort 方法了吧?可是看到下面代码的时候我就沉默了。你看第三行,它怎么自己实现了 CompareTo 方法。难道我继承了 IComparable 接口不就是不想重复造轮子么?如果我自己重写 CompareTo ,那还不如不继承接口,自己直接手写 sort 方法不就完了? 难道 BCL 中就没有自己的 CompareTo ?如果没有自带的 CompareTo ,那么当你对标准数组排序调用 sort 方法时,sort 调用的是谁的 CompareTo 方法呢?
截图
之所以纠结这个问题,是因为下面的情况是在 matlab 面向对象程序中从未遇到的情况。mgr 到底是哪个类的对象呢? IExtensionManager 的? FileExtensionManage ? 虽然 FileExtensionManage 是 IExtensionManager 的子类 ,但是二者的字段 数量可能都不一样,最后 mgr 到底以谁为模板生成对象了呢?会不会出现鼠头鸭脖的矛盾呢?
截图
请看上面这段单元测试的讲解,有两个问题:
1 、为什么“使用[Setup] 越多,测试代码可读性就越差。为了理解测试怎么得到实例,使用的对象是什么类型,人们不得不同时看文件里的两处代码。” 是因为由于 setup 的存在。所以每执行一次 test 标签的代码就会重新执行一次 m_analyzer = new LogAnalyzer(); 么? 但是这为什么会导致可读性变差。为什么会不得不同时看文件里的两处代码?而且书中说一段测试代码只能使用一个 setup 模块。所以何来“使用[Setup] 越多”的问题呢?
2 、为什么代码中最后一部分 public void TearDown () 说“不是必须的,在真实刹试中请不要使用”
]]>// 像素转换信息 public class ConvertParam { // 输入的图像信息 public CImage InImage { get; set; } // 输出的图像信息 public CImage OutImage { get; set; } // 构造函数 public ConvertParam() { InImage = new CImage(); OutImage = new CImage(); } }
大佬们,上面 ConvertParam 类里面有两个 CImage 类型的属性 InImage 和 OutImage ,
下面的无参构造函数能不能省略呢?
如果不能的话,这个无参构造函数起什么必要的作用呢?
]]>网上下了一个海康相机 C# 的 Demo 。resx 文件有英文和中文的,点“开始执行”后得到的窗体标签的文字都是英文的,怎么让它默认显示英文呢?
本地计算机的地区和语言都是 [中国|中文]
]]>this 关键字指代类的当前实例,还可用作扩展方法的第一个参数的修饰符。
问题:
1 、在 Forms 类中,使用 this 的话,窗体可以弹出
2 、在 Forms 类中,不使用 this ,自己去创建实例的话,窗体无法弹出
这是为啥呢?
]]>现在该如何选择方向,学些什么以后会好一下(想做一下职业规划,毕竟如果被辞了,怕不知道干什么)
在网上找了好多,都是几年前的,而且对 C#也没有一些最新的评价
]]>服务端断点时,一个一个看客户端又能收到,关闭断点有低概率收到完整,大概率又收不完全。
其实循环里面只用发一次,调试故意发 5 次,至少收到 1 次,但没试过 5 次都全收到,除非卡着断点一个一个 Send 走。
// 创建其他玩家 foreach (var model in DALManager.Instance.UserDal.GetAllUserModel()) { Server.Send(connid, MessageType.Type_User, MessageType.User_Create_S, model.ID, model.UserInfo.ModelID, model.Point); Server.Send(connid, MessageType.Type_User, MessageType.User_Create_S, model.ID, model.UserInfo.ModelID, model.Point); Server.Send(connid, MessageType.Type_User, MessageType.User_Create_S, model.ID, model.UserInfo.ModelID, model.Point); Server.Send(connid, MessageType.Type_User, MessageType.User_Create_S, model.ID, model.UserInfo.ModelID, model.Point); Server.Send(connid, MessageType.Type_User, MessageType.User_Create_S, model.ID, model.UserInfo.ModelID, model.Point); }
封装的 Send 方法;
public static void Send(IntPtr connid, byte type, int command, params object[] content) { Message message = new Message(type, command, content); byte[] bytes = Message.ToBytes(message); server.Send(connid, bytes, bytes.Length); }
hp-socket 的代码了;
public bool Send(IntPtr connId, byte[] bytes, int length) { GCHandle gcHandle = GCHandle.Alloc((object) bytes, GCHandleType.Pinned); bool flag = HPSocket.Sdk.Server.HP_Server_Send(this.SenderPtr, connId, gcHandle.AddrOfPinnedObject(), length); this.SysErrorCode.Value = flag ? 0 : Sys.SYS_GetLastError(); gcHandle.Free(); return flag; }
似乎连续总是会丢失后面的,有大佬知道问题在哪吗?
]]>let a = if <slow operation A> { 1 } else if <slow operation B> { 2 } else { 3 };
(注:Rust 不带mut
默认是常量)
没有这个功能的话,a 就得声明成 mutable ,然后在条件分支里面改,或者用一长串?:?:。 用 C++的时候是用一个临时的 lambda ,在条件里 return 。
const int i = [&]() { if (<slow operation A>) return 1; else if (<slow operation A>) return 2; else return 3; }();
看 V 站经常有人说 C#功能大杂烩,有没有好一点的办法?
]]>就是实现继承单例“MySingletonBase”,管理基类“ManagerBase”继承“MySingletonBase”实现单例,“UIManager”又继承“ManagerBase”,现在的问题就是假如有好多个“ManagerBase”的实现类怎么存到一个“List<ManagerBase<MonoBehaviour>> Managers = new List<ManagerBase<MonoBehaviour>>()”里面,主要就是那个泛型“T”不知道怎么处理,一直提示类型不对。
看视频就看到“UIManager : ManagerBase<UIManager>”是这么写,至于 List 怎么改都存不进去,存进去后主要就是遍历执行 ManagerBase 的方法,泛型 T 对于“ManagerBase”也没有什么用,只为了传给“MySingletonBase”。
怎么才能正常存 List 并遍历执行 ManagerBase 的方法?
using System.Collections; using System.Collections.Generic; using UnityEngine; public class MySingletonBase <T> : MonoBehaviour where T : MonoBehaviour { private static T instance; public static T Instance { get { return instance; } } void Awake() { instance = this as T; } }
using System; using System.Collections; using System.Collections.Generic; using Net; using UnityEngine; public abstract class ManagerBase<T> : MySingletonBase<T> where T : MonoBehaviour { public List<MonoBase> MOnos= new List<MonoBase>(); public void Register(MonoBase monoBase) { if (!Monos.Contains(monoBase)) { Monos.Add(monoBase); } } .... }
using System; using System.Collections; using System.Collections.Generic; using Net; using UnityEngine; public class UIManager : ManagerBase<UIManager> { protected override byte GetMessageType() { return MessageType.Type_Acount; } }
]]>控件名:Wheel
作 者:WPFDevelopersOrg - 俞宏伟
.NET6
;Visual Studio 2022
;Canvas
作为容器控件,DrawingContext
上绘制水平线。1 )创建 Wheel.xaml
代码如下:
<UserControl x:Class="TopControl.Wheel" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:local="clr-namespace:TopControl" mc:Ignorable="d" Width="30" Height="180"> <Grid> <!-- 进度 --> <Grid Width="2" Background="#0a0a0a" Height="180" HorizOntalAlignment="Left" VerticalAlignment="Bottom"/> <Grid Width="2" x:Name="Grid_Value" Height="0" HorizOntalAlignment="Left" VerticalAlignment="Bottom"> <Grid Height="180" VerticalAlignment="Bottom"> <Grid.Background> <LinearGradientBrush StartPoint="0,0" EndPoint="0,1"> <GradientStop Offset="0" Color="#f0d967"/> <GradientStop Offset="1" Color="#33b08d"/> </LinearGradientBrush> </Grid.Background> </Grid> </Grid> <Grid Background="#0a0a0a" Width="26" HorizOntalAlignment="Right" Height="180" Margin="2,0,0,0"/> <!-- 滚轮 --> <Grid x:Name="WheelArea" Height="176" Width="22" HorizOntalAlignment="Right" Margin="0,0,2,0" MouseDown="WheelArea_MouseDown" MouseMove="WheelArea_MouseMove" MouseUp="WheelArea_MouseUp" MouseWheel="WheelArea_MouseWheel"> <Grid.Background> <LinearGradientBrush StartPoint="0,0" EndPoint="0,1"> <GradientStop Color="#141414" Offset="0"/> <GradientStop Color="#3c3c3c" Offset="0.5"/> <GradientStop Color="#141414" Offset="1"/> </LinearGradientBrush> </Grid.Background> <Grid x:Name="LayerBox" IsHitTestVisible="False"/> </Grid> </Grid> </UserControl>
2 )创建 Wheel.xaml.cs
代码如下:
using System.Windows; using System.Windows.Controls; using System.Windows.Input; namespace TopControl { public partial class Wheel : UserControl { public Wheel() { InitializeComponent(); Loaded += Wheel_Loaded; } #region 属性 public int MinValue { get; set; } = -720; public int MaxValue { get; set; } = 720; public int Value { get; set; } = -720; #endregion #region 控件事件 private void Wheel_Loaded(object sender, RoutedEventArgs e) { InitLayer(); } private void WheelArea_MouseDown(object sender, MouseButtonEventArgs e) { if (e.ChangedButton == MouseButton.Left) { BeginDrag(); } } private void WheelArea_MouseMove(object sender, MouseEventArgs e) { if (_dragMode) { Drag(); } } private void WheelArea_MouseUp(object sender, MouseButtonEventArgs e) { if (e.ChangedButton == MouseButton.Left && _dragMode) { EndDrag(); } } private void WheelArea_MouseWheel(object sender, MouseWheelEventArgs e) { if (_dragMode) return; int offset = e.Delta / 120; if (offset < 0 && Value > MinValue) { Value += offset; UpdateProgress(); _wheelLayer.AngleOffset -= offset * _wheelSpeed; _wheelLayer.UpdateLayer(); } else if (offset > 0 && Value < MaxValue) { Value += offset; UpdateProgress(); _wheelLayer.AngleOffset -= offset * _wheelSpeed; _wheelLayer.UpdateLayer(); } } #endregion #region 鼠标操作 private void BeginDrag() { _dragMode = true; WheelArea.CaptureMouse(); _dragStart = Mouse.GetPosition(WheelArea); _angleStart = _wheelLayer.AngleOffset; _valueStart = Value; _offsetDown = Value - MinValue; _offsetUp = Value - MaxValue; } private void Drag() { double offset_y = Mouse.GetPosition(WheelArea).Y - _dragStart.Y; if (offset_y < _offsetUp) offset_y = _offsetUp; else if (offset_y > _offsetDown) offset_y = _offsetDown; double offset_angle = offset_y * _wheelSpeed; Value = _valueStart - (int)offset_y; _wheelLayer.AngleOffset = _angleStart + offset_angle; UpdateProgress(); _wheelLayer.UpdateLayer(); } private void EndDrag() { _dragMode = false; WheelArea.ReleaseMouseCapture(); } #endregion #region 私有方法 /// <summary> /// 初始化图层 /// </summary> private void InitLayer() { _wheelLayer.Width = LayerBox.ActualWidth; _wheelLayer.Height = LayerBox.ActualHeight; LayerBox.Children.Add(_wheelLayer); _wheelLayer.Init(); _wheelLayer.UpdateLayer(); } /// <summary> /// 更新进度 /// </summary> private void UpdateProgress() { Grid_Value.Height = (double)(Value - MinValue) / (MaxValue - MinValue) * 180; } #endregion #region 字段 private readonly WheelLayer _wheelLayer = new WheelLayer(); private Point _dragStart = new Point(); private double _angleStart = 0; private int _valueStart = 0; private bool _dragMode = false; /// <summary>滚轮速度</summary> private readonly double _wheelSpeed = 0.7; /// <summary>最大向上偏移</summary> private double _offsetUp; /// <summary>最大向下偏移</summary> private double _offsetDown; #endregion } }
3 )创建 WheelLayer.cs
代码如下:
using MathUtil; using System; using System.Collections.Generic; using System.Runtime.CompilerServices; using System.Windows; using System.Windows.Media; using WpfUtil; namespace TopControl { public class WheelLayer : SingleLayer { #region 属性 /// <summary>槽高度:180px - 上下边框( 4px )</summary> public int GrooveHeight { get; set; } = 176; /// <summary>角度:圆弧切线与槽边的夹角</summary> public int Angle { get; set; } = 90; /// <summary>刻度线数量</summary> public int LineCount { get; set; } = 90; /// <summary>角度偏移</summary> public double AngleOffset { get; set; } = 0; #endregion #region 公开方法 public override void Init() { // 起点、终点、中点 Point2D startPoint = new Point2D(0, 0); Point2D endPoint = new Point2D(GrooveHeight, 0); Point2D centerPoint = startPoint.CenterWith(endPoint); // 向量:中点 -> 起点 Vector2 centerToStart = new Vector2(centerPoint, startPoint); centerToStart.Rotate(-90); // 向量:终点 -> 中点 Vector2 endToCenter = new Vector2(endPoint, centerPoint); endToCenter.Rotate(-90 + Angle); // 圆心 _circleCenter = centerToStart.IntersectionWith(endToCenter); // 向量:圆心 -> 起点 Vector2 vector = new Vector2(_circleCenter, startPoint); _radius = vector.Distance; _anglePerLine = 360.0 / LineCount; } protected override void OnUpdate() { // 最高点 Point2D top = new Point2D(_circleCenter.X, _circleCenter.Y - _radius); // 向量:圆心 -> 最高点 Vector2 vector = new Vector2(_circleCenter, top); double max = Math.Abs(vector.Target.Y); // 偏移角度 vector.Rotate(AngleOffset); // 开始旋转计算刻度位置 List<Point2D> pointList = new List<Point2D>(); for (int counter = 0; counter < LineCount; counter++) { if (vector.Target.Y < 0) pointList.Add(vector.Target); vector.Rotate(-_anglePerLine); } // 绘制刻度线 foreach (var item in pointList) DrawHorizontalLine(item.X, Math.Abs(item.Y) / max); } #endregion #region 私有方法 /// <summary> /// 绘制水平线 /// </summary> [MethodImpl(MethodImplOptions.AggressiveInlining)] private void DrawHorizontalLine(double y, double opacity) { Pen pen = new Pen(new SolidColorBrush(Color.FromArgb((byte)(opacity * 255), 32, 32, 32)), 1); Pen pen2 = new Pen(new SolidColorBrush(Color.FromArgb((byte)(opacity * 255), 64, 64, 64)), 1); _dc.DrawLine(pen, new Point(2, y - 0.5), new Point(Width - 2, y - 0.5)); _dc.DrawLine(pen2, new Point(2, y + 0.5), new Point(Width - 2, y + 0.5)); } #endregion #region 字段 /// <summary>圆心</summary> private Point2D _circleCenter = new Point2D(0, 0); /// <summary>半径</summary> private double _radius = 0; /// <summary>刻度线之间的夹角</summary> private double _anglePerLine = 0; #endregion } }
4 )创建 WheelExample.xaml
代码如下:
<wd:Window x:Class="TopControl.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:TopControl" xmlns:wd="https://github.com/WPFDevelopersOrg/WPFDevelopers" mc:Ignorable="d" Background="#1e1e1e" Title="https://github.com/WPFDevelopersOrg/SimulationControl - 俞宏伟" Height="450" Width="800"> <Grid> <local:Wheel HorizOntalAlignment="Left" VerticalAlignment="Top" Margin="50"/> </Grid> </wd:Window>
更多代码请访问GitHub
源码地址