c#串口通讯wpf的mvvm模式电子称
INotifyPropertyChanged,用来绑定字段
/// <summary> /// mvvm的基类 /// </summary> public class NotificationOjbect : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; public void RaisePropertyChanged(string PropertyName) { if (this.PropertyChanged != null) { this.PropertyChanged.Invoke(this, new PropertyChangedEventArgs(PropertyName)); } } }
ICommand,用来绑定事件
/// <summary> /// 执行命令 /// </summary> public class DelegateCommand : ICommand { public event EventHandler CanExecuteChanged; public Action<object> ExecuteAction; public Func<object, bool> CanExecuteFunc; public DelegateCommand() { } public DelegateCommand(Action<object> execute) : this(execute, null) { } public DelegateCommand(Action<object> execute, Func<object, bool> canExecute) { if (execute == null) { return; } ExecuteAction = execute; CanExecuteFunc = canExecute; } public bool CanExecute(object parameter) { if (this.CanExecuteFunc == null) { return true; } return this.CanExecuteFunc(parameter); } public void Execute(object parameter) { if (this.ExecuteAction != null) { this.ExecuteAction(parameter); } } }
属性的绑定
private string _PortName; /// <summary> /// 端口名称 /// </summary> public string PortName { get { return _PortName; } set { _PortName = value; _notification.RaisePropertyChanged("PortName"); } }
事件的绑定
public ICommand SaveSerialPort { get { return new DelegateCommand( (param) => { btnSave_Click(param); } , (v) => { return true; }); } }
调用代码
this.DataContext = new SerialPortViewModel();
界面绑定属性和事件
一个最简单的wpf的mvvm就弄完了
dome的地址:https://gitee.com/cainiaoA/wpfstudent
串口通讯封装代码
xml序列化,用来报错串口配置
public class XmlSerializerHelper { #region Xml系列化 public static void Serialize<T>(Stream stream, T instance) { Serialize<T>(stream, instance, null, null, true); } public static void Serialize<T>(Stream stream, T instance, Encoding encoding) { Serialize<T>(stream, instance, null, encoding, true); } public static void Serialize<T>(Stream stream, T instance, XmlSerializerNamespaces ns, bool CloseStream = true) { if (instance == null) return; XmlSerializer xs = new XmlSerializer(typeof(T)); if (ns == null) xs.Serialize(stream, instance); else xs.Serialize(stream, instance, ns); if (CloseStream) { stream.Close(); } } public static void Serialize<T>(Stream stream, T instance, XmlSerializerNamespaces ns, Encoding encoding, bool CloseStream = true) { if (instance == null) return; XmlSerializer xs = new XmlSerializer(typeof(T)); StreamWriter writer = null; if (encoding == null) writer = new StreamWriter(stream); else writer = new StreamWriter(stream, encoding); if (ns == null) xs.Serialize(writer, instance); else xs.Serialize(writer, instance, ns); if (CloseStream) { writer.Close(); stream.Close(); } } public static MemoryStream Serialize<T>(T instance) { return Serialize<T>(instance, null, null); } public static MemoryStream Serialize<T>(T instance, Encoding encoding) { return Serialize<T>(instance, null, encoding); } public static MemoryStream Serialize<T>(T instance, XmlSerializerNamespaces ns) { if (instance == null) return null; MemoryStream ms = new MemoryStream(); Serialize<T>(ms, instance, ns, false); return ms; } public static MemoryStream Serialize<T>(T instance, XmlSerializerNamespaces ns, Encoding encoding) { if (instance == null) return null; MemoryStream ms = new MemoryStream(); Serialize<T>(ms, instance, ns, encoding, false); return ms; } public static string SerializeToString<T>(T instance) { return SerializeToString<T>(instance, null, Encoding.UTF8); } public static string SerializeToString<T>(T instance, Encoding encoding) { return SerializeToString<T>(instance, null, encoding); } public static string SerializeToString<T>(T instance, XmlSerializerNamespaces ns) { return SerializeToString<T>(instance, ns, Encoding.UTF8); } public static string SerializeToString<T>(T instance, XmlSerializerNamespaces ns, Encoding encoding) { using (MemoryStream ms = Serialize(instance, ns, encoding)) { ms.Position = 0; using (StreamReader sr = new StreamReader(ms, encoding)) { return sr.ReadToEnd(); } } } public static byte[] SerializeToBytes<T>(T instance) { return SerializeToBytes<T>(instance, null, null); } public static byte[] SerializeToBytes<T>(T instance, Encoding encoding) { return SerializeToBytes<T>(instance, null, null); } public static byte[] SerializeToBytes<T>(T instance, XmlSerializerNamespaces ns) { using (MemoryStream ms = Serialize<T>(instance, ns)) { return ms.ToArray(); } } public static byte[] SerializeToBytes<T>(T instance, XmlSerializerNamespaces ns, Encoding encoding) { using (MemoryStream ms = Serialize<T>(instance, ns, encoding)) { return ms.ToArray(); } } #endregion #region xml反系列化 /// <summary> /// XML反系列化 /// </summary> /// <param name="ms">Stream流</param> public static T DeSerialize<T>(Stream ms, Encoding encoding = null) { if (encoding == null) encoding = Encoding.UTF8; ms.Position = 0; using (StreamReader sr = new StreamReader(ms, encoding)) { //通过XmlReader.Create静态方法创建XmlReader实例 using (XmlReader rdr = XmlReader.Create(sr)) { XmlSerializer xs = new XmlSerializer(typeof(T)); T model = (T)xs.Deserialize(rdr); return model; } } } /// <summary> /// XML反系列化 /// </summary> /// <param name="str">xml字符串</param> public static T DeSerializeString<T>(string str, Encoding encoding = null) { if (encoding == null) encoding = Encoding.UTF8; using (MemoryStream ms = new MemoryStream()) { byte[] bytes = encoding.GetBytes(str); BinaryWriter bw = new BinaryWriter(ms); bw.Write(bytes); return DeSerialize<T>(ms); } } /// <summary> /// XML反系列化 /// </summary> /// <param name="bytes">字节数组</param> public static T DeSerializeBytes<T>(byte[] bytes, Encoding encoding = null) { if (encoding == null) encoding = Encoding.UTF8; using (MemoryStream ms = new MemoryStream()) { BinaryWriter bw = new BinaryWriter(ms); bw.Write(bytes); return DeSerialize<T>(ms, encoding); } } #endregion }
单例模式,保存串口配置
public class AppPathAttribute : Attribute { public AppPathAttribute(string path) { Path = path; } public string Path { get; set; } }
public class AppBase<T> where T : AppBase<T> { #region 字段 private static T _instance; private static readonly object _objLock = new object(); private static FileSystemWatcher m_Watcher; /// <summary> /// 配置文件完整路径 /// </summary> public static string FullPath { get; private set; } #endregion #region 构造函数 static AppBase() { var type = typeof(T); var pathAttr = (AppPathAttribute)type.GetCustomAttributes(typeof(AppPathAttribute), false).FirstOrDefault(); if (pathAttr != null) FullPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, pathAttr.Path); else FullPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"Config", type.Name + ".config"); string fileName = Path.GetFileName(FullPath); string path = Path.GetDirectoryName(FullPath); if (!Directory.Exists(path)) Directory.CreateDirectory(path); m_Watcher = new FileSystemWatcher(); m_Watcher.Filter = fileName; m_Watcher.Path = path; m_Watcher.NotifyFilter = NotifyFilters.Attributes | NotifyFilters.CreationTime | NotifyFilters.DirectoryName | NotifyFilters.FileName | NotifyFilters.LastAccess | NotifyFilters.LastWrite | NotifyFilters.Security | NotifyFilters.Size; m_Watcher.Changed += new FileSystemEventHandler(OnChanged); m_Watcher.Created += new FileSystemEventHandler(OnChanged); m_Watcher.Deleted += new FileSystemEventHandler(OnChanged); m_Watcher.Renamed += new RenamedEventHandler(OnRenamed); m_Watcher.EnableRaisingEvents = true; } private static void OnChanged(object sender, FileSystemEventArgs e) { lock (_objLock) { _instance = null; } } private static void OnRenamed(object sender, RenamedEventArgs e) { lock (_objLock) { _instance = null; } } #endregion #region 属性 /// <summary> /// 单例模式 /// </summary> public static T Instance { get { lock (_objLock) { if (_instance != null) return _instance; _instance = GetSetting(); return _instance; } } set { lock (_objLock) { _instance = value; } } } #endregion #region 方法 /// <summary> /// 读取本地配置 /// </summary> /// <returns>基类为BaseSetting的对象</returns> private static T GetSetting() { var SettingPath = FullPath; if (File.Exists(SettingPath)) { try { return WithRetry(() => { using (var fs = new FileStream(SettingPath, FileMode.Open, FileAccess.ReadWrite, FileShare.Read)) { return XmlSerializerHelper.DeSerialize<T>(fs); } }); } catch (InvalidOperationException) { } } return Activator.CreateInstance<T>(); } /// <summary> /// 保存配置 /// </summary> public void Save() { m_Watcher.EnableRaisingEvents = false; try { var path = Path.GetDirectoryName(FullPath); if (!Directory.Exists(path)) Directory.CreateDirectory(path); WithRetry(() => { using (var fs = new FileStream(FullPath, FileMode.Create, FileAccess.ReadWrite, FileShare.Read)) { var ns = new XmlSerializerNamespaces(); ns.Add("", ""); XmlSerializerHelper.Serialize(fs, _instance, ns); } }); } catch { throw; } finally { m_Watcher.EnableRaisingEvents = true; } } private static void WithRetry(Action action, int timeoutMs = 2000) { var time = Stopwatch.StartNew(); try { while (true) { try { action(); break; } catch (IOException) { if (time.ElapsedMilliseconds < timeoutMs) { throw; } } } } finally { time.Stop(); } } private static Out WithRetry<Out>(Func<Out> action, int timeoutMs = 2000) { var time = Stopwatch.StartNew(); try { while (true) { try { return action(); } catch (IOException) { if (time.ElapsedMilliseconds > timeoutMs) { throw; } } } } finally { time.Stop(); } } #endregion }
#region 委托事件 /// <summary> /// 串口状态 /// </summary> /// <param name="Status"></param> public delegate void StatusEvent(bool Status); /// <summary> /// 数据接收 /// </summary> /// <param name="Data"></param> public delegate void DataReceived(string Data); /// <summary> /// 接收结果委托 /// </summary> /// <param name="StrWeight"></param> public delegate void ResultReceived(string StrResult); /// <summary> /// 接收串口原始委托 /// </summary> /// <param name="OrginData"></param> public delegate void OrginDataReceived(string OrginData); #endregion public class ScalesSerialPort : IDisposable { #region 参数 private static readonly SynchronizationContext DefaultSynchronizationContext = new SynchronizationContext(); private readonly SynchronizationContext _synchronizationContext; private static SerialPorter _DefaultSerialPort = new SerialPorter(new SerialPort()); private SerialPorter _CurrentSerialPort; public StatusEvent StatusEvent; public OrginDataReceived orginDataReceived; public ResultReceived resultReceived; #endregion #region 构造函数 public ScalesSerialPort() : this(_DefaultSerialPort) { } public ScalesSerialPort(SerialPort SerialPort) : this(new SerialPorter(SerialPort)) { } private ScalesSerialPort(SerialPorter SerialPort) { _synchronizationContext = SynchronizationContext.Current ?? DefaultSynchronizationContext; _CurrentSerialPort = SerialPort; _CurrentSerialPort.OrginDataReceived += _serialPort_DataReceived; _CurrentSerialPort.resultReceived += _serialPort_ResultReceived; _CurrentSerialPort.StatusEvent += _serialPort_StatusEvent; } #endregion #region 初始化 private void _serialPort_DataReceived(string OrginData) { _synchronizationContext.Post((arg) => { if (orginDataReceived != null) orginDataReceived(OrginData); }, null); } private void _serialPort_ResultReceived(string StrWeight) { _synchronizationContext.Post((arg) => { if (resultReceived != null) { resultReceived(StrWeight); } }, null); } public void _serialPort_StatusEvent(bool Status) { _synchronizationContext.Post((arg) => { if (StatusEvent != null) StatusEvent(Status); }, null); } #endregion #region 方法 /// <summary> /// 串口配置 /// </summary> public void SetConfig(SerialPortSetting setting) { _CurrentSerialPort.SetConfig(_CurrentSerialPort.SerialPort, setting); } /// <summary> /// 串口状态 /// </summary> public bool IsOpen { get { return _CurrentSerialPort.SerialPort.IsOpen; } } /// <summary> /// 串口名称 /// </summary> public string PortName { get { return _CurrentSerialPort.SerialPort.PortName; } } /// <summary> /// 打开串口 /// </summary> public void Open() { try { if (!_CurrentSerialPort.SerialPort.IsOpen) _CurrentSerialPort.SerialPort.Open(); } catch { throw; } finally { if (_CurrentSerialPort.StatusEvent != null) _CurrentSerialPort.StatusEvent(_CurrentSerialPort.SerialPort.IsOpen); } } /// <summary> /// 关闭串口 /// </summary> public void Close() { try { _CurrentSerialPort.SerialPort.Close(); } catch { throw; } finally { if (_CurrentSerialPort.StatusEvent != null) _CurrentSerialPort.StatusEvent(_CurrentSerialPort.SerialPort.IsOpen); } } /// <summary> /// 释放资源 /// </summary> public void Dispose() { _CurrentSerialPort.OrginDataReceived -= _serialPort_DataReceived; _CurrentSerialPort.resultReceived -= _serialPort_ResultReceived; _CurrentSerialPort.StatusEvent -= _serialPort_StatusEvent; } #endregion } public class SerialPorter { /// <summary> /// 接收数据缓存 /// </summary> private string StrDataReceived = string.Empty; private SerialPortSetting _Setting; public SerialPortSetting Setting { get { return _Setting; } } public SerialPort SerialPort { get; private set; } public StatusEvent StatusEvent; public OrginDataReceived OrginDataReceived; public ResultReceived resultReceived; public SerialPorter(SerialPort serialPort) { SerialPort = serialPort; SetConfig(serialPort, SerialPortSetting.Instance); serialPort.DataReceived += _serialPort_DataReceived; } public void SetConfig(SerialPort SerialPort, SerialPortSetting setting) { bool isOpen = SerialPort.IsOpen; if (isOpen) SerialPort.Close(); // Allow the user to set the appropriate properties. SerialPort.PortName = setting.PortName;// 端口 SerialPort.BaudRate = setting.BaudRate;//波特率 SerialPort.Parity = setting.Parity;//奇偶 SerialPort.DataBits = setting.DataBits;//位数 SerialPort.StopBits = setting.StopBits;//停止位 // Set the read/write timeouts SerialPort.ReadTimeout = 500; SerialPort.WriteTimeout = 500; //重新打开串口 if (isOpen) SerialPort.Open(); _Setting = setting; } private void _serialPort_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e) { var OrginData = SerialPort.ReadExisting(); if (OrginDataReceived != null) OrginDataReceived(OrginData); StrDataReceived += OrginData; if (string.IsNullOrWhiteSpace(_Setting.StartChar)) return; var lastindex = StrDataReceived.LastIndexOf(_Setting.StartChar); if (lastindex <= 0) return; var suf = StrDataReceived.Substring(0, lastindex); var suflastindex = suf.LastIndexOf(_Setting.StartChar); if (suflastindex <= 0) return; var WeightData = suf.Substring(suflastindex + 1); StrDataReceived = StrDataReceived.Substring(lastindex); if (WeightData.Length > 0) { string StrWeight = string.Empty; char[] charArray = WeightData.ToCharArray(); for (int i = 1; i <= charArray.Length; i++) { StrWeight += charArray[charArray.Length - i]; } if (resultReceived != null) { resultReceived(StrWeight); } } } }