WinForm版地图上位机 - (第二十二讲)
视频讲解如下:
工程源码下载:GPS定位系统系列教程源码下载
winForm版本的上位机使用了.net4.8的框架,同时集成前面的DbEntity和Link两个类库,开发环境还是VS2022。参考文章:
《百度地图上显示GPS坐标》
《C#环境下使用EF操作MySql》
《如何实现TCP通信》
1、集成事项
winForm的环境如下:

DbEntity和Link两个类库需要新建项目来集成,类型选择如下,依赖库和前面的版本有点不一样,请以工程源码为准,这里就不截图说明了。


集成后的代码如下:

using DbEntity;
using DbEntity.Tables;
using Link;
using System;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Net.Sockets;
using System.Net;
using System.Security.Permissions;
using System.Windows.Forms;
using Link.Sockets;
namespace WindowsFormsApp
{
[PermissionSet(SecurityAction.Demand, Name = "FullTrust")]
[System.Runtime.InteropServices.ComVisibleAttribute(true)]
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
// 这边把脚本错误的压制设置为true.
webBrowser1.ScriptErrorsSuppressed = true;
webBrowser1.DocumentCompleted += WebBrowser1_DocumentCompleted;
}
private void WebBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
// 对WEB浏览器错误的处理
this.webBrowser1.Document.Window.Error += OnWebBrowserDocumentWindowError;
}
private void OnWebBrowserDocumentWindowError(object sender, HtmlElementErrorEventArgs e)
{
e.Handled = true;
}
private void Form1_Load(object sender, EventArgs e)
{
DbInit();// 启动数据库
// index.html文件和可执行文件放在同一目录
// 可以将html目录下的所有文件属性设置成“始终复制”,编译时,系统会自动复制最新的文件到执行目录下
webBrowser1.Url = new Uri(Path.Combine(Application.StartupPath, @"html/index.html"));
webBrowser1.ObjectForScripting = this;
comboBox3.Items.Clear();
comboBox3.Items.Add("127.0.0.1");
comboBox3.Items.Add(GetLocalIP());
comboBox3.SelectedIndex = 0;
}
#region 数据库
/// <summary>
/// 启动数据库
/// </summary>
private void DbInit()
{
try
{
wRes.MyDb = new MyDbContext() { config = wRes.SqlStr };
wRes.MyDb.Database.EnsureCreated();
}
catch (Exception e)
{
MessageBox.Show(e.Message);
}
}
#endregion
#region TCP网络
/// <summary>
/// 启动TCP Server
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void button1_Click(object sender, EventArgs e)
{
if (Link.Res.TSC == null || !Link.Res.TSC.IsOpen())
{
// 定义一个设备
Link.Res.Socs.Add(new Link.Equipment.GpsModel() { equi = 0x01, equino = 1.IntToByte() });
// 启动Socket Server,端口是2233
Link.Res.TSC = new Link.Sockets.TcpSocketServer(comboBox3.Text, int.Parse(textBox1.Text));
Link.Res.TSC.HandleRecMsg = new Link.Equipment.Server().Calculation;
Link.Res.TSC.HandleClientClose = new Link.Equipment.Server().ClientDisconnect;
Link.Res.TSC.StartServer();
// 初始化接收事件
EventInit();
button1.Text = "关闭网络";
button1.BackColor = Color.Red;
}
else
{
Link.Res.TSC.StopServer();
button1.Text = "打开网络";
button1.BackColor = Color.Empty;
}
}
/// <summary>
/// 事件初始化
/// </summary>
private void EventInit()
{
// 保存GPS数据
Link.Res.SenseDataMsg = (dev, a, b, c) =>
{
System.Diagnostics.Debug.WriteLine($"SenseDataMsg 接收到数据:{a},{b},{c}");
// 如果用户不存在,属于非法数据,可以忽略
User user = wRes.MyDb.Tb_User.FirstOrDefault(x => x.ID == a);
if (user == null) return;
// 显示地图
BeginInvoke(new Action(() =>
{
webBrowser1.Document.InvokeScript("WriteLine", new object[] { b, c });
textBox2.Text += $"{b},{c}\r\n";
}));
// 将接收到的数据保存到数据库
using (MyDbContext db = new MyDbContext() { config = wRes.SqlStr })
{
GpsData data = new GpsData()
{
CreateTime = DateTime.Now,
UpdateTime = DateTime.Now,
UserId = user.UserId,
gps = $"{b},{c}"
};
db.Tb_GpsData.Add(data);
db.SaveChanges();
}
};
// 后面可以扩展
/* ... */
}
#endregion
/// <summary>
/// 清除地图
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void button3_Click(object sender, EventArgs e)
{
webBrowser1.Document.InvokeScript("clearAll");
}
/// <summary>
/// 清空日志
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void button5_Click(object sender, EventArgs e)
{
textBox2.Text = "";
}
/// <summary>
/// 主动请求数据
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void button2_Click(object sender, EventArgs e)
{
// 由于初始化的时候,设置的设备类型是1,设备号也是1,所以这边查询的时候也要按这个参数查询
Link.Equipment.GpsModel sense = Link.Res.Socs.FirstOrDefault(v => v.equi == 1 && v.equino.ByteToInt() == 1) as Link.Equipment.GpsModel;
if (sense != null)
{
if (sense.socketstate == 1)
{
// 下发命令,可以带参数,这里用0
int ret = sense.SetState(0);
if (ret == 0) MessageBox.Show("命令发送成功");
if (ret == 1) MessageBox.Show("命令发送失败");
if (ret == -1) MessageBox.Show("网络错误");
}
else MessageBox.Show("设备链接已断开");
}
else MessageBox.Show("未查询到设备");
}
public string GetLocalIP()
{
try
{
string HostName = Dns.GetHostName(); //得到主机名
IPHostEntry IpEntry = Dns.GetHostEntry(HostName);
for (int i = 0; i < IpEntry.AddressList.Length; i++)
{
//从IP地址列表中筛选出IPv4类型的IP地址
//AddressFamily.InterNetwork表示此IP为IPv4,
//AddressFamily.InterNetworkV6表示此地址为IPv6类型
if (IpEntry.AddressList[i].AddressFamily == AddressFamily.InterNetwork)
{
string strip = IpEntry.AddressList[i].ToString();
string[] sArray = strip.Split('.');
if (sArray[3] != "1")
return IpEntry.AddressList[i].ToString();
}
}
return "";
}
catch (Exception ex)
{
return "";
}
}
}
}
2、最终演示效果
