以下是简化后的C#窗体应用项目结构,完全按照Visual Studio新建项目的默认结构设计:
```
DataParserApp/
├── DataParserApp.csproj
├── Program.cs
├── Properties/
│ └── AssemblyInfo.cs
├── Resources/
│ └── Rules.xml
├── MainForm.cs
├── MainForm.Designer.cs
└── ProtocolParser.cs
```
### 1. DataParserApp.csproj (项目文件)
```xml
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net472</TargetFramework>
<UseWindowsForms>true</UseWindowsForms>
</PropertyGroup>
<ItemGroup>
<None Include="Resources\Rules.xml">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>
```
### 2. Program.cs (程序入口)
```csharp
using System;
using System.Windows.Forms;
namespace DataParserApp
{
static class Program
{
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new MainForm());
}
}
}
```
### 3. Resources/Rules.xml (规则配置文件)
```xml
<?xml version="1.0" encoding="utf-8"?>
<DataDefinitions>
<Template Command="0x01" SubCommand="0x00">
<Fields>
<Field Name="Current" Offset="2" Type="float" Coefficient="0.1" />
<Field Name="Voltage" Offset="6" Type="float" Coefficient="0.01" />
<Field Name="Temp" Offset="10" Type="int16" Coefficient="0.5" />
</Fields>
<Flags>
<Flag Name="SystemFault" Offset="12">
<Bit Pos="0" Desc="过流" />
<Bit Pos="1" Desc="过压" />
<Bit Pos="2" Desc="过温" />
</Flag>
</Flags>
</Template>
</DataDefinitions>
```
### 4. MainForm.cs (主窗体逻辑)
```csharp
using System;
using System.Windows.Forms;
namespace DataParserApp
{
public partial class MainForm : Form
{
private ProtocolParser parser;
public MainForm()
{
InitializeComponent();
parser = new ProtocolParser("Resources\\Rules.xml");
parser.DataParsed += UpdateDisplay;
parser.FaultDetected += ShowFault;
}
private void UpdateDisplay(object sender, DataEventArgs e)
{
if (InvokeRequired)
{
Invoke(new Action<object, DataEventArgs>(UpdateDisplay), sender, e);
return;
}
Controls[$"txt{e.Name}"].Text = e.Value.ToString("F2");
}
private void ShowFault(object sender, FaultEventArgs e)
{
MessageBox.Show($"故障:{e.Description}", "警告", MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
private void btnSend_Click(object sender, EventArgs e)
{
byte[] testData = new byte[13];
testData[0] = 0x01; // 命令字
testData[1] = 0x00; // 子命令
// 电流值 100A (原始值1000)
BitConverter.GetBytes(1000).CopyTo(testData, 2);
// 电压值 220V (原始值22000)
BitConverter.GetBytes(22000).CopyTo(testData, 6);
// 温度值 30℃ (原始值60)
BitConverter.GetBytes((short)60).CopyTo(testData, 10);
// 故障标志 (过温)
testData[12] = 0x04;
parser.Parse(testData);
}
}
}
```
### 5. MainForm.Designer.cs (窗体设计器)
```csharp
namespace DataParserApp
{
partial class MainForm
{
private System.ComponentModel.IContainer components = null;
public System.Windows.Forms.TextBox txtCurrent;
public System.Windows.Forms.TextBox txtVoltage;
public System.Windows.Forms.TextBox txtTemp;
public System.Windows.Forms.Button btnSend;
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(300, 200);
// 创建文本框
this.txtCurrent = new TextBox() { Location = new System.Drawing.Point(100, 10), Width = 100 };
this.txtVoltage = new TextBox() { Location = new System.Drawing.Point(100, 40), Width = 100 };
this.txtTemp = new TextBox() { Location = new System.Drawing.Point(100, 70), Width = 100 };
// 创建按钮
this.btnSend = new Button() { Text = "发送数据", Location = new System.Drawing.Point(100, 110) };
this.btnSend.Click += btnSend_Click;
// 添加控件
this.Controls.Add(new Label() { Text = "电流:", Location = new System.Drawing.Point(20, 10) });
this.Controls.Add(txtCurrent);
this.Controls.Add(new Label() { Text = "电压:", Location = new System.Drawing.Point(20, 40) });
this.Controls.Add(txtVoltage);
this.Controls.Add(new Label() { Text = "温度:", Location = new System.Drawing.Point(20, 70) });
this.Controls.Add(txtTemp);
this.Controls.Add(btnSend);
}
}
}
```
### 6. ProtocolParser.cs (协议解析器)
```csharp
using System;
using System.Xml.Serialization;
using System.IO;
namespace DataParserApp
{
public class ProtocolParser
{
private Template template;
public event EventHandler<DataEventArgs> DataParsed;
public event EventHandler<FaultEventArgs> FaultDetected;
public ProtocolParser(string rulePath)
{
LoadRules(rulePath);
}
private void LoadRules(string path)
{
if (!File.Exists(path)) return;
var serializer = new XmlSerializer(typeof(Template));
using (var reader = new StreamReader(path))
{
template = (Template)serializer.Deserialize(reader);
}
}
public void Parse(byte[] data)
{
if (data.Length < 2 || template == null) return;
string cmd = data[0].ToString("X2");
string subCmd = data[1].ToString("X2");
if (cmd != template.Command || subCmd != template.SubCommand) return;
ParseData(data);
ParseFlags(data);
}
private void ParseData(byte[] data)
{
foreach (var field in template.Fields)
{
if (field.Offset + GetSize(field.Type) > data.Length) continue;
dynamic value = null;
switch (field.Type.ToLower())
{
case "int16": value = BitConverter.ToInt16(data, field.Offset); break;
case "int32": value = BitConverter.ToInt32(data, field.Offset); break;
case "float": value = BitConverter.ToSingle(data, field.Offset); break;
}
OnDataParsed(new DataEventArgs(field.Name, value * field.Coefficient));
}
}
private void ParseFlags(byte[] data)
{
foreach (var flag in template.Flags)
{
if (flag.Offset >= data.Length) continue;
byte flagByte = data[flag.Offset];
foreach (var bit in flag.Bits)
{
if ((flagByte & (1 << bit.Pos)) != 0)
OnFaultDetected(new FaultEventArgs(bit.Desc));
}
}
}
private int GetSize(string type)
{
switch (type.ToLower())
{
case "int16": return 2;
case "int32": return 4;
case "float": return 4;
default: return 0;
}
}
protected virtual void OnDataParsed(DataEventArgs e)
{
DataParsed?.Invoke(this, e);
}
protected virtual void OnFaultDetected(FaultEventArgs e)
{
FaultDetected?.Invoke(this, e);
}
}
// 数据模型类
[XmlRoot("Template")]
public class Template
{
[XmlAttribute("Command")] public string Command { get; set; }
[XmlAttribute("SubCommand")] public string SubCommand { get; set; }
[XmlArray("Fields"), XmlArrayItem("Field")]
public Field[] Fields { get; set; } = new Field[0];
[XmlArray("Flags"), XmlArrayItem("Flag")]
public Flag[] Flags { get; set; } = new Flag[0];
}
public class Field
{
[XmlAttribute("Name")] public string Name { get; set; }
[XmlAttribute("Offset")] public int Offset { get; set; }
[XmlAttribute("Type")] public string Type { get; set; }
[XmlAttribute("Coefficient")] public float Coefficient { get; set; }
}
public class Flag
{
[XmlAttribute("Name")] public string Name { get; set; }
[XmlAttribute("Offset")] public int Offset { get; set; }
[XmlElement("Bit")] public Bit[] Bits { get; set; } = new Bit[0];
}
public class Bit
{
[XmlAttribute("Pos")] public int Pos { get; set; }
[XmlAttribute("Desc")] public string Desc { get; set; }
}
// 事件参数类
public class DataEventArgs : EventArgs
{
public string Name { get; }
public float Value { get; }
public DataEventArgs(string name, float value)
{
Name = name;
Value = value;
}
}
public class FaultEventArgs : EventArgs
{
public string Description { get; }
public FaultEventArgs(string description)
{
Description = description;
}
}
}
```文本框没有内容显示
最新发布