关于wpf:Modbus协议与SerialPort端口读写

@[toc] 一、Modbus协定概念Modbus协定是MODICON(莫迪康)(现施耐德品牌)在1979年开发的,是寰球第一个真正用于现场的总线协定。Modbus协定是利用于电子控制器的一种通用语言。通过此协定,能够实现控制器相互之间、控制器经由网络和其余设施之间的通信。特点 规范凋谢、公开发表、无版税要求、无许可证费(没有费用)反对多种接口(RS232\RS422\RS485\RJ45);各种传输介质(双绞线,网线)格局简略、紧凑、通俗易懂,容易上手(好用)Modbus总线通信环境 根本通信从机编码 二、Modbus协定的分类分类 串口 RS485(一注多从):ModbusAscii【Ascii字符形式进行发送】、ModbusRTU以太网(点对点链接)ModbusTCP、ModbusUDPModbus协定下的数据存储 数据存储中的位、字节byte (8位)、字 word(2个字节,16位)、双字 word(4个字节 32位),C#中的数据显示:数据类型、显示格局内存分区与性能 存储区对象类型拜访类型存储区标识阐明可用性能码线圈状态单个bit读写0XXXX通过应用程序扭转这种类型数据01 05 15输出线圈单个bit只读1XXXXI/O零碎提供这种类型数据02输出寄存器16-位字只读3XXXXI/O零碎提供这种类型数据04放弃寄存器16-位字读写4XXXX通过应用程序扭转这种类型数据03 06 16操作存储区的命令 性能码:01、02、03、04、05、06、15、16 三、Modbus通信报文解读读寄存器音讯帧格局 TX:发送 RX:接管示例如下: 16进制 //01:读1号从站放弃型寄存器 //03:性能码 //00 00 :起始地址 (高下位)00 00 //00 0A :读取数量 (高下位)00 0A //C5 CD:CRC校验 Tx:000662-01 03 00 00 00 0A C5 CD Rx:000663-01 03 14 02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 DA 850x03 0x04 ...

June 8, 2022 · 7 min · jiezi

关于wpf:Jetbrains-Rider采用Java代码风格格式化C代码

去掉else、while、catch、finally关键词开启新的一行配置,菜单门路 File | Settings | Editor | Code Style | C#,在右侧界面中选中Line Break and Wrapping,去掉下图红框配置项的勾选切换到Braces Layout,更改C#类文件中所有代码块的格调为At end of line(K&R style),Save后失效原有代码依照批改后的配置从新格式化,Ctrl + Alt + L

November 22, 2021 · 1 min · jiezi

关于wpf:WPF自定义控件的三种方式

简介: 某些场景下,咱们的确须要创立新的控件。此时,了解 WPF不同控件的创立办法就显得十分重要。 WPF 提供3个用于创立控件的办法,每个办法都提供不同的灵便度。 WPF控件能够通过数据模型(DataTemplate)、款式(Style)、控件模板(ControlTemplate)和触发器(Trigger)等机制缩小创立新控件的须要。 然而,某些场景下,咱们的确须要创立新的控件。此时,了解 WPF不同控件的创立办法就显得十分重要。 WPF 提供3个用于创立控件的办法,每个办法都提供不同的灵便度,上面别离进行介绍。 1 基于UserControl 创立创立控件最简略一个办法就是基于UserControl 类进行继承。此时,咱们能够将WPF中现有组件增加到 UserControl 画布上来,并将各组件进行命名,这样能够在后盾进行组件拜访和应用事件处理程序。 UserControl 能够利用丰盛内容、款式和触发器的长处。 然而,继承自 UserControl的控件,将无奈应用 DataTemplate 或 ControlTemplate 来自定义UI外观。 2 基于Control 创立基于Control类创立自定义控件的办法 ,能够应用模板定义UI外观。而且能够将后盾逻辑和前端款式展示上进行拆散。 另外,这种办法创立的自定义控件,还反对应用命令和绑定来实现相干动作,实现相似事件的成果。最初,控件能够从新定义ControlTemplate和DataTemplate来自定义UI外观。控件反对不同的主题。 3 基于 FrameworkElement 创立一般来说,基于 UserControl 或 Control 创立的自定义控件即可实现业务需要,然而,在一些非凡状况下,简略的元素组合不能满足自定义控件的UI外观要求。此时,基于FrameworkElement 创立自定义控件是一个很好的抉择。 基于FrameworkElement创立控件,一方面能够通过重写的 OnRender 办法进行UI的间接绘制。 另一方面,能够通过自定义元素组合来可视化编写组件的外观。 4 依赖属性WPF 能够通过设置控件的属性来更改其外观和行为。其中的依赖属性能够让自定义控件执行以下操作: 在款式中设置该属性。将该属性绑定到数据源。应用动静资源作为该属性的值。对该属性进行动画解决。如果控件的属性反对以上任一性能,应将该属性实现为依赖属性。 上面给出一个微软官网文档的示例程序: /// <summary>/// Identifies the Value dependency property./// </summary>public static readonly DependencyProperty ValueProperty = DependencyProperty.Register( "Value", typeof(decimal), typeof(NumericUpDown), new FrameworkPropertyMetadata(MinValue, new PropertyChangedCallback(OnValueChanged), new CoerceValueCallback(CoerceValue)));/// <summary>/// Gets or sets the value assigned to the control./// </summary>public decimal Value{ get { return (decimal)GetValue(ValueProperty); } set { SetValue(ValueProperty, value); }}private static object CoerceValue(DependencyObject element, object value){ decimal newValue = (decimal)value; NumericUpDown control = (NumericUpDown)element; newValue = Math.Max(MinValue, Math.Min(MaxValue, newValue)); return newValue;}private static void OnValueChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args){ NumericUpDown control = (NumericUpDown)obj; RoutedPropertyChangedEventArgs<decimal> e = new RoutedPropertyChangedEventArgs<decimal>( (decimal)args.OldValue, (decimal)args.NewValue, ValueChangedEvent); control.OnValueChanged(e);}此示例代码来自官网https://docs.microsoft.com/zh... ,其中定义一个名为 ValueProperty的依赖属性(DependencyProperty ),通过调用DependencyProperty.Register向属性零碎注册属性名称Value,其中蕴含了三个外围信息: ...

September 17, 2021 · 1 min · jiezi

关于WPF:WPF-点击空白处隐藏View

本文介绍一种点击空白处使控件暗藏的实现办法。 问题形容思考如下场景,在白板类软件中,点击按钮弹出一个View,心愿在点击空白处间接暗藏掉View,同时能够间接书写,如下图: 实现该需要,能够通过View间通信解决,但这样会减少代码耦合且使逻辑显得简单。 本文通过派生UserControl,将解决逻辑封装在View外部,从而升高代码耦合度。 解决方案通过剖析需要能够想到,点击空白处时,该View会失去焦点,因而能够通过监听LostFocus事件来解决。 首先,须要设置Focusable属性为true,其默认值为false。而后监听LostFocus事件,当View失去焦点时,Visibility属性置为Collapsed。 此处有个问题,如果点击View外部的子控件,View会先LostFocus,而后立马GotFocus,通过测试距离在20ms内。因而还要响应下GotFocus事件,获取到焦点时,Visibility属性置为Visible。 另外,当点击按钮显示View时,此View并未获取焦点,因而须要监听IsVisibleChanged事件,当NewValue为true时,通过调用Focus使View获取焦点。 还须要解决一个问题。如上文动图所示,需点击按钮显示,再次点击按钮暗藏。但再次点击按钮时,View曾经失去了焦点,此时已暗藏,所以再次点击会导致View暗藏后立马显示。通过测试统计,点击按钮执行命令,到View响应命令执行显示/暗藏,工夫在(50,200)ms范畴内。因而如果在该范畴内View先暗藏后显示,需将其Visibility置为Collapsed。 至此,逻辑根本解决完了,然而还有一个坑。如果应用bool值绑定Visibility(Mode需设置为TwoWay),点击按钮批改bool时,PropertyChanged事件会告诉监听者属性扭转,此时由上个步骤中的逻辑晓得,咱们须要批改Visibility的值,这实践上又会导致bool值的扭转,但bool值并未批改(属性未修改完再次批改),这就导致Visibility与bool值不统一,再次点击按钮不会显示View。咱们只须要异步执行上个步骤,就能够解决。 通过上述解决,点击空白处暗藏View的逻辑就封装到View外面了,外围代码如下所示,感兴趣的能够下载残缺demo试试。如果有其它好的办法,欢送交换(WPF或开源库或者有更好的解决方案)。 // 派生UserControlpublic class MyAutoHideControl : UserControl{ public MyAutoHideControl() : base() { Focusable = true; _lastTimeCollapsed = DateTime.Now.Ticks / 10000; IsVisibleChanged += AutoHideControl_IsVisibleChanged; GotFocus += AutoHideControl_GotFocus; LostFocus += AutoHideControl_LostFocus; } private void AutoHideControl_GotFocus(object sender, RoutedEventArgs e) { if (Visibility != Visibility.Visible) Visibility = Visibility.Visible; } private void AutoHideControl_LostFocus(object sender, RoutedEventArgs e) { if (Visibility == Visibility.Visible) Visibility = Visibility.Collapsed; } private void AutoHideControl_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e) { if ((bool)e.NewValue == (bool)e.OldValue) return; if ((bool)e.NewValue) { long interval = DateTime.Now.Ticks / 10000 - _lastTimeCollapsed; if (interval > MinInterval && interval < MaxInterval) { if (Visibility == Visibility.Visible) { Dispatcher.BeginInvoke(new Action(() => { Visibility = Visibility.Collapsed; })); } } else Focus(); } else _lastTimeCollapsed = DateTime.Now.Ticks / 10000; } private long _lastTimeCollapsed; // 需解决再次点击按钮暗藏的状况 private const long MinInterval = 50; private const long MaxInterval = 200;}// View<Window ... xmlns:c="clr-namespace:CalcBinding;assembly=CalcBinding" xmlns:local="clr-namespace:AutoHideControl" Title="AutoHideControl" Height="200" Width="350"> <Window.Resources> <BooleanToVisibilityConverter x:Key="BooleanToVisibility"/> </Window.Resources> <Grid> <InkCanvas Background="LightCyan"/> <DockPanel VerticalAlignment="Bottom" Margin="10" Height="Auto"> <local:MyAutoHideView DockPanel.Dock="Top" Width="150" Height="50" Margin="10" Visibility="{Binding ShowView,Converter={StaticResource BooleanToVisibility},Mode=TwoWay}"/> <Button Width="80" Height="30" Command="{Binding ButtonClickedCommand}" Content="{c:Binding ShowView ? \'Hide\' : \'Show\'}"/> </DockPanel> </Grid></Window>// ViewModelpublic class MainWindowViewModel : INotifyPropertyChanged{ public bool ShowView { get => _showView; set { _showView = value; OnPropertyChanged(); } } public DelegateCommand ButtonClickedCommand => _buttonClickedCommand ?? (_buttonClickedCommand = new DelegateCommand { ExecuteAction = (_)=> ShowView = !_showView }); public void OnPropertyChanged([CallerMemberName] string name = "")=> PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name)); public event PropertyChangedEventHandler PropertyChanged; private bool _showView;

June 25, 2021 · 2 min · jiezi

关于WPF:WPF-PasswordBox数据绑定方法

本文介绍下PasswordBox进行数据绑定的办法,本文参考链接。 本文残缺示例程序见GitHub。 问题形容PasswordBox的Password属性不是依赖属性,因而无奈进行数据绑定。 解决办法该问题的解决办法有多种,本文介绍如何通过增加附加属性解决该问题。 附加属性是说一个属性本不属于某个对象,但因为某种需要附加到该对象上,通过附加属性能够实现将属性与宿主解耦的目标。附加属性实质上就是依赖属性,只是它们在属性包装器和注册时有区别。注册附加属性应用RegisterAttached办法,注册依赖属性应用Register办法,这两个办法的参数差异并不大。 首先增加一个PasswordBoxBindingHelper类,该类蕴含一个附加属性(snippet:propa+两次tab),通过设置该属性的PropertyChangedCallback将扭转告诉到PasswordBox.Password,并通过增加对PasswordBox.PasswordChanged事件的响应来响应PasswordBox.Password的扭转。有了该附加属性,即可进行数据绑定。 public static string GetPasswordContent(DependencyObject obj) => (string)obj.GetValue(PasswordContentProperty);public static void SetPasswordContent(DependencyObject obj, string value) => obj.SetValue(PasswordContentProperty, value);public static readonly DependencyProperty PasswordContentProperty = DependencyProperty.RegisterAttached("PasswordContent", typeof(string), typeof(PasswordBoxBindingHelper), new PropertyMetadata(string.Empty, OnPasswordContentPropertyChanged));private static void OnPasswordContentPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e){ var box = d as PasswordBox; box.PasswordChanged -= OnPasswordChanged; var password = (string)e.NewValue; if (box != null && box.Password != password) box.Password = password; box.PasswordChanged += OnPasswordChanged;}private static void OnPasswordChanged(object sender, RoutedEventArgs e){ var box = sender as PasswordBox; SetPasswordContent(box, box.Password);}而后在View中应用该附加属性进行数据绑定,本文示例中主窗口蕴含一个PasswordBox控件及一个Button按钮: ...

June 22, 2021 · 2 min · jiezi

关于WPF:WPF-窗口裁剪投影效果

在Windows窗口利用开发过程中,常常会设计一些非矩形窗口,并蕴含一些投影成果,本文介绍一种实现窗口投影+裁剪成果的办法。 本文裁剪成果参考刘铁猛老师《深入浅出WPF》一书第十二章:绘图和动画,裁剪米老鼠形状窗口,区别在于给窗口增加投影成果。 窗口裁剪WPF中能够不便的设计各种不规则形态的窗口或控件,应用Clip属性即可,Clip属性的数据类型是Geometry类型,能够应用门路标记语法设置其值。如下示例所示,该示例将窗口轮廓裁剪为米老鼠款式 留神:若要裁剪窗口,需将AllowsTransparency设置为True,WindowStyle设置为None。 <Window ... Title="MickeyWindow" Height="250" Width="300" WindowStyle="None" AllowsTransparency="True" ResizeMode="NoResize" Background="Gray"> <Window.Clip> <PathGeometry Figures="M 55,100 A 50,50 0 1 1 100,60 A 110,95 0 0 1 200,60 A 50,50 0 1 1 250,100 A 110,95 0 1 1 55,100 Z"/> </Window.Clip> <Grid> ... </Grid></Window>成果如下图: 窗口投影投影成果能够通过设置BitmapEffect属性或Effect属性实现,倡议应用Effect属性。BitmapEffect已标记为Obsolete,它应用CPU计算,会影响程序性能。Effect应用GPU运算,缩小了对CPU资源的节约。 Effect为抽象类,通过派生能够实现各种成果。WPF官网仅提供了含糊成果(BlurEffect)与投影成果(DropShadowEffect),其它自定义成果可通过派生ShaderEffect实现。本文应用DropShadowEffect实现投影成果。 投影成果无奈间接利用于Window,能够为Window的外部元素增加投影成果,并须要设置其Margin属性,Window的AllowsTransparency需设置为True。 DropShadowEffect中有几个要害属性,Color属性设置投影色彩,BlurRadius属性设置含糊成果半径,ShadowDepth属性设置投影距元素的间隔,Opacity属性设置投影的不透明度,Direction属性设置投影方向。 本文实现晕影成果,将ShadowDepth置为0即可,无需设置Direction。 <Window ... Title="MickeyWindow" Height="250" Width="300" WindowStyle="None" AllowsTransparency="True" ResizeMode="NoResize" Background="Transparent"> <Grid> <Border Margin="15" BorderBrush="Gray" BorderThickness="2"> <Border.Effect> <DropShadowEffect Color="Black" BlurRadius="15" ShadowDepth="0"/> </Border.Effect> </Border> </Grid></Window>成果如下图: 合并裁剪与投影成果投影成果增加到了窗口外部Border元素上,因而须要调整Clip属性。间接将Clip也利用到Border上是不行的,须要将其利用到子元素上。 <Grid> <Border Margin="15"> <Border.Effect> <DropShadowEffect Color="Black" BlurRadius="15" ShadowDepth="0"/> </Border.Effect> <Grid Background="lightgray"> <Grid.Clip> <PathGeometry Figures="M 55,100 A 50,50 0 1 1 100,60 A 110,95 0 0 1 200,60 A 50,50 0 1 1 250,100 A 110,95 0 1 1 55,100 Z"/> </Grid.Clip> </Grid> </Border></Grid>成果如下图: ...

June 1, 2021 · 1 min · jiezi

关于WPF:WPF-Genericxaml文件报错

本文记录下创立自定义管制时碰到的一个小问题。 问题在Generic.xaml文件中写好自定义控件的DefaultStyle后进行编译,VS报错。 把报错地位的内容全副正文掉后,从新编译,仍然报错。 查看错误信息:“给定编码中的字符有效...”,找到谬误定位的地位后,发现此处有中文。应用编辑器关上Generic.xaml文件,查看编码格局,原来默认生成的文件编码格局是ANSI。 解决办法起因分明后就很好解决了,应用编辑器将文件格式转换为UTF-8即可,从新编辑胜利。 Generic.xaml资源文件在WPF我的项目中,首次创立自定义控件,VS会默认生成一个Themes文件夹,并在其中创立一个Generic.xaml文件,该文件用来寄存以后程序集中自定义控件的默认款式,WPF框架会找到它并应用其中的自定义控件的默认款式。 程序集的AssemblyInfo.cs指定了资源文件的地位,ResourceDictionaryLocation.None示意不指定零碎格调的主题,这样在不同的零碎下控件格调是统一的。ResourceDictionaryLocation.SourceAssembly示意资源文件在程序集内,WPF会找到Themes文件夹下的Generic.xaml文件,将其中自定义控件的默认格调利用到对应的控件上。 [assembly: System.Windows.ThemeInfo(System.Windows.ResourceDictionaryLocation.None, System.Windows.ResourceDictionaryLocation.SourceAssembly)]

May 28, 2021 · 1 min · jiezi

关于WPF:Win32Api-回到Windows桌面

本文分享下回到桌面性能的实现办法,成果与快捷键(Win+D)雷同。 实现办法Windows回到桌面性能的实现形式有多种,能够模仿快捷键,也能够执行如下办法。其中办法一须要援用Shell32.dll,办法为增加援用,抉择COM找到"Microsoft Shell Controls and Automation",选中并确认,还须要将其嵌入互操作类型置为false。 // 办法一,[参考链接](https://stackoverflow.com/questions/41598951/programmatically-show-the-desktop)Shell32.ShellClass objShel = new Shell32.ShellClass();objShel.ToggleDesktop();// 办法二,[参考链接](https://social.msdn.microsoft.com/Forums/vstudio/en-US/a27ca1e4-bd02-434b-8d02-06553c35f3d5/show-desktop-program-no-working)Type shellType = Type.GetTypeFromProgID("shell.application");object shell = Activator.CreateInstance(shellType);shellType.InvokeMember("ToggleDesktop", BindingFlags.InvokeMethod, null, shell, new object[] { });问题失常状况下,这两个办法都能够胜利执行。 然而,明天碰到一台设施操作未胜利。场景是WPF利用收到udp音讯时,执行回到桌面操作失败。 看到有网友说执行上述代码时,需在STA thread中执行,否则会报错。办法一是须要在STA thread中执行的,然而并不能解决该问题。 再次剖析问题时发现,当WPF利用为以后流动窗口时,操作执行胜利,否则执行失败。因而,先激活窗口,再执行上述代码就能够胜利解决该问题了。 在出问题的设施上,应用简略的Show()、Active()办法激活窗口是不行的,只会在任务栏闪动图标,应用大佬提供的激活窗口的办法能够胜利激活。 该问题的难点在于并不是所有设施都存在该问题,我手中有两台设施,操作系统是一样的,但一台是好的,一台是不行的。出问题的设施代码是执行了的,不晓得为什么没有成果,必须将利用置为流动窗口才行,有理解该问题的小伙伴欢送探讨。 本文测试demo的局部代码如下,具体可见Github。 // Wpf主窗口public partial class MainWindow : Window{ public MainWindow() { InitializeComponent(); InitLogger(); InitUdpThread(); showDesktop = Method1; Logger.LogMessage(Severity.Info, $"start process, Main Thread id: {Thread.CurrentThread.ManagedThreadId}"); } private void InitLogger() { var file = new FileLogger("log.txt"); Logger.LogMessage(Severity.Info, "Init logger success"); } private void InitUdpThread() { Thread udpThread = new Thread(new ThreadStart(GetUdpMessage)); udpThread.IsBackground = true; udpThread.Start(); } private void GetUdpMessage() { UdpClient udpClient = null; try { udpClient = new UdpClient(10001); } catch (Exception) { Logger.LogMessage(Severity.Error, "create udp client failed"); return; } Logger.LogMessage(Severity.Info, "create udp client success"); IPEndPoint remotePoint = null; while (true) { try { byte[] receiveData = udpClient.Receive(ref remotePoint); string receiveString = Encoding.Default.GetString(receiveData); Logger.LogMessage(Severity.Info, $"receive udp message: {receiveString}"); if (receiveString.ToLower().Contains("showdesktop")) showDesktop?.Invoke(); } catch (Exception e) { Logger.LogMessage(Severity.Error, e.Message); } } } private void Button_Click(object sender, RoutedEventArgs e) { if (sender is Button btn) { switch (btn.Name) { case "method1": showDesktop = Method1; Logger.LogMessage(Severity.Info, "turn to method1"); break; case "method2": showDesktop = Method2; Logger.LogMessage(Severity.Info, "turn to method2"); break; case "activeFirst": showDesktop = ActiveFirst; Logger.LogMessage(Severity.Info, "turn to activeFirst method"); break; default: break; } } } private void Method1() { Thread newSta = new Thread(()=> { Shell32.ShellClass objShel = new Shell32.ShellClass(); objShel.ToggleDesktop(); Logger.LogMessage(Severity.Info, $"Current Thread id: {Thread.CurrentThread.ManagedThreadId}"); }); newSta.TrySetApartmentState(ApartmentState.STA); newSta.Start(); } private void Method2() { Type shellType = Type.GetTypeFromProgID("Shell.Application"); object shellObject = System.Activator.CreateInstance(shellType); shellType.InvokeMember("ToggleDesktop", System.Reflection.BindingFlags.InvokeMethod, null, shellObject, null); Logger.LogMessage(Severity.Info, $"Current Thread id: {Thread.CurrentThread.ManagedThreadId}"); } private void ActiveFirst() { App.Current.Dispatcher.Invoke(new Action(() => { Win32Api.SetWindowToForegroundWithAttachThreadInput(this); Method2(); })); } private Action showDesktop;}

May 25, 2021 · 2 min · jiezi

关于WPF:WPF-应用启动慢问题

明天碰到一个奇怪的景象,在某些机器上,进行了系统还原后,WPF利用关上较慢,约有35s。 因为设施调试不不便且焦急发版,没有剖析根本原因,尝试了如下两个计划都是能够的。本文先记录下该问题的解决方案,利用启动性能官网文档中有阐明,还有搜到的其它计划没来得及测试,如NGEN update 计划一,更改启动项出问题利用的启动项是应用的默认设置,查看App.g.cs文件,能够看到主动生成的Main入口函数,如下: [System.STAThreadAttribute()][System.Diagnostics.DebuggerNonUserCodeAttribute()][System.CodeDom.Compiler.GeneratedCodeAttribute("PresentationBuildTasks", "4.0.0.0")]public static void Main(){ WpfApp1.App app = new WpfApp1.App(); app.InitializeComponent(); app.Run();}新建一个StartUp文件,将我的项目启动项批改为WpfApp1.StartUp,这样就能够解决该问题,代码如下。与原始计划比照,该计划应用了WindowsFormsApplicationBase,该计划为什么能够解决启动慢的问题,我还没搞清楚,或者和计划二无关。 // StartUp.csclass StartUp : Application{ [STAThread] public static void Main(string[] args) { var startUp = new MyStartUp(); startUp.Run(args); }}// 须要增加对Microsoft.VisualBasic的援用class MyStartUp : WindowsFormsApplicationBase{ protected override bool OnStartup(StartupEventArgs eventArgs) { App app = new App(); app.Run(); return false; }}// App.xaml.cs 删除App.xaml中的StartupUri="MainWindow.xaml"public partial class App : Application{ public App() { var win = new MainWindow(); win.Show(); }}计划二,禁用查看应用程序的CAS发布者策略在config文件中增加如下配置项。generatePublisherEvidence?redirectedfrom=MSDN)指定运行时是否为CAS创立发布者证据,其默认值为true,即创立发布者证据,这样可能会导致超时和服务启动提早。因而将其置为false,该办法也能够解决启动慢的问题。 ...

May 21, 2021 · 1 min · jiezi

关于WPF:WPF-使用当前进程打开自定义文件的一种方式

问题形容当双击关上自定义格局的文件时,心愿应用以后正在运行的过程,而不是另起一个过程。 本文介绍一种形式解决如上问题,计划参考user3582780的解答 设置自定义文件格式的默认打开方式参考链接,具体步骤如下: 在HKEY_CLASSES_ROOT中新建项,命名为自定义文件格式(如.custom),设置其默认值(如mycustom);在HKEY_CLASSES_ROOT中新建项,命名为步骤1中的默认值,即mycustom;在mycustom中新建项,命名为DefaultIcon,设置默认值(Icon门路);在mycustom中新建项,命名为shell,在shell中持续新建项open,在open中新建项command,设置其默认值(格局:程序门路 "%1")应用以后实例关上文件首先,当双击自定义格式文件进行关上时,会将该文件的门路作为参数传递给程序,因而关上程序应响应启动参数。 在WPF应用程序中,Application的OnStartup办法会携带程序的启动参数(通过Environment也可获取启动参数)。 当双击自定义格式文件时,若有一个实例正在运行,并不会间接应用该实例关上文件,而是会从新关上一个实例。此时须要将新实例的启动参数传递给以后实例并敞开新实例。 本文应用发送窗口音讯的形式解决该问题,即应用Win32的SendMessage接口发送参数给以后实例窗口,以后实例响应音讯解决即可。具体实现计划如下: // Appprivate static Mutex mutex;protected override void OnStartup(StartupEventArgs e){ mutex = new Mutex(true, "myapp", out bool ret); if(!ret) Reopen(e); // ...}private void Reopen(StartupEventArgs e){ // IntPtr hwnd = FindWindow(null, "window title"); if(e.Args.Length > 0) SendMessage(); Environment.Exit(0);}private void SendMessage(IntPtr hwnd, string data){ CopyDataStruct cds = new CopyDataStruct(); try { cds.cbData = (data.Length + 1) * 2; // number of bytes cds.lpData = Win32.LocalAlloc(0x40, cds.cbData); // known local-pointer in RAM Marshal.Copy(data.ToCharArray(), 0, cds.lpData, data.Length); // Copy data to preserved local-pointer cds.dwData = (IntPtr)1; SendMessage(hwnd, WM_COPYDATA, IntPtr.Zero, ref cds); } finally { cds.Dispose(); }}// Windowprivate IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled){ if(msg == WM_COPYDATA) { CopyDataStruct st = (CopyDataStruct)Marshal.PtrToStructure(lParam, typeof(CopyDataStruct)); string strData = Marshal.PtrToStringUni(st.lpData); OpenFile(strData); Activate(); } return IntPtr.Zero;}

April 14, 2021 · 1 min · jiezi

关于WPF:WPF-使用Blend工具绘制Control样式

本文通过设计一个RadioButton,分享下应用Blend绘制Path的办法。待绘制的RadioButton款式如下文所示,如有更好的办法实现该款式,欢送交换。 实现成果将要实现的RadioButton款式如下图,能够看出按钮的笔尖和笔身的填充色,以及选中时右上方圆形的填充色统一,代表笔的色彩。 实现形式笔身应用矩形,填充色绑定按钮背景色;笔头局部应用闭合的Path,其中笔尖的色彩同样绑定按钮背景色;右上方的圆形应用Ellipse,填充色同样绑定按钮背景色。 实现步骤关上Blend,新建一个WPF我的项目;选中MainWindow的Grid,点击资产按钮,找到RadioButton并选中,在Grid中拖动增加按钮,如下图所示: 找到属性中的Width/Height属性,批改为适合的值;点击缩放按钮,弹出的列表框中选中"适宜选定内容",以不便编辑;选中该RadioButton,右键抉择编辑模板-编辑正本,弹出的对话框应用适合的形式创立资源(本文采纳默认),设置完后点击确定;删除templateRoot中的所有内容,只保留根Grid;此时会报错,先将xaml中的所有Trigger正文掉即可;点击矩形按钮,拖动增加矩形;属性框中调整相干属性,如下图所示: 右键矩形按钮,抉择线,增加一条直线,调整其属性,如下图: 选中笔按钮,第一点增加在矩形左上角,第二点长按增加在直线左端点,长按拖动鼠标可调整曲线形态;同样的办法增加右侧的Path,如下图所示: 点击门路抉择按钮,应用键盘方向键及鼠标对Path上的点进行微调,如下图; 选中直线及两条曲线,右键门路,生成复合门路,连贯两点使Path闭合;抉择pen按钮,增加笔尖曲线,如下图: 右键矩形按钮,抉择椭圆形,在右上角增加一个椭圆,调整其属性,使Width=Height;为矩形、圆形、笔尖Path设置填充色,即Fill属性,右键Fill属性右侧的方框,抉择创立数据绑定,将其绑定到RadioButton的Background属性,圆形和笔尖同理。切换到RadioButton,批改其Background属性,能够看到矩形背景色随之变动,如下图; 选中笔头局部Path,选中其Fill属性,抉择突变画笔,调整属性值进行突变填充;切换到xaml,调整主动生成的代码,比方将Path门路中的坐标准确到小数点后一位。这样自定义的RadioButton按钮款式就实现了,应用时能够再依据需要微调。// 最终Style<Style x:Key="RadioButtonStyle1" TargetType="{x:Type RadioButton}"> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type RadioButton}"> <Grid x:Name="templateRoot" Background="Transparent" SnapsToDevicePixels="True"> <Rectangle Fill="{Binding Background, RelativeSource={RelativeSource TemplatedParent}}" HorizontalAlignment="Center" Height="37" Stroke="Black" VerticalAlignment="Bottom" Width="23.5" Margin="13,0"/> <Path Data="M16.4,0.76 L7.4,0.76 M7.7,0.7 C2,12.87 0.5,24.1 0.5,24.1 0.5,24.1 23.1,23.8 23.1,23.8 23.1,23.8 20.7,6.5 16,0.5" HorizontalAlignment="Center" Height="24.6" Stretch="Fill" Stroke="Black" VerticalAlignment="Top" Width="23.6" Margin="13,19.4,13,0"> <Path.Fill> <LinearGradientBrush EndPoint="0.5,0.5" MappingMode="RelativeToBoundingBox" StartPoint="0,0.5" SpreadMethod="Reflect"> <GradientStop Color="#FF626060"/> <GradientStop Color="#FFD6D3D3" Offset="0.873"/> </LinearGradientBrush> </Path.Fill> </Path> <Path Data="M21.1,19.3 C21.1,19.3 25.3,-5.5 28.2,19.2" Fill="{Binding Background, RelativeSource={RelativeSource TemplatedParent}}" HorizontalAlignment="Left" Height="12" Margin="21.2,8.3,0,0" Stretch="Fill" Stroke="Black" VerticalAlignment="Top" Width="8"/> <Ellipse Fill="{Binding Background, RelativeSource={RelativeSource TemplatedParent}}" HorizontalAlignment="Right" Height="3" Stroke="Black" VerticalAlignment="Top" Width="3" Margin="0,3,3,0" StrokeThickness="0"/> </Grid> </ControlTemplate> </Setter.Value> </Setter></Style>Blend绘制Path应用Blend绘制Path的办法参考官网。 绘制PathPath由一系列的直线或曲线连贯而成,能够应用Line、Pen、Pencil工具绘制Path,能够在工具条中找到它们。 绘制直线应用Pen工具:点击定义直线起始点,再次点击定义直线起点;应用Line工具:拖动增加直线,在直线起点地位开释;绘制曲线应用Pen工具,点击增加曲线终点,再次点击并拖动能够增加点并调整两点间的曲线形态。若想闭合Path,点击终点即可。 扭转曲线形态应用门路抉择工具,选中形态,拖动曲线上的点以扭转形态。 移除Path上的线段应用门路抉择工具,选中Path上要删除的线段,点击删除按钮。 移除Path上的点应用抉择工具选中Path,应用Pen工具点击Path上的点即可删除。 Path增加点应用抉择工具选中Path,应用Pen工具在想要增加点的地位点击。 绘制自在的形态应用Pencil工具进行绘制。

March 1, 2021 · 1 min · jiezi

关于WPF:Prism-简介

Prism是一个开源框架,用于在WPF、Xamarin Forms、Uno/Win UI等利用中创立松耦合、可保护、可测试的XAML应用程序。Prism提供了一组设计模式的实现,这些设计模式有助于编写构造良好且可保护的XAML应用程序,包含MVVM,dependency injection,commands,EventAggregator等。 Prism最后属于微软,起初该团队成员来到微软独立起来,但微软官网仍保留着Prism的文档只是不再更新。原来的Prism框架比拟臃肿,2020年公布了8.0版本,已进行了很多改善。微软官网Prism文档很长,而且内容较老,如果想学习Prism框架,倡议间接去GitHub,能够联合Prism-Documentation及Prism-Samples-Wpf一起看。 另外,Prism的核心成员Brian Lagunas和Dan Siegel在YouTube/Twitch平台上公布了一些视频及直播,如Brian Lagunas在一年前进行了Prism.Outlook的直播开发,该系列视频共11集,每粗放两小时,有条件的能够进行观看。 Brian Lagunas是Prism的作者,也是Microsoft MVP/Xamarin MVP/Microsoft P&P Champion,领有多年开发教训。通过看视频既能学习Prism框架,又能学习作者的一些开发理念及技巧,同时还能练习下英语听力,一举三得。 Prism提供了Visual Studio的Prism Template Pack插件,应用该插件能够疾速的创立Prism利用及Prism模块。

February 21, 2021 · 1 min · jiezi

关于WPF:PrismWPF-Prism框架使用下

本文参考Prism官网示例 命令应用Prism提供了两种命令:DelegateCommand和CompositeCommand。 DelegateCommandDelegateCommand封装了两个委托:Execute和CanExecute,应用如下: // view<Button Command="{Binding ExecuteDelegateCommand}" Content="DelegateCommand"/>// viewmodelpublic DelegateCommand ExecuteDelegateCommand { get; private set; }public MainWindowViewModel(){ ExecuteDelegateCommand = new DelegateCommand(Execute, CanExecute);}private void Execute(){ UpdateText = $"Updated: {DateTime.Now}";}private bool CanExecute(){ return IsEnabled;}CompositeCommandCompositeCommand为复合命令,由多个子命令形成。当调用CompositeCommand时,将顺次调用每个子命令。默认状况下,当所有子命令CanExecute均返回true时才会执行CompositeCommand。应用办法如下: // Project.Core中定义接口及实现public interface IApplicationCommands{ CompositeCommand SaveCommand { get; }}public class ApplicationCommands : IApplicationCommands{ private CompositeCommand _saveCommand = new CompositeCommand(); public CompositeCommand SaveCommand { get { return _saveCommand; } }}// App.xaml.cs中注册单例对象protected override void RegisterTypes(IContainerRegistry containerRegistry){ containerRegistry.RegisterSingleton< IApplicationCommands, ApplicationCommands>();}// viewmodel中增加子命令public TabViewModel(IApplicationCommands applicationCommands){ _applicationCommands = applicationCommands; UpdateCommand = new DelegateCommand(Update).ObservesCanExecute( () => CanUpdate); _applicationCommands.SaveCommand.RegisterCommand(UpdateCommand);}// view中执行命令(需在对应的viewmodel的构造函数中传入IApplicationCommands实例)<Button Content="Save" Command="{Binding ApplicationCommands.SaveCommand}"/>EventAggregatorEventAggregator是一种事件机制,解决了松耦合模块间的通信问题。应用办法如下: ...

February 20, 2021 · 3 min · jiezi

关于WPF:PrismWPF-Prism框架使用上

本文参考Prism官网示例 创立Prism我的项目将App.xaml中的WPF规范Application替换为PrismApplication,移除StartupUri属性;将App.xaml.cs中的基类改为PrismApplication;必须实现PrismApplication中的两个形象办法:RegisterTypes、CreateShell;RegisterTypes用来注册类型;CreateShell用来创立程序主窗口。Region应用在view xaml文件中应用prism:RegionManager.RegionName="SomeRegion"标记region;创立自定义RegionAdapter类,继承自RegionAdapterBase<T>,override Adapt和CreateRegion办法;在App.xaml.cs中通过override ConfigureRegionAdapterMappings办法注册自定义RegionAdapter,示例如下:protected override void ConfigureRegionAdapterMappings( RegionAdapterMappings regionAdapterMappings){ base.ConfigureRegionAdapterMappings(regionAdapterMappings); regionAdapterMappings.RegisterMapping( typeof(StackPanel), Container.Resolve<StackPanelRegionAdapter>());}View注入Region有两种办法,第一种称为View Discovery,该办法实用于当region加载时就把视图注入到region场景;另外一种办法称为View Injection,该办法实用于当激发某一事件后view注入到region场景。 View Discovery通过如下办法实现: regionManager.RegisterViewWithRegion("ContentRegion", typeof(ViewA));View Injection通过如下办法实现,并可通过IRegion的Activate与Deactivate接口实现view的使能: private void Button_Click(object sender, RoutedEventArgs e){ var view = _container.Resolve<ViewA>(); IRegion region = _regionManager.Regions["ContentRegion"]; region.Add(view);}private void Button_Click(object sender, RoutedEventArgs e){ //activate view a _region.Activate(_viewA);}private void Button_Click_1(object sender, RoutedEventArgs e){ //deactivate view a _region.Deactivate(_viewA);}增加视图模块增加我的项目,在我的项目中增加继承自IModule的类,实现OnInitialized与RegisterTypes办法。个别在OnInitialized中增加View Discovery代码以将该模块的相干View注入到Region中;在程序中增加模块。增加模块的形式很多,本文仅介绍应用代码的形式增加,办法如下:// App.xaml.csprotected override void ConfigureModuleCatalog(IModuleCatalog moduleCatalog){ moduleCatalog.AddModule<ModuleA.ModuleAModule>();}匹配ViewModels如果不批改命名规定,在xaml中为窗口/控件增加如下属性将主动匹配viewmodel: prism:ViewModelLocator.AutoWireViewModel="True"能够通过如下办法批改默认的viewmodel匹配规定,仍需在xaml中配置AutoWireViewModel: // App.xaml.csprotected override void ConfigureViewModelLocator(){ base.ConfigureViewModelLocator(); ViewModelLocationProvider.SetDefaultViewTypeToViewModelTypeResolver( (viewType) => { var viewName = viewType.FullName; var viewAssemblyName = viewType.GetTypeInfo().Assembly.FullName; var viewModelName = $"{viewName}ViewModel, {viewAssemblyName}"; return Type.GetType(viewModelName); });}若不想批改匹配规定,且viewmodel名称不匹配默认规定,可通过如下形式匹配,仍需在xaml中配置AutoWireViewModel: ...

February 19, 2021 · 1 min · jiezi

关于wpf:一种直线识别方案

本文介绍一种直线的辨认计划。 步骤应用最小二乘法回归直线:$$\begin{cases}\frac{\sum_{i=1}^N(x_i,\overline{x})(y_i,\overline{y})}{\sum_{i=1}^N(x_i,\overline{x})^2}\\b=\overline{y}-k\overline{x}\end{cases}$$ 失去直线方程y=kx+b后,计算所有点到直线的间隔,若在阈值范畴内,认为是直线。实现/// <summary>/// 最小二乘法求回归直线方程/// </summary>/// <param name="points">输出数据</param>/// <param name="k">直线斜率</param>/// <param name="b">直线截距</param>/// <param name="type">直线类型 1:水平线 2:垂直线 3:个别直线</param>/// <returns></returns>public static bool IsLine(List<Point> points, out double k, out double b, out int type){ k = 0; b = 0; type = 0; if (points.Count < 2) return false; double averageX = 0, averageY = 0, n = 0; n = points.Count; foreach (Point p in points) { averageX += p.X; averageY += p.Y; } averageX /= n; averageY /= n; double numerator = 0, denominator = 0; foreach (Point p in points) { numerator += (p.X - averageX) * (p.Y - averageY); denominator += (p.X - averageX) * (p.X - averageX); } if (numerator == 0) //平行于X轴为水平线,返回纵坐标平均值 { b = averageY; type = 1; } else if (denominator == 0)//平行于Y轴为垂直线,返回横坐标平均值 { b = averageX; type = 2; } else { type = 3; } k = numerator / denominator; b = averageY - k * averageX; foreach (Point p in points) { dis = GetPoint2LineDistance(p, k, b, type); if (dis > MAX_POINT_LINE_DIS) return false; //点到拟合直线间隔过大 } return true;}/// <summary>/// 计算点到直线的间隔/// </summary>/// <param name="p">待计算点</param>/// <param name="k">直线斜率</param>/// <param name="b">直线截距</param>/// <param name="type">直线类型 1:水平线 2:垂直线 3:个别直线</param>/// <returns>间隔</returns>private static double GetPoint2LineDistance(Point p, double k, double b, int type){ if (type == 1) { return Math.Abs(p.Y - b); } else if (type == 2) { return Math.Abs(p.X - b); } else { double numerator = 0, denominator = 0; numerator = Math.Abs(k * p.X - p.Y + b); denominator = Math.Sqrt(k * k + 1); return numerator / denominator; }}

January 16, 2021 · 2 min · jiezi

一个导出小工具

说明一个导出QQ群成员信息的工具使用双击QunExporter.exe,会打开https://qun.qq.com/页面(利用CEF项目),登录QQ账号,软件获取登录信息点击获取群列表按钮,之后即可导出群成员信息下载源码

April 1, 2019 · 1 min · jiezi

ArcFace2.0+红外双目摄像头的活体检测[Windows][C#][.NET][WPF]

废话不多说 直接上图 这个是demo中用到的双目摄像头,一个是红外的,一个是正常的rgb摄像头两个usb接口,在电脑上呈现两路摄像头通道程序检测RGB输出图像,当检测到有人脸时,用RGB人脸的位置到红外画面的位置去检测人脸如果没有检测到,说明当前目标为非活体当在红外画面检测到人脸时,说明当前目标为活体目标再继续使用RGB图像提取特征值下面为demo效果图DEMO源码地址:https://gitee.com/jch/FaceAliveDEMO中用的C#封装库为:https://github.com/Thxzzzzz/A…由于原库有BUG,所以demo中直接附加了修复了bug的源码

March 5, 2019 · 1 min · jiezi