程序媛日记
-
internal修饰的类?
internal也是一各类型/成员修饰符(被修饰的类型或者成员称为内部类型或成员),只是它所修饰的类只能在同一个程序集中被访问,而同一个程序集表示同一个dll程序集或同一个exe程序集。
-
C#基类的重写(关键字virtual,override,abstract)
c#支持重写实例方法和属性,但是不支持重写字段和任何静态成员,为了进行重写,需要将需要重写的成员用virtual关键字标记。在子类中使用override关键字重写。
如果不想让一个类的成员被重写,就将这个成员用sealed修饰符修饰。
如果我们就是想在父类中声明一些虚的成员(抽象成员),至于具体的实现都是在子类中,我们就可以将父类声明为抽象类(abstract修饰),然后在抽象类中声明抽象成员,这些抽象成员使用abstract修饰就好,或者virtual。
这里说说一下virtual和abstract修饰的成员的区别:
1)virtual修饰的成员比如方法必须有实现,哪怕是只有一对大括号的空实现,但是abstract修饰的成员不允许有实现;
2)virtual修饰的成员可以被子类重写,也可以不被重写,程序不会报错,但是abstract修饰的成员一定要在子类中实现;
3)抽象类中virtual修饰的已经在父类中实现地成员没有意义,因为抽象类无法实例化。 -
将xml文本快速序列化成类
复制xml文本内容,在vs中点击编辑->选择性粘贴->将xml粘贴为类。
-
一个类对应一个实体时,类的构造函数应该使用private关键字修饰。
private static Lazy<ConfigViewModel> _instance = new Lazy<ConfigViewModel>(() => new ConfigViewModel()); public static ConfigViewModel Instance => _instance.Value; private ConfigViewModel() { }
-
在窗口中可以直接将写好的用户控件放在里面,不把所有的东西都放在窗口上。
但注意:不要写页面Page,要写用户控件UserControl。
-
打开 文件/ 文件夹路径 选择窗口:
//选择文件 OpenFileDialog fileDialog = new OpenFileDialog(); fileDialog.ShowDialog(); fileDialog.Filter = "文本文件|*.txt"//选择的文件类型 string fileName = fileDialog.FileName; //选择文件夹、路径 FolderBrowserDialog folderBrowser = new FolderBrowserDialog(); folderBrowser.ShowDialog(); string SavePath = folderBrowser.SelectedPath;
-
Dictionary字典的用法,key - value
// 创建一个字典,将LightSource映射到相应的操作 Dictionary<LightSource, Action> LightActions = new Dictionary<LightSource, Action> { { LightSource.预扫, () => OpenLight(Presweep.预扫) }, { LightSource.出料, () => OpenLight(Presweep.出料) } }; // 使用字典来执行适当的操作 if (GetDic.LightActions.ContainsKey(LightSource)) { GetDic.LightActions[LightSource](); }
-
xml配置文件的加载和保存
//配置文件的加载 public int LoadConfig() { try { string filePath = AppDomain.CurrentDomain.BaseDirectory; filePath += "\\Config\\AOIConfig.xml"; var fs = new FileStream(filePath, FileMode.Open); var ser = new XmlSerializer(typeof(AOIConfig)); _config = ser.Deserialize(fs) as AOIConfig; fs.Close(); return 0; } catch (Exception ex) { return -1; } } //写入保存xml文件 public void SaveConfig() { try { string filePath = AppDomain.CurrentDomain.BaseDirectory; filePath += "\\Config\\AOIConfig.xml"; if (!File.Exists(filePath)) { var fp = File.Create(filePath); fp.Close(); } SerializeToXml(filePath, Config); HandyControl.Controls.MessageBox.Show("保存成功"); } catch (Exception ex) { HandyControl.Controls.MessageBox.Show("保存失败"); } } private void SerializeToXml<T>(string filePath, T obj) { //高级用法没看懂 using (StreamWriter streamWriter = new StreamWriter(filePath)) new XmlSerializer(typeof(T)).Serialize(streamWriter, obj); }
-
隐藏控件 Visibility=“Hidden”
-
串口通信,通信协议的使用和封装
public class Light { private ILight _lightType; private SerialPort serial = new SerialPort(); private AutoResetEvent _autoEvent; string _strRecv; public bool IsOpen => serial?.IsOpen ?? false; //串口通信 public int Open(string port, int baudRate) { try { serial.PortName = port; serial.BaudRate = baudRate; serial.Open(); if (serial.IsOpen) { serial.DataReceived += Serial_DataReceived; _autoEvent = new AutoResetEvent(false); } return 0; } catch (Exception) { return -1; } } public int Close() { try { if (IsOpen) { serial.Close(); serial.DataReceived -= Serial_DataReceived; _autoEvent.Close(); } return 0; } catch (Exception) { return -1; } } private void Serial_DataReceived(object sender, SerialDataReceivedEventArgs e) { byte[] array = new byte[serial.BytesToRead]; int num = serial.Read(array, 0, array.Length); if (num > 0) { string receiveStr = Encoding.UTF8.GetString(array, 0, array.Length); serial.DiscardInBuffer(); _strRecv = receiveStr; _autoEvent.Set(); } } private int WriteAndRecv(string cmd, int timeout, out string recv) { if (IsOpen) { _autoEvent.Reset(); serial.Write(cmd); if (!_autoEvent.WaitOne(timeout)) { recv = "串口返回超时"; return -1; } _autoEvent.Reset(); recv = _strRecv; } else { recv = "串口未连接"; } return 0; } public void SetLuminance(char channel, int value) { string protocol = _lightType.SetLuminance(channel, value); WriteAndRecv(protocol, 1000, out string recv); } public string GetLuminance(char channel) { string protocol = _lightType.GetLuminance(channel, 0); WriteAndRecv(protocol, 1000, out string recv); return recv; } }
public class Light_Navitar : ILight { public string GetLuminance(char channel, int value) { //#4 读取对应通道亮度参数 成功返回亮度,失败返回& int ch = GetChancel(channel); string protocol = $"#4{ch}000"; return protocol; } //通信协议 public string SetLuminance(char channel, int value) { if (value < 0 || value > 255) return ""; //#1 打开对应通道亮度 成功返回$,失败返回& //#2 关闭对应通道亮度 //#3 设置对应通道亮度参数 int ch = GetChancel(channel); string protocol = $"#3{ch}0{value:X2}"; string send = GetSend(protocol); return send; } private int GetChancel(char channel) { switch (channel) { case 'A': return 1; case 'B': return 2; case 'C': return 3; case 'D': return 4; default: return 1; } } private string GetSend(string str) { int temp = 0;//校验和 byte[] ascii = Encoding.ASCII.GetBytes(str); foreach (byte b in ascii) { temp = temp ^ b; } var h = (temp & 0xf0) >> 4; var l = temp & 0x0f; string send = str + h + l; return send; } }
-
三方库的使用,把库放到\bin\debug目录下,在资源里添加引用即可
-
三目运算符:bool类型 ? bool为真返回内容 :bool为假返回内容;
如:string s = 猪 == 八戒 ?唐僧徒弟 :其他猪;
-
依赖属性
public LightSource LightSource
{
get { return (LightSource)GetValue(LightSourceProperty); }
set { SetValue(LightSourceProperty, value); }
}
// Using a DependencyProperty as the backing store for LightSource. This enables animation, styling, binding, etc...
public static readonly DependencyProperty LightSourceProperty =
DependencyProperty.Register("LightSource", typeof(LightSource), typeof(LightControl1), new PropertyMetadata(null));
- 实现INotifyPropertyChanged接口和ICommand接口
internal class PersonViewModel :INotifyPropertyChanged
{
private Person _person;
public string Name
{
get { return _person.Name; }
set
{
_person.Name = value;
OnPropertyChanged(nameof(Name));
}
}
public int Age
{
get { return _person.Age; }
set
{
_person.Age = value;
OnPropertyChanged(nameof(Age));
}
}
public PersonViewModel()
{
_person = new Person() { Name = "张三", Age = 13 };
//将Button的Command属性绑定到ViewModel中的实现了ICommand接口的命令属性来实现按钮的命令绑定
ShowCommand = new Command(ExecuteShowCommand, CanExecuteShowCommand);
ChangeCommand = new Command(ExecuteChangeCommand, CanExecuteChangeCommand);
}
//显示当前Person的属性值
public ICommand ShowCommand { get; set; }
private void ExecuteShowCommand(object parameter)
{
// 执行命令逻辑
MessageBox.Show($"姓名:{Name}" + $" 年龄:{Age}");
}
private bool CanExecuteShowCommand(object parameter)
{
// 确定命令是否可以执行的逻辑
return true;
}
//更改Person的属性值
public ICommand ChangeCommand { get; set; }
private void ExecuteChangeCommand(object parameter)
{
// 执行命令逻辑
Name = "刘亦菲";
Age = 18;
}
private bool CanExecuteChangeCommand(object parameter)
{
return true;
}
//实现了INotifyPropertyChanged接口,于通知绑定源对象的属性值已更改
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
//触发事件,在又订阅者的情况下才会触发,如果有订阅者就会调用Invoke方法,将当前对象和包含属性 名称 的PropertyChangedEventArgs传递给订阅者
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
//实现ICommand接口
public class Command : ICommand
{
private readonly Action<object> _execute;//Action委托表示将要执行的命令
private readonly Func<object, bool> _canExecute;
public Command(Action<object> execute, Func<object, bool> canExecute = null)
{
_execute = execute ?? throw new ArgumentNullException(nameof(execute));
_canExecute = canExecute;
}
public event EventHandler CanExecuteChanged;
public bool CanExecute(object parameter) => _canExecute == null || _canExecute(parameter);
public void Execute(object parameter) => _execute(parameter);
public void RaiseCanExecuteChanged() => CanExecuteChanged?.Invoke(this, EventArgs.Empty);
}
-
字典用法
// 创建一个字典,将LightSource映射到相应的操作 Dictionary<LightSource, Action> LightActions = new Dictionary<LightSource, Action> { { LightSource.预扫, () => OptLightDevice.GetInstance().OpenLight(Presweep.预扫, ckbLight.IsChecked == true ? 255 : 0) }, { LightSource.出料, () => OptLightDevice.GetInstance().OpenLight(Presweep.出料, ckbLight.IsChecked == true ? 255 : 0) }, { LightSource.上料, () => OptLightDevice.GetInstance2().OpenLight(Monitor.上料, ckbLight.IsChecked == true ? 255 : 0) }, { LightSource.转台, () => OptLightDevice.GetInstance2().OpenLight(Monitor.转台, ckbLight.IsChecked == true ? 255 : 0) }, { LightSource.前端, () => LightDevice.GetInstance().OpenLight(EndDetect.前端, ckbLight.IsChecked == true ? 255 : 0) }, { LightSource.后端, () => LightDevice.GetInstance().OpenLight(EndDetect.后端, ckbLight.IsChecked == true ? 255 : 0) }, }; // 使用字典来执行适当的操作 if (GetDic.LightActions.ContainsKey(LightSource)) { GetDic.LightActions[LightSource](); }
-
关于Lock:确保代码块完成运行,而不会被其他线程中断;一般有多个线程需要访问数组的时候,需要上锁
这种情况会造成死锁:
using System;
using System.Threading;
class DeadlockExample
{
static object lock1 = new object();
static object lock2 = new object();
static void Main()
{
Thread thread1 = new Thread(Method1);
Thread thread2 = new Thread(Method2);
thread1.Start();
thread2.Start();
thread1.Join();
thread2.Join();
Console.WriteLine("Main thread finished.");
}
static void Method1()
{
lock (lock1)
{
Console.WriteLine("Method1 acquired lock1.");
Thread.Sleep(1000);
Console.WriteLine("Method1 trying to acquire lock2.");
lock (lock2)
{
Console.WriteLine("Method1 acquired lock2.");
}
}
}
static void Method2()
{
lock (lock2)
{
Console.WriteLine("Method2 acquired lock2.");
Thread.Sleep(1000);
Console.WriteLine("Method2 trying to acquire lock1.");
lock (lock1)
{
Console.WriteLine("Method2 acquired lock1.");
}
}
}
}
- ToString(“X2”) 为C#中的字符串格式控制符
大写X:ToString(“X2”)即转化为大写的16进制。
小写x:ToString(“x2”)即转化为小写的16进制。
2表示每次输出两位,不足2位的前面补0,如 0x0A 如果没有2,就只会输出0xA
假设有两个数10和26,正常情况十六进制显示0xA、0x1A,这样看起来不整齐,为了好看,可以指定"X2",这样显示出来就是:0x0A、0x1A
二进制在C#中无法直接表示,我们一般用0和1的字符串来表示一个数的二进制形式,
十进制转换为二进制:
System.Convert.ToString(d, 2);// d为int类型 以4为例,输出为100
十六进制转换为二进制:
System.Convert.ToString(d, 2);// d为int类型 以0X14为例,输出为10100
二进制转换为十进制(string–>int):
System.Convert.ToInt32(s, 2);// d为string类型 以“1010”为例,输出为10
十六进制转换为十进制(string–>int、int–>int)
System.Convert.ToString(0xa,10);// 以0XA为例,输出为10
System.Convert.ToInt32(“0x41”, 16);//以"0x41"为例,输出为65
System.Int32.Parse(s, System.Globalization.NumberStyles.HexNumber);//s为string类型,以“41”为例,输出为65(注意这里的s中不能带有“0X”或者“0x”,区别于上面的方法。)
-
- Modbus协议计算CRC校验码
#region 计算CRC校验码 /// <summary> /// 计算CRC校验码,并转换为十六进制字符串 /// Cyclic Redundancy Check 循环冗余校验码 /// 特征是信息字段和校验字段的长度可以任意选定 /// 此校验计算 高位在前,低位在后 /// </summary> /// <returns></returns> public static byte[] get_CRC16_C(byte[] data) { byte num = 0xff; byte num2 = 0xff; byte num3 = 1; byte num4 = 160; byte[] buffer = data; for (int i = 0; i < buffer.Length; i++) { //位异或运算 num = (byte)(num ^ buffer[i]); for (int j = 0; j <= 7; j++) { byte num5 = num2; byte num6 = num; //位右移运算 num2 = (byte)(num2 >> 1); num = (byte)(num >> 1); //位与运算 if ((num5 & 1) == 1) { //位或运算 num = (byte)(num | 0x80); } if ((num6 & 1) == 1) { num2 = (byte)(num2 ^ num4); num = (byte)(num ^ num3); } } } return new byte[] { num, num2 }; //return byteToHexStr(new byte[] { num, num2 }, 2); } #endregion
-
在程序集中无法添加资源文件
解决办法:先卸载该程序集,在弹出的界面添加该语句:
{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
若不知道该添加在哪,可以卸载一个正常的程序集 ,对照添加,完成后重新加载程序集即可。