项目
ExControl
包含所有界面的控件
界面
用户界面
用户登录界面
public static void showlogin()
{
ExControl.User.Form1 instance = ExControl.User.Form1.instance;
if (instance == null)
{
instance = new ExControl.User.Form1();
instance.OnUserChanged += F_OnUserChanged;
instance.Show();
}
else
{
instance.Activate();
instance.WindowState = FormWindowState.Normal;
}
}
- 单例模式:Form1.instance 是 Form1 类内部维护的一个静态引用,保证全局只有一个登录窗口。第二次调用 showlogin() 时不会重复创建,而是激活已有窗口。在代码中有
instance = this;,可以保证如果打开了,就会有记录
public Form1()
{
try
{
InitializeComponent();
instance = this;
if (!userData.LoadDone)
{
userData.Readfile();
}
user = userData.CurrentUser;
base.StartPosition = FormStartPosition.CenterScreen;
base.ShowIcon = false;
fixedWindowText = "用户管理";
Text = fixedWindowText;
base.MaximizeBox = false;
setVisble();
base.FormClosed += Form1_FormClosed;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
- 其中
base.FormClosed += Form1_FormClosed;,是父类的窗口关闭事件,意思是当窗口关闭完了之后,就要调用Form1_FormClosed - 默认用户:admin,密码:123a
DevExpress
BarManager
BarManager 管菜单和工具栏
DockManager
DockManager 管可停靠面板。
using DevExpress.XtraBars.Docking;
DockManager dm = new DockManager();
dm.Form = this;
DockPanel leftPanel = dm.AddPanel(DockingStyle.Left);
leftPanel.Text = "设备列表";
DockPanel rightPanel = dm.AddPanel(DockingStyle.Right);
rightPanel.Text = "相机预览";
- 用了这个之后,就能拖曳窗口
AccessAssisstant
timer
用于刷新前面板的仪器状态
Timer timer = new Timer() { Interval = 100 };
private void LoadDevice()
{
var edit = (getItem("edit")) as DevExpress.XtraBars.BarSubItem;
if (edit != null)
{
var set = new DevExpress.XtraBars.BarButtonItem(BarMana, "外部设备");
//edit.LinksPersistInfo.Add(new DevExpress.XtraBars.LinkPersistInfo(set, true));
edit.AddItem(set);
SetBeginGroup(edit, set);
set.ItemClick += ItemClick;
}
TickDevice();
}
- getItem(“edit”):就是找到菜单栏的设置
类
MainTask
- 就是包含所有管理类,其中包括
- CamMana
- SQLMana
- DeviceMana
WriteAble
- 继承WriteAble要重写filename
- public override string fileName => “proxy.dat”;
- 写用Write,例如proxy.param.Write();
[Serializable]
public abstract class WriteAble<T>
{
public abstract string fileName { get; }
private static string GetFileName()
{
return (System.Activator.CreateInstance<T>() as WriteAble<T>).fileName;
}
public virtual void Write(string filePath = "")
{
if (filePath == null || filePath == "")
{
filePath = AppDomain.CurrentDomain.BaseDirectory + fileName;
}
if (File.Exists(filePath) == false)
{
DirectoryInfo infor = new DirectoryInfo(filePath);
Directory.CreateDirectory(infor.Parent.FullName);
}
using (FileStream fs = new FileStream(filePath, FileMode.Create))
{
BinaryFormatter bf = new BinaryFormatter();
bf.Serialize(fs, this);
fs.Close();
}
}
public static T Read(string filePath = "")
{
try
{
if (filePath == null || filePath == "") filePath = AppDomain.CurrentDomain.BaseDirectory + GetFileName();
using (FileStream fs = new FileStream(filePath, FileMode.Open))
{
BinaryFormatter bf = new BinaryFormatter();
return (T)bf.Deserialize(fs);
}
}
catch (Exception ex)
{
Log.print($"[{filePath}]"+ ex.Message, MsgTpye.Error);
return System.Activator.CreateInstance<T>();
}
}
public static T1 Read<T1>(string filePath = "")
{
try
{
if (filePath == null || filePath == "") filePath = AppDomain.CurrentDomain.BaseDirectory +
(System.Activator.CreateInstance<T1>() as WriteAble<T>).fileName;
using (FileStream fs = new FileStream(filePath, FileMode.Open))
{
BinaryFormatter bf = new BinaryFormatter();
return (T1)bf.Deserialize(fs);
}
}
catch (Exception ex)
{
Log.print(ex.Message, MsgTpye.Error);
return Activator.CreateInstance<T1>();
}
}
}
CloneAble
public class CloneAble<T>
{
public virtual T Clone()
{
System.IO.Stream stream = new System.IO.MemoryStream();
System.Runtime.Serialization.Formatters.Binary.BinaryFormatter formatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
formatter.Serialize(stream, this);
stream.Seek(0, System.IO.SeekOrigin.Begin);
return (T)formatter.Deserialize(stream);
}
}
继承了这个类之后,就能得到深拷贝的副本
public class Recipe : CloneAble<Recipe>
{
public string Name { get; set; }
public List<string> Steps { get; set; }
}
var original = new Recipe { Name = "配方A", Steps = new List<string> { "步骤1" } };
var copy = original.Clone(); // 深拷贝
copy.Name = "配方B"; // 修改副本,不影响 original
修改 copy 不会影响 original,因为它是深拷贝,内部对象也是新创建的。
CollectionElement : CloneAble
CollectionElement 继承了 CloneAble,所以它就自动拥有了父类里的 Clone() 方法,而且返回类型正好是 CollectionElement,不需要强转。
[Serializable]
public class CollectionElement : CloneAble<CollectionElement>
- 必须要加[Serializable],否则clone里面的序列化器会报错
写法:
var original = new CollectionElement();
var copy = original.Clone(); // 返回 CollectionElement
原理:
public virtual T Clone()
在子类里等价于:
public virtual CollectionElement Clone()
ManaCollection
这个是管理器的父类,继承并实现了集合接口
public class ManaCollection : WriteAble<ManaCollection>, IEnumerable<CollectionElement>, ICollection<CollectionElement>
- 是包含了CollectionElement的集合,可以使用count,add等函数
- SetEnumableItem()函数用户设置所有可枚举类型的对象实例
public virtual void SetEnumableItem()
{}
public class DeviceMana : ManaCollection
DeviceMana设备管理类在SetEnumableItem函数,新建了所有设备类
public class DeviceMana : ManaCollection
{
public override string fileName => "Device.dat";
public DeviceMana()
{
SetEnumableItem();
}
public override void SetEnumableItem()
{
SetEnumableItem(new CollectionElement[] { new PLCModbus(), new HsSims(),new HsMelsecMc(),new HsOmron(),
new RS232(),new NetWorkBase(),new ILSerials(),new OPTLightDevice(),new SenPum()});
}
}
重写设备类
- 两把自动扫码器
WEBAPI
- 设置界面
- 调用类
主流程
接口
IEnumerable 和 ICollection
如果一个类同时继承了 IEnumerable 和 ICollection,那它本质上就是一个 标准集合类。
接口会有实现count,add,remove,clear,contains等集合函数
| 能力 | 具体作用 |
|---|---|
| 可遍历 | 可以用 foreach 遍历 |
| 可 LINQ | 能直接用 Where、Select、FirstOrDefault 等 |
| 可计数 | 有 Count 属性 |
| 可增删 | 有 Add、Remove、Clear、Contains |
| 可替换 | 能当成 ICollection<T> 或 IEnumerable<T> 传给别的方法 |
| 可绑定 | 很多 UI 控件、序列化、数据源只认这些标准接口 |
问答
- 继承了接口的类的子类,需不需要再实现接口的函数
| 情况 | 子类要不要再实现 Add/Remove | 说明 |
|—|—|—|
| 父类已经实现了 | 不需要 | 子类直接继承父类的实现即可 |
| 父类只声明了接口,没实现 | 必须实现 | 否则子类编译会报错,除非子类也是abstract|
| 子类想改行为 | 可以选择重写/隐藏/重新实现 | 取决于父类方法是不是virtual|
写法
Device
namespace StandardKit.Kit.Equipment
{
[Serializable]
public class DeviceParam : CloneAble<DeviceParam>
{
}
[Serializable]
public class Device : DeviceBase
{
public DeviceParam param { get; set; }
public Device()
{
param =new DeviceParam();
}
public virtual DeviceResult Read()
{
return new DeviceResult("指定的设备无效");
}
public virtual DeviceResult Write(byte[] data)
{
return new DeviceResult("指定的设备无效");
}
public virtual void WaitConnect()
{
}
public DeviceResult Write(string str,string codename= "ascii")
{
try
{
byte[] arr;
if (str == null || str == "")
arr = new byte[0];
else
arr = Encoding.GetEncoding(codename).GetBytes(str);
return Write(arr);
}
catch (Exception ex)
{
return new DeviceResult(ex);
}
}
/// <summary>
/// 返回字符串
/// </summary>
/// <returns></returns>
public string ReadString(string incodename="ascii")
{
try
{
byte[] v = Read().Content;
if (v != null)
return Encoding.GetEncoding(incodename).GetString(v);
else
return "";
}
catch
{
return "";
}
}
public virtual void ClearBuffer()
{
}
}
}
- 设备在继承了RS232或者NetWorkBase后,这些函数在里面就会重写,所以子类本身不要重写write,最好只调用write
- DeviceParam : CloneAble:DeviceParam在继承了CloneAble之后,就能够创建一个副本
Scanner
- DeviceProperty会不会显示重写类的属性
- 在DeviceMan添加new Scanner()
[Serializable]
public class DeviceMana : ManaCollection
{
public override string fileName => "Device.dat";
public DeviceMana()
{
SetEnumableItem();
}
public override void SetEnumableItem()
{
SetEnumableItem(new CollectionElement[] { new PLCModbus(), new HsSims(),new HsMelsecMc(),new HsOmron(),
new RS232(),new NetWorkBase(),new ILSerials(),new OPTLightDevice(),new SenPum(),new Scanner()});
}
}
- 增加实体类和实体类参数
namespace StandardKit.Kit.Equipment
{
[Serializable]
public class ScannerParam : NetWorkParam
{
[Browsable(true)]
[DisplayName("启用长度校验")]
[Category("校验设置"), DefaultValue(false)]
public bool enableLen { get; set; }
[Browsable(true)]
[DisplayName("长度")]
[Category("校验设置"), DefaultValue(0)]
public int codeLength { get; set; }
[Browsable(true)]
[DisplayName("启用关键字校验")]
[Category("校验设置"), DefaultValue(false)]
public bool enableKeyWord { get; set; }
[Browsable(true)]
[DisplayName("关键字")]
[Category("校验设置"), DefaultValue("")]
public string keyWord { get; set; }
}
[Serializable]
public class Scanner :NetWorkBase
{
public Scanner() {
param = new ScannerParam();
}
public override string displayText
{
get {
return "扫码器";
}
}
public override Image Image
{
get
{
return null;
}
}
private object lockobj = new object();
public virtual bool Scan(out string barcode)
{
barcode = "";
bool result = true;
try
{
lock (lockobj)
{
ClearBuffer();
var deviceResult = Write("start\r\n");
if (deviceResult.isSuccess != true)
{
isConnect = false;
return false;
}
barcode = ReadString();
var scannerParam = param as ScannerParam;
if (scannerParam.enableLen)
result &= barcode.Trim().Length == scannerParam.codeLength;
if (scannerParam.enableKeyWord)
result &= barcode.Trim().ToLower().Contains(scannerParam.keyWord.ToLower());
barcode = barcode.Trim();
return result;
}
}
catch (Exception ex)
{
return false;
}
}
}
}
数据库
SQLMana
在SetEnumableItem增加数据库类
[Serializable]
public class SQLMana : ManaCollection
{
public override string fileName { get; } = "Sql.dat";
public SQLMana()
{
SetEnumableItem();
}
public override void SetEnumableItem()
{
SetEnumableItem(new CollectionElement[] { new MySQL(), new SQLServer(), new SQLite()});
}
}
界面
主界面
RenderBase
- 继承XtraUserControl
注册保存事件
在ItemClickEventHandler注册事件的时候,new hotMelt.FrameSetting()实际上是没运行的,要等到点击参数设置后,才会运行,才会注册OnSave事件
access.AddMenuItem("edit", "参数设置", new DevExpress.XtraBars.ItemClickEventHandler((s, e) =>
{
access.documentMana.AddDocument(() => new hotMelt.FrameSetting() { hotMelt = render.hotMelt, Dock = DockStyle.Fill }, "参数设置");
}));
用户
通过ExControl.ExportClass.userMama.OnUserChanged事件来广播
ExControl.ExportClass.userMama.OnUserChanged += (s, e) =>
{
render.message.RaisEventOnUserChanged(userMama.CurentUser.UserMode, null);
};
userMama
统一注册OnUserChanged事件
namespace ExControl.ExportClass
{
public class userMama
{
public static event EventHandler OnUserChanged;
//private static readonly string[] PowerArray = new string[] { "普通", "管理员", "超级管理员", "程序员" };
//private static readonly Color[] Colors = new Color[] { Color.Black, Color.Green, Color.DeepPink, Color.OrangeRed };
public userMama()
{
}
public static User.UserInfor CurentUser
{
get
{
var u = ExControl.User.userData.CurrentUser;
return new User.UserInfor() { name = u.name, password = u.password, power = u.power, tag = u.tag };
}
}
public static bool CheckUser(string name, string password)
{
bool res;
// var old = CurentUser;
if (ExControl.User.userData.LoadDone == false)
ExControl.User.userData.Readfile();
ExControl.User.userData.checkPassword(name, password, out res);
return res;
}
public static void showlogin()
{
var f = ExControl.User.Form1.instance;
if (f == null)
{
f = new ExControl.User.Form1();
f.OnUserChanged += F_OnUserChanged;
f.Show();
}
else
{
f.Activate();
f.WindowState = System.Windows.Forms.FormWindowState.Normal;
}
}
public static void logout()
{
ExControl.User.userData.CurrentUser = new ExControl.User.UserInfor();
OnUserChanged?.Invoke(null, null);
}
public static string[,] getAllUser()
{
return ExControl.User.userData.table;
}
public static void UpdateAllUser(string[,] table)
{
ExControl.User.userData.UpdateData(table);
}
private static void F_OnUserChanged(object sender, EventArgs e)
{
OnUserChanged?.Invoke(sender, e);
}
}
}
ManaControl
笔记
- 控件写在ExControl,功能写在StanardKit,主界面写在Mainpoject
- C# 中的 [Serializable] 特性(SerializableAttribute)不会被继承。
- 子类必须显式标记:如果基类标记了 [Serializable],派生类不会自动获得该特性。若希望子类也可序列化,必须在子类上再次显式添加 [Serializable]。
- C# 中特性的继承性取决于 [AttributeUsage] 的 Inherited 属性,其默认值为 true,即默认是可继承的。
转载自 CSDN-专业IT技术社区
原文链接:https://blog.csdn.net/weixin_41303851/article/details/170200922



