using System;
using System.IO;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;
using System.Threading.Tasks;
namespace JoyD.Windows.CS.Toprie
{
public partial class Camera : UserControl
{
// 设备管理器实例
private DeviceManager _deviceManager;
// 是否正在接收图像
private bool _isReceivingImage = false;
// 全局图像缓冲区bitmap,用于在其上绘制图像和mask信息
private Bitmap _imageBuffer = null;
private const int BUFFER_WIDTH = 512;
private const int BUFFER_HEIGHT = 384;
// 最后接收的图像
private Image _lastImage = null;
// 信息图像,用于显示额外信息
private Image _infoImage = null;
// 用于保护_lastImage的线程锁
private readonly object _lastImageLock = new object();
// 用于保护_infoImage的线程锁
private readonly object _infoImageLock = new object();
// 是否显示信息图像
private bool _isDisplayingInfo = false;
// 项目路径,用于数据文件的存取
private string _projectPath = "";
///
/// 获取或设置项目路径,控件所需的数据文件将在此目录中进行存取
///
[Category("配置")]
[Description("设置项目路径,控件所需的数据文件将在此目录中进行存取")]
[DefaultValue("")]
public string ProjectPath
{
get { return _projectPath; }
set
{
// 只有当值发生变化时才进行同步
if (_projectPath != value)
{
_projectPath = value;
// 如果DeviceManager已经初始化,则同步更新其ProjectPath属性
if (_deviceManager != null)
{
_deviceManager.ProjectPath = _projectPath;
}
}
}
}
// 显示错误的定时器
///
/// 更新设计模式状态到DeviceManager
///
private void UpdateDesignModeStatus()
{
DeviceManager.IsDesignMode = DesignMode;
Console.WriteLine($"相机控件设计模式状态已更新: {DesignMode}");
}
///
/// 更新InfoImage显示
/// 1. 如果暂停,显示暂停信息
/// 2. 否则如果Ping不通或断开,显示重连信息
/// 3. 否则清空InfoImage
/// 4. 最后调用更新UI
///
private void UpdateInfo()
{
// 更新Ping状态到Info文本
Console.WriteLine($"Ping状态更新: {(IsDevicePingable ? "可Ping通" : "不可Ping通")}");
if (DesignMode) return;
try
{
lock (_infoImageLock)
{
// 检查连接状态
bool isDisconnected = _deviceManager != null && _deviceManager.ConnectionStatus == ConnectionStatus.Disconnected;
bool isReconnecting = _deviceManager != null && _deviceManager.ConnectionStatus == ConnectionStatus.Reconnecting;
bool isPaused = _isPaused; // 使用_isPaused标志判断暂停状态
bool isPingFailed = !IsDevicePingable;
// 根据用户要求的优先级显示信息:先检查暂停状态,然后再检查Ping状态和连接状态
if (isPaused)
{
// 暂停状态 - 最高优先级
using (Graphics g = Graphics.FromImage(_infoImage))
{
// 设置半透明背景
using (SolidBrush brush = new SolidBrush(Color.FromArgb(128, Color.Black)))
{
g.FillRectangle(brush, 0, 0, BUFFER_WIDTH, BUFFER_HEIGHT);
}
// 绘制暂停文本
string text = "暂停";
Color textColor = Color.Red;
using (Font font = new Font("Arial", 48, FontStyle.Bold))
using (SolidBrush textBrush = new SolidBrush(textColor))
{
StringFormat format = new StringFormat();
format.Alignment = StringAlignment.Center;
// 将主文本居中显示
g.DrawString(text, font, textBrush,
new RectangleF(0, BUFFER_HEIGHT / 3, BUFFER_WIDTH, BUFFER_HEIGHT / 3),
format);
}
}
}
else if (isPingFailed || isDisconnected || isReconnecting)
{
// 非暂停状态下,检查Ping状态和连接状态
using (Graphics g = Graphics.FromImage(_infoImage))
{
// 设置半透明背景
using (SolidBrush brush = new SolidBrush(Color.FromArgb(128, Color.Black)))
{
g.FillRectangle(brush, 0, 0, BUFFER_WIDTH, BUFFER_HEIGHT);
}
// 确定显示的文本和颜色
string text = "";
Color textColor = Color.White;
if (isReconnecting)
{
text = "正在重连...";
textColor = Color.Yellow;
}
else if (isDisconnected)
{
text = "连接断开";
textColor = Color.Red;
}
else if (isPingFailed)
{
text = "连接断开";
textColor = Color.Red;
}
// 绘制文本
using (Font font = new Font("Arial", 48, FontStyle.Bold))
using (SolidBrush textBrush = new SolidBrush(textColor))
{
StringFormat format = new StringFormat();
format.Alignment = StringAlignment.Center;
// 将主文本居中显示
g.DrawString(text, font, textBrush,
new RectangleF(0, BUFFER_HEIGHT / 3, BUFFER_WIDTH, BUFFER_HEIGHT / 3),
format);
}
}
}
// 否则清空InfoImage(已在开头处理)
// 设置显示标志
_isDisplayingInfo = (isPaused || isDisconnected || isReconnecting);
}
// 调用更新UI
UpdateImageOnUI();
}
catch (Exception ex)
{
Console.WriteLine($"更新Info显示时出错: {ex.Message}");
}
}
///
/// 暂停/恢复检测菜单项点击事件处理
/// 1、暂停或恢复时,设置暂停状态,调用更新Info
///
private void PauseDetectionToolStripMenuItem_Click(object sender, EventArgs e)
{
if (DesignMode) return;
try
{
// 切换暂停状态
_isPaused = !_isPaused;
if (_isPaused)
{
// 设置暂停状态
pauseDetectionToolStripMenuItem.Text = "恢复检测";
// 暂停时停止图像接收并更新DeviceManager的暂停检测状态
if (_deviceManager != null)
{
_deviceManager.IsDetectionPaused = true;
if (_isReceivingImage)
{
_deviceManager.StopImageReceiving();
_isReceivingImage = false;
}
}
Console.WriteLine("检测已暂停");
}
else
{
// 设置恢复状态
pauseDetectionToolStripMenuItem.Text = "暂停检测";
// 恢复时更新DeviceManager的暂停检测状态并重新开始图像接收
if (_deviceManager != null)
{
_deviceManager.IsDetectionPaused = false;
if (_deviceManager.ConnectionStatus == ConnectionStatus.Connected)
{
_deviceManager.StopImageReceiving();
_deviceManager.StartImageReceiving();
_isReceivingImage = true;
// 恢复检测后,启动连接检查以确保连接正常
_deviceManager.StartConnectionCheck();
}
// 如果当前是断开状态但启用了自动重连,尝试启动重连
else if (_deviceManager.AutoReconnectEnabled)
{
_deviceManager.StartAutoReconnect();
}
}
Console.WriteLine("检测已恢复");
}
// 按照用户要求:暂停或恢复时,设置暂停状态,调用更新Info
UpdateInfo();
}
catch (Exception ex)
{
Console.WriteLine($"处理暂停/恢复检测时出错: {ex.Message}");
}
}
public Camera()
{
InitializeComponent();
// 为右键菜单添加Opening事件,用于在菜单显示前更新色彩模式的选中状态
this.contextMenuStrip1.Opening += ContextMenuStrip1_Opening;
// 将设计模式状态传递给DeviceManager
UpdateDesignModeStatus();
// 初始化图像缓冲区
InitializeImageBuffer();
// 初始化Ping定时器
_pingTimer = new System.Threading.Timer(PingTimer_Tick, null, Timeout.Infinite, Timeout.Infinite);
// 只有在非设计模式下才初始化设备管理器和错误定时器
if (!DesignMode)
{
// 清空现有日志
try
{
string logFile = Path.Combine(Application.StartupPath, "log.txt");
// 确保日志文件目录存在
string logDir = Path.GetDirectoryName(logFile);
if (!Directory.Exists(logDir))
{
Directory.CreateDirectory(logDir);
}
if (File.Exists(logFile))
{
File.WriteAllText(logFile, string.Empty);
}
}
catch { }
InitializeDeviceManager();
}
}
///
/// Camera控件加载事件
/// 在控件加载时自动启动相机显示热图
///
private void Camera_Load(object sender, EventArgs e)
{
// 只有在非设计模式下才启动相机
if (!DesignMode)
{
try
{
StartCamera();
}
catch (Exception ex)
{
ShowError($"自动启动相机失败: {ex.Message}");
}
}
}
// 注意:UserControl不支持FormClosing事件,资源清理已在Dispose方法中处理
///
/// 初始化设备管理器
///
private void InitializeDeviceManager()
{
// 只有在非设计模式下才初始化设备管理器
if (!DesignMode)
{
_deviceManager = new DeviceManager
{
AutoReconnectEnabled = true,
ReconnectInterval = 2000, // 2秒
ProjectPath = !string.IsNullOrEmpty(ProjectPath) ? ProjectPath : Application.StartupPath
};
// 设置静态属性
DeviceManager.MaxReconnectAttempts = 5;
// 注册图像接收事件
_deviceManager.ImageReceived += DeviceManager_ImageReceived;
// 注册连接状态变更事件
_deviceManager.ConnectionStatusChanged += DeviceManager_ConnectionStatusChanged;
// 注册连接异常事件
_deviceManager.ConnectionException += DeviceManager_ConnectionException;
}
}
///
/// 初始化图像缓冲区和相关图像资源
///
private void InitializeImageBuffer()
{
try
{
// 创建512*384大小的透明bitmap作为图像缓冲区
_imageBuffer = new Bitmap(BUFFER_WIDTH, BUFFER_HEIGHT);
Console.WriteLine($"图像缓冲区已初始化: {BUFFER_WIDTH}x{BUFFER_HEIGHT}");
// 初始化缓冲区为透明背景
using (Graphics g = Graphics.FromImage(_imageBuffer))
{
g.Clear(Color.Transparent);
}
// 初始化InfoImage为透明bitmap
lock (_infoImageLock)
{
_infoImage = new Bitmap(BUFFER_WIDTH, BUFFER_HEIGHT);
using (Graphics g = Graphics.FromImage(_infoImage))
{
g.Clear(Color.Transparent);
}
Console.WriteLine("InfoImage已初始化为透明bitmap");
}
// 初始化图像框的bitmap为透明
if (imageBox != null && !imageBox.IsDisposed)
{
imageBox.Image = new Bitmap(BUFFER_WIDTH, BUFFER_HEIGHT);
using (Graphics g = Graphics.FromImage(imageBox.Image))
{
g.Clear(Color.Transparent);
}
Console.WriteLine("图像框bitmap已初始化为透明");
}
}
catch (Exception ex)
{
Console.WriteLine($"初始化图像资源失败: {ex.Message}");
// 发生异常时释放已创建的资源
if (_imageBuffer != null)
{
_imageBuffer.Dispose();
_imageBuffer = null;
}
lock (_infoImageLock)
{
if (_infoImage != null)
{
_infoImage.Dispose();
_infoImage = null;
}
}
}
}
///
/// 启动相机
///
public void StartCamera()
{
// 启动设备Ping
StartDevicePing();
if (DesignMode) return;
try
{
// 只有在没有接收图像时才启动
if (!_isReceivingImage)
{
// 清理错误显示
ShowError(string.Empty);
// 使用异步方式连接设备和设置模式,避免UI线程阻塞
ThreadPool.QueueUserWorkItem(delegate
{
try
{
// 设置为热图模式
bool modeSet = false;
// 启用自动重连
_deviceManager.AutoReconnectEnabled = true;
// 尝试连接设备
if (_deviceManager.ConnectDevice())
{
Console.WriteLine("设备连接成功");
// 如果热图模式未成功设置,在连接成功后再次尝试
if (!modeSet)
{
try
{
_deviceManager.SetImageMode(ImageMode.Infrared);
Console.WriteLine("连接后已设置热图模式");
}
catch (Exception ex)
{
Console.WriteLine($"连接后设置热图模式失败: {ex.Message}");
}
}
// 在连接成功后开始接收图像
this.Invoke(new Action(() =>
{
// 再次检查是否已在UI线程设置为接收状态
if (!_isReceivingImage)
{
StartReceiveImage();
}
}));
}
else
{
// 连接失败时显示错误
string errorMsg = "设备连接失败,请检查设备状态或网络连接";
this.Invoke(new Action(() => ShowError(errorMsg)));
Console.WriteLine(errorMsg);
}
}
catch (Exception ex)
{
// 捕获所有异常,防止后台线程崩溃
string errorMsg = $"启动相机异常: {ex.Message}";
this.Invoke(new Action(() => ShowError(errorMsg)));
Console.WriteLine(errorMsg);
Console.WriteLine(ex.StackTrace);
}
});
Console.WriteLine("相机启动流程已开始");
}
else
{
Console.WriteLine("相机已在运行状态");
}
}
catch (Exception ex)
{
ShowError($"启动相机失败: {ex.Message}");
Console.WriteLine($"启动相机主流程错误: {ex.Message}");
Console.WriteLine(ex.StackTrace);
}
}
///
/// 开始接收图像(使用HTTP方式)
///
private void StartReceiveImage()
{
if (DesignMode) return;
try
{
if (!_isReceivingImage && _deviceManager.ConnectionStatus == ConnectionStatus.Connected)
{
Console.WriteLine("Camera开始使用HTTP方式接收图像");
// 直接调用HTTP方式的图像接收
_deviceManager.StartImageReceiving();
_isReceivingImage = true;
}
}
catch (Exception ex)
{
ShowError($"开始接收图像失败: {ex.Message}");
}
}
///
/// 停止接收图像
///
public void StopCamera()
{
// 停止设备Ping
StopDevicePing();
if (DesignMode) return;
try
{
if (_isReceivingImage)
{
_deviceManager.StopReceiveImage();
_isReceivingImage = false;
}
}
catch (Exception ex)
{
Console.WriteLine($"停止相机失败: {ex.Message}");
}
}
private bool _isPaused = false; // 暂停状态标志
// Ping相关字段
private System.Threading.Timer _pingTimer;
private bool _isDevicePingable = false;
private const int _pingInterval = 500; // 0.5秒Ping一次
///
/// 获取设备是否可Ping通
///
public bool IsDevicePingable
{
get { return _isDevicePingable; }
private set
{
if (_isDevicePingable != value)
{
_isDevicePingable = value;
Console.WriteLine($"设备Ping状态变更: {(_isDevicePingable ? "可Ping通" : "不可Ping通")}");
// 状态变化时调用更新Info
UpdateInfo();
}
}
}
///
/// 设备管理器图像接收事件处理
///
private void DeviceManager_ImageReceived(object sender, ImageReceivedEventArgs e)
{
if (DesignMode) return;
try
{
if (e.ImageData != null && e.ImageData.Length > 0)
{
// 创建内存流并从流中创建图像
using (MemoryStream ms = new MemoryStream(e.ImageData))
{
// 检查流是否可读且有效
if (ms.CanRead && ms.Length > 0)
{
// 从流中创建图像
using (Image tempImage = System.Drawing.Image.FromStream(ms))
{
// 创建一个全新的位图而仅仅是克隆,确保数据完整性
Image newImage = new Bitmap(tempImage);
// 立即验证新创建的图像是否有效
try
{
// 访问Width和Height属性来验证图像是否有效
int width = newImage.Width;
int height = newImage.Height;
if (width <= 0 || height <= 0)
{
Console.WriteLine("创建的图像尺寸无效");
newImage.Dispose();
return;
}
}
catch (Exception)
{
Console.WriteLine("创建的图像无效");
newImage.Dispose();
return;
}
// 按照用户要求:收到图像数据后,将图像保存到LastImage中
// 不释放旧的LastImage,仅在控件Dispose时释放
lock (_lastImageLock)
{
// 如果是第一次设置LastImage,直接赋值
if (_lastImage == null)
{
_lastImage = newImage;
}
else
{
// 后续更新时,使用临时变量保存新图像,然后替换引用
Image temp = newImage;
newImage = _lastImage;
_lastImage = temp;
// 注意:这里不Dispose旧图像,只在控件Dispose时统一释放
}
}
// 按照用户要求:调用更新到UI
// 只有当图像更新未暂停时才更新UI
if (!_isPaused)
{
this.BeginInvoke(new Action(() =>
{
try
{
UpdateImageOnUI();
}
catch (Exception ex)
{
Console.WriteLine($"更新UI图像失败: {ex.Message}");
}
}));
}
}
}
}
}
}
catch (Exception ex)
{
Console.WriteLine($"处理接收到的图像时出错: {ex.Message}");
}
}
///
/// 在UI线程上更新图像 - 新实现,按照用户要求:
/// 1. 先将LastImage绘制到全局缓冲
/// 2. 再将InfoImage绘制到缓冲
/// 3. 最后一次性绘制到图像框的bitmap
///
private void UpdateImageOnUI()
{
if (DesignMode) return;
// 线程安全检查 - 确保在UI线程上执行
if (this.InvokeRequired)
{
try
{
this.BeginInvoke(new Action(UpdateImageOnUI));
}
catch (ObjectDisposedException)
{
Console.WriteLine("控件已释放,跳过UI更新");
}
return;
}
// 一次性控件有效性检查,避免重复检查
if (this.IsDisposed || imageBox == null || imageBox.IsDisposed)
{
Console.WriteLine("控件已释放,无法更新图像");
return;
}
Image lastImage = null;
Image infoImage = null;
Image oldImage = null;
Bitmap displayImage = null;
try
{
// 检查图像缓冲区是否有效
if (_imageBuffer == null)
{
Console.WriteLine("图像缓冲区未初始化,尝试重新初始化");
InitializeImageBuffer();
if (_imageBuffer == null)
{
Console.WriteLine("重新初始化图像缓冲区失败");
return;
}
}
// 保存旧图像引用,以便在设置新图像后释放
oldImage = imageBox.Image;
// 获取当前的LastImage引用
lock (_lastImageLock)
{
if (_lastImage != null)
{
lastImage = (Image)_lastImage.Clone();
}
}
// 获取当前的InfoImage引用
lock (_infoImageLock)
{
if (_infoImage != null)
{
infoImage = (Image)_infoImage.Clone();
}
}
// 合并锁定,减少锁的数量,提高性能
lock (_imageBuffer)
{
using (Graphics g = Graphics.FromImage(_imageBuffer))
{
// 清除缓冲区背景为透明色
g.Clear(Color.Transparent);
// 步骤1:先将LastImage绘制到全局缓冲
if (lastImage != null)
{
// 保持原始图像比例,居中显示
float scale = Math.Min((float)BUFFER_WIDTH / lastImage.Width, (float)BUFFER_HEIGHT / lastImage.Height);
int scaledWidth = (int)(lastImage.Width * scale);
int scaledHeight = (int)(lastImage.Height * scale);
int x = (BUFFER_WIDTH - scaledWidth) / 2;
int y = (BUFFER_HEIGHT - scaledHeight) / 2;
g.DrawImage(lastImage, x, y, scaledWidth, scaledHeight);
}
// 步骤2:再将InfoImage绘制到缓冲
if (infoImage != null)
{
g.DrawImage(infoImage, 0, 0);
}
else if (_isDisplayingInfo)
{
// 如果没有InfoImage但需要显示信息,则绘制默认信息
using (Font font = new Font("微软雅黑", 12, FontStyle.Bold))
using (Brush textBrush = new SolidBrush(Color.Red))
{
g.DrawString("测试信息", font, textBrush, 10, 10);
}
}
}
// 在同一个锁内创建缓冲区的副本,避免重复锁定
displayImage = (Bitmap)_imageBuffer.Clone();
}
// 将全局缓冲一次性绘制到图像框的bitmap
imageBox.Image = displayImage;
if (lastImage != null)
{
Console.WriteLine($"图像更新成功: {lastImage.Width}x{lastImage.Height}");
}
}
catch (ArgumentException ex) when (ex.Message.Contains("参数无效"))
{
// 特别处理"参数无效"异常
Console.WriteLine($"图像参数无效异常: {ex.Message}");
// 尝试设置旧图像回来,不需要再次检查控件状态(已在方法开始处检查)
if (oldImage != null)
{
try
{
imageBox.Image = oldImage;
}
catch
{
// 如果设置旧图像也失败,释放它
DisposeImage(oldImage);
}
}
}
catch (Exception ex)
{
Console.WriteLine($"更新图像UI异常: {ex.Message}");
}
finally
{
// 确保在任何情况下都释放资源
DisposeImage(lastImage);
DisposeImage(infoImage);
// 只有当旧图像不再被使用时才释放
if (oldImage != null && oldImage != imageBox.Image)
{
DisposeImage(oldImage);
}
}
}
///
/// 安全释放图像资源的辅助方法
///
private void DisposeImage(Image image)
{
if (image != null)
{
try { image.Dispose(); } catch { }
}
}
///
/// 设备管理器连接状态变更事件处理
///
private void DeviceManager_ConnectionStatusChanged(object sender, ConnectionStatusChangedEventArgs e)
{
if (DesignMode) return;
// 参数验证
if (e == null)
{
Console.WriteLine($"[{DateTime.Now:HH:mm:ss.fff}] 警告: 接收到空的连接状态变更事件参数");
return;
}
Console.WriteLine($"[{DateTime.Now:HH:mm:ss.fff}] [线程:{Thread.CurrentThread.ManagedThreadId}] 接收连接状态变更事件: {e.Status}");
// 捕获所有可能的异常,确保事件处理器不会崩溃
try
{
// 首先检查控件状态
if (this.IsDisposed || this.Disposing)
{
Console.WriteLine($"[{DateTime.Now:HH:mm:ss.fff}] 控件已释放或正在释放,跳过UI更新");
return;
}
// 检查事件参数中的状态信息
string statusMessage = $"连接状态变更为: {e.Status}";
if (!string.IsNullOrEmpty(e.DeviceInfo))
{
statusMessage += $" (设备信息: {e.DeviceInfo})";
}
// 线程安全处理 - 确保在UI线程上更新
if (this.InvokeRequired)
{
try
{
// 使用BeginInvoke代替Invoke,避免可能的死锁问题
this.BeginInvoke(new Action(args =>
{
// 再次检查控件状态,防止在异步调用期间控件被释放
if (!this.IsDisposed && !this.Disposing)
{
HandleConnectionStatusChanged(args);
}
else
{
Console.WriteLine($"[{DateTime.Now:HH:mm:ss.fff}] 异步调用期间控件已释放,跳过处理");
}
}), e);
}
catch (ObjectDisposedException ode)
{
// 捕获控件已释放异常,避免程序崩溃
Console.WriteLine($"[{DateTime.Now:HH:mm:ss.fff}] 控件已释放,无法进行UI线程调用: {ode.Message}");
}
catch (InvalidOperationException ioe)
{
// 捕获无效操作异常,通常发生在控件状态异常时
Console.WriteLine($"[{DateTime.Now:HH:mm:ss.fff}] UI线程调用无效: {ioe.Message}");
}
}
else
{
// 直接在UI线程上处理
HandleConnectionStatusChanged(e);
}
}
catch (Exception ex)
{
// 捕获所有其他异常,记录并继续
Console.WriteLine($"[{DateTime.Now:HH:mm:ss.fff}] 处理连接状态变更事件异常: {ex.Message}\n{ex.StackTrace}");
}
}
///
/// 处理连接状态变更
/// 2、断开或连接时,设置连接状态,调用更新Info
///
private void HandleConnectionStatusChanged(ConnectionStatusChangedEventArgs e)
{
if (DesignMode) return;
try
{
// 确保在UI线程上更新UI状态
if (this.InvokeRequired)
{
this.Invoke(new Action(HandleConnectionStatusChanged), e);
return;
}
// 更新UI状态
UpdateUIState(e.Status == ConnectionStatus.Connected);
// 检查_deviceManager是否为空
if (_deviceManager == null)
{
Console.WriteLine("设备管理器未初始化");
return;
}
switch (e.Status)
{
case ConnectionStatus.Connected:
Console.WriteLine("设备已连接");
// 仅在首次连接时设置为热图模式,重连时保留之前的模式
if (!_isReceivingImage) // 首次连接时_isReceivingImage为false
{
try
{
_deviceManager.SetImageMode(ImageMode.Infrared);
Console.WriteLine("首次连接,设置热图模式");
}
catch (Exception ex)
{
Console.WriteLine($"设置热图模式失败: {ex.Message}");
}
}
else
{
Console.WriteLine("重连成功,保留当前图像模式");
}
// 注意:色彩模式同步现在在DeviceManager内部的连接成功处理中自动完成
// 无需在此处重复调用
// 开始接收图像(包含在try-catch中)
if (!_isReceivingImage)
{
try
{
StartReceiveImage();
}
catch (Exception ex)
{
Console.WriteLine($"开始接收图像失败: {ex.Message}");
}
}
// 设置连接状态后,调用更新Info
UpdateInfo();
break;
case ConnectionStatus.Disconnected:
Console.WriteLine("设备已断开连接");
// 停止接收图像(添加空检查和异常处理)
if (_isReceivingImage)
{
try
{
_deviceManager.StopReceiveImage();
_isReceivingImage = false;
}
catch (Exception ex)
{
Console.WriteLine($"停止接收图像失败: {ex.Message}");
_isReceivingImage = false; // 确保状态更新
}
}
// 设置连接状态后,调用更新Info
UpdateInfo();
if (!string.IsNullOrEmpty(e.DeviceInfo))
{
ShowError(e.DeviceInfo);
}
else
{
ShowError("设备连接已断开");
}
break;
case ConnectionStatus.Connecting:
Console.WriteLine($"正在连接设备...{(!string.IsNullOrEmpty(e.DeviceInfo) ? " " + e.DeviceInfo : "")}");
ShowError(string.Empty); // 清除之前的错误信息
break;
case ConnectionStatus.Reconnecting:
Console.WriteLine($"正在重新连接设备...{(!string.IsNullOrEmpty(e.DeviceInfo) ? " " + e.DeviceInfo : "")}");
ShowError(string.Empty); // 清除之前的错误信息
// 设置重连状态后,调用更新Info
UpdateInfo();
break;
}
}
catch (Exception ex)
{
Console.WriteLine($"处理连接状态变更时发生错误: {ex.Message}");
// 避免在异常处理中再次引起异常
try
{
ShowError($"连接状态处理错误: {ex.Message}");
}
catch
{}
}
}
///
/// 更新UI状态
///
/// 是否已连接
private void UpdateUIState(bool isConnected)
{
if (DesignMode) return;
try
{
// 根据连接状态更新图像框状态
if (imageBox != null && !imageBox.IsDisposed)
{
if (isConnected)
{
imageBox.BorderStyle = BorderStyle.FixedSingle;
}
else
{
imageBox.BorderStyle = BorderStyle.Fixed3D;
}
}
// 更新图像框的边框颜色,提供视觉反馈
if (imageBox != null)
{
imageBox.BorderStyle = isConnected ? BorderStyle.FixedSingle : BorderStyle.Fixed3D;
// 可选:设置不同的边框颜色以提供更好的视觉反馈
if (isConnected)
{
imageBox.BackColor = Color.LightGreen;
}
else
{
imageBox.BackColor = Color.LightGray;
}
}
Console.WriteLine($"UI状态已更新为: {(isConnected ? "已连接" : "未连接")}");
}
catch (Exception ex)
{
Console.WriteLine($"更新UI状态时出错: {ex.Message}");
}
}
///
/// 设备管理器连接异常事件处理
///
private void DeviceManager_ConnectionException(object sender, ConnectionExceptionEventArgs e)
{
if (DesignMode) return;
// 参数验证
if (e == null)
{
Console.WriteLine($"[{DateTime.Now:HH:mm:ss.fff}] 警告: 接收到空的连接异常事件参数");
return;
}
// 记录详细的异常信息,但避免在UI线程上执行耗时操作
string exceptionMessage = e.Exception != null ? e.Exception.Message : "无详细异常信息";
string stackTrace = e.Exception != null ? e.Exception.StackTrace : "无堆栈信息";
Console.WriteLine($"[{DateTime.Now:HH:mm:ss.fff}] [线程:{Thread.CurrentThread.ManagedThreadId}] 接收连接异常事件: {e.Message}\n{exceptionMessage}\n{stackTrace}");
// 捕获所有可能的异常,确保异常处理不会导致程序崩溃
try
{
// 首先检查控件状态
if (this.IsDisposed || this.Disposing)
{
Console.WriteLine($"[{DateTime.Now:HH:mm:ss.fff}] 控件已释放或正在释放,跳过异常显示");
return;
}
// 创建用于UI显示的错误消息
string uiErrorMessage = $"连接异常: {e.Message}";
if (string.IsNullOrEmpty(e.Message) && e.Exception != null)
{
uiErrorMessage = $"连接异常: {exceptionMessage}";
}
// 线程安全处理 - 确保在UI线程上更新
if (this.InvokeRequired)
{
try
{
// 创建局部变量保存错误消息,避免闭包问题
string errorMsg = uiErrorMessage;
// 使用BeginInvoke代替Invoke,避免可能的死锁问题
this.BeginInvoke(new Action(() =>
{
// 再次检查控件状态,防止在异步调用期间控件被释放
if (!this.IsDisposed && !this.Disposing)
{
try
{
ShowError(errorMsg);
}
catch (Exception showEx)
{
Console.WriteLine($"[{DateTime.Now:HH:mm:ss.fff}] 显示错误消息异常: {showEx.Message}");
}
}
else
{
Console.WriteLine($"[{DateTime.Now:HH:mm:ss.fff}] 异步调用期间控件已释放,跳过错误显示");
}
}));
}
catch (ObjectDisposedException ode)
{
// 捕获控件已释放异常,避免程序崩溃
Console.WriteLine($"[{DateTime.Now:HH:mm:ss.fff}] 控件已释放,无法进行UI线程调用: {ode.Message}");
}
catch (InvalidOperationException ioe)
{
// 捕获无效操作异常,通常发生在控件状态异常时
Console.WriteLine($"[{DateTime.Now:HH:mm:ss.fff}] UI线程调用无效: {ioe.Message}");
}
}
else
{
// 直接在UI线程上处理
try
{
ShowError(uiErrorMessage);
}
catch (Exception showEx)
{
Console.WriteLine($"[{DateTime.Now:HH:mm:ss.fff}] 显示错误消息异常: {showEx.Message}");
}
}
}
catch (Exception ex)
{
// 捕获所有其他异常,记录并继续
Console.WriteLine($"[{DateTime.Now:HH:mm:ss.fff}] 处理连接异常事件异常: {ex.Message}\n{ex.StackTrace}");
}
}
///
/// 显示错误信息
///
private void ShowError(string message)
{
if (DesignMode) return;
Console.WriteLine(message);
// 错误消息仅写入日志即可,不需要在UI上显示
}
///
/// 右键菜单显示前的事件处理方法
/// 用于更新色彩模式菜单项的选中状态
///
///
/// 右键菜单打开事件处理
///
private void ContextMenuStrip1_Opening(object sender, System.ComponentModel.CancelEventArgs e)
{
// 暂停菜单项的文本已经在点击事件中更新,这里无需再次更新
if (DesignMode) return;
try
{
// 检查是否处于暂停状态
bool isPaused = pauseDetectionToolStripMenuItem.Text == "恢复检测";
// 在暂停状态下,隐藏图像模式根菜单和色彩模式菜单
// 注意:根菜单隐藏后,其所有子菜单会自动隐藏,不需要单独设置
if (isPaused)
{
// 隐藏图像模式根菜单
if (imageModeToolStripMenuItem != null)
imageModeToolStripMenuItem.Visible = false;
// 隐藏色彩模式菜单
colorModeToolStripMenuItem.Visible = false;
// 当只有一个菜单项可见时,隐藏分隔符
toolStripSeparator1.Visible = false;
}
else
{
// 在非暂停状态下,显示图像模式根菜单
// 注意:根菜单显示后,其所有子菜单会自动显示,不需要单独设置
if (imageModeToolStripMenuItem != null)
imageModeToolStripMenuItem.Visible = true;
// 在非暂停状态下,显示分隔符
toolStripSeparator1.Visible = true;
// 根据当前图像模式控制色彩模式菜单的可见性
if (_deviceManager != null)
{
colorModeToolStripMenuItem.Visible = _deviceManager.CurrentImageMode == ImageMode.Infrared;
}
// 清除视频模式菜单项的选中状态
thermalModeToolStripMenuItem.Checked = false;
visibleModeToolStripMenuItem.Checked = false;
fusionMode1ToolStripMenuItem.Checked = false;
fusionMode2ToolStripMenuItem.Checked = false;
fusionMode3ToolStripMenuItem.Checked = false;
fusionMode4ToolStripMenuItem.Checked = false;
fusionMode5ToolStripMenuItem.Checked = false;
// 清除色彩模式菜单项的选中状态
whiteHotToolStripMenuItem.Checked = false;
blackHotToolStripMenuItem.Checked = false;
ironRedToolStripMenuItem.Checked = false;
lavaToolStripMenuItem.Checked = false;
rainbowToolStripMenuItem.Checked = false;
ironGrayToolStripMenuItem.Checked = false;
redHotToolStripMenuItem.Checked = false;
rainbow2ToolStripMenuItem.Checked = false;
// 尝试获取当前色彩模式并更新对应菜单项的选中状态
if (_deviceManager != null && _deviceManager.ConnectionStatus == ConnectionStatus.Connected)
{
try
{
// 获取当前色彩模式
PaletteType currentPalette = _deviceManager.CurrentPaletteType;
// 根据当前色彩模式设置对应菜单项的选中状态
switch (currentPalette)
{
case PaletteType.WhiteHot:
whiteHotToolStripMenuItem.Checked = true;
break;
case PaletteType.BlackHot:
blackHotToolStripMenuItem.Checked = true;
break;
case PaletteType.IronRed:
ironRedToolStripMenuItem.Checked = true;
break;
case PaletteType.Lava:
lavaToolStripMenuItem.Checked = true;
break;
case PaletteType.Rainbow:
rainbowToolStripMenuItem.Checked = true;
break;
case PaletteType.IronGray:
ironGrayToolStripMenuItem.Checked = true;
break;
case PaletteType.RedHot:
redHotToolStripMenuItem.Checked = true;
break;
case PaletteType.Rainbow2:
rainbow2ToolStripMenuItem.Checked = true;
break;
}
}
catch (Exception ex)
{
Console.WriteLine($"获取当前色彩模式失败: {ex.Message}");
}
// 更新视频模式菜单项的选中状态
try
{
// 更改为使用ImageMode枚举
var currentImageMode = _deviceManager.CurrentImageMode;
thermalModeToolStripMenuItem.Checked = currentImageMode == ImageMode.Infrared;
visibleModeToolStripMenuItem.Checked = currentImageMode == ImageMode.Natural;
}
catch (Exception ex)
{
Console.WriteLine($"获取当前图像模式失败: {ex.Message}");
}
}
}
}
catch (Exception ex)
{
Console.WriteLine($"更新右键菜单选中状态失败: {ex.Message}");
}
}
#region 色彩模式切换方法
///
/// 白热色彩模式
///
private void WhiteHotToolStripMenuItem_Click(object sender, EventArgs e)
{
try
{
if (_deviceManager != null)
{
Console.WriteLine("切换到白热色彩模式");
_deviceManager.SetPaletteType(PaletteType.WhiteHot);
}
}
catch (Exception ex)
{
Console.WriteLine($"切换到白热色彩模式失败: {ex.Message}");
}
}
///
/// 黑热色彩模式
///
private void BlackHotToolStripMenuItem_Click(object sender, EventArgs e)
{
try
{
if (_deviceManager != null)
{
Console.WriteLine("切换到黑热色彩模式");
_deviceManager.SetPaletteType(PaletteType.BlackHot);
}
}
catch (Exception ex)
{
Console.WriteLine($"切换到黑热色彩模式失败: {ex.Message}");
}
}
///
/// 铁红色彩模式
///
private void IronRedToolStripMenuItem_Click(object sender, EventArgs e)
{
try
{
if (_deviceManager != null)
{
Console.WriteLine("切换到铁红色彩模式");
_deviceManager.SetPaletteType(PaletteType.IronRed);
}
}
catch (Exception ex)
{
Console.WriteLine($"切换到铁红色彩模式失败: {ex.Message}");
}
}
///
/// 熔岩色彩模式
///
private void LavaToolStripMenuItem_Click(object sender, EventArgs e)
{
try
{
if (_deviceManager != null)
{
Console.WriteLine("切换到熔岩色彩模式");
_deviceManager.SetPaletteType(PaletteType.Lava);
}
}
catch (Exception ex)
{
Console.WriteLine($"切换到熔岩色彩模式失败: {ex.Message}");
}
}
///
/// 彩虹色彩模式
///
private void RainbowToolStripMenuItem_Click(object sender, EventArgs e)
{
try
{
if (_deviceManager != null)
{
Console.WriteLine("切换到彩虹色彩模式");
_deviceManager.SetPaletteType(PaletteType.Rainbow);
}
}
catch (Exception ex)
{
Console.WriteLine($"切换到彩虹色彩模式失败: {ex.Message}");
}
}
///
/// 铁灰色彩模式
///
private void IronGrayToolStripMenuItem_Click(object sender, EventArgs e)
{
try
{
if (_deviceManager != null)
{
Console.WriteLine("切换到铁灰色彩模式");
_deviceManager.SetPaletteType(PaletteType.IronGray);
}
}
catch (Exception ex)
{
Console.WriteLine($"切换到铁灰色彩模式失败: {ex.Message}");
}
}
///
/// 红热色彩模式
///
private void RedHotToolStripMenuItem_Click(object sender, EventArgs e)
{
try
{
if (_deviceManager != null)
{
Console.WriteLine("切换到红热色彩模式");
_deviceManager.SetPaletteType(PaletteType.RedHot);
}
}
catch (Exception ex)
{
Console.WriteLine($"切换到红热色彩模式失败: {ex.Message}");
}
}
///
/// 彩虹2色彩模式
///
private void Rainbow2ToolStripMenuItem_Click(object sender, EventArgs e)
{
try
{
if (_deviceManager != null)
{
Console.WriteLine("切换到彩虹2色彩模式");
_deviceManager.SetPaletteType(PaletteType.Rainbow2);
}
}
catch (Exception ex)
{
Console.WriteLine($"切换到彩虹2色彩模式失败: {ex.Message}");
}
}
#endregion
#region 视频模式切换方法
///
/// 红外模式
///
private void ThermalModeToolStripMenuItem_Click(object sender, EventArgs e)
{
try
{
_deviceManager.SetImageMode(ImageMode.Infrared);
}
catch (Exception ex)
{
Console.WriteLine("切换到红外模式失败: " + ex.Message);
ShowError("切换到红外模式失败");
}
}
private void VisibleModeToolStripMenuItem_Click(object sender, EventArgs e)
{
try
{
_deviceManager.SetImageMode(ImageMode.Natural);
}
catch (Exception ex)
{
Console.WriteLine("切换到自然模式失败: " + ex.Message);
ShowError("切换到自然模式失败");
}
}
#endregion
#region 设备Ping相关方法
///
/// Ping定时器的回调方法
///
/// 状态对象
private void PingTimer_Tick(object state)
{
if (_deviceManager != null && !string.IsNullOrEmpty(_deviceManager.IPAddress))
{
Task.Factory.StartNew(() =>
{
bool pingResult = PingDevice(_deviceManager.IPAddress);
try
{
// 在线程安全的方式下更新状态
if (this.InvokeRequired)
{
this.Invoke(new Action(UpdatePingState), pingResult);
}
else
{
UpdatePingState(pingResult);
}
}
catch (ObjectDisposedException)
{
// 控件可能已被释放,忽略此更新
}
});
}
}
///
/// 执行Ping操作
///
/// 要Ping的IP地址
/// 是否Ping通
private bool PingDevice(string ipAddress)
{
try
{
using (var ping = new System.Net.NetworkInformation.Ping())
{
var reply = ping.Send(ipAddress, 2000); // 2秒超时
return reply != null && reply.Status == System.Net.NetworkInformation.IPStatus.Success;
}
}
catch (Exception ex)
{
Console.WriteLine($"Ping设备失败: {ex.Message}");
return false;
}
}
///
/// 更新Ping状态
///
/// 是否可Ping通
private void UpdatePingState(bool isPingable)
{
IsDevicePingable = isPingable;
}
///
/// 开始设备Ping
///
private void StartDevicePing()
{
try
{
if (_pingTimer != null)
{
_pingTimer.Change(0, _pingInterval); // 立即开始,然后按间隔执行
Console.WriteLine("设备Ping已启动");
}
}
catch (Exception ex)
{
Console.WriteLine($"启动设备Ping失败: {ex.Message}");
}
}
///
/// 停止设备Ping
///
private void StopDevicePing()
{
try
{
if (_pingTimer != null)
{
_pingTimer.Change(Timeout.Infinite, Timeout.Infinite);
Console.WriteLine("设备Ping已停止");
}
}
catch (Exception ex)
{
Console.WriteLine($"停止设备Ping失败: {ex.Message}");
}
}
#endregion
///
/// 清理资源
///
protected override void Dispose(bool disposing)
{
if (disposing)
{
// 检查是否处于设计模式
if (!DesignMode)
{
// 停止相机并释放相关资源
try
{
StopCamera();
}
catch (Exception ex)
{
Console.WriteLine("关闭相机时出错: " + ex.Message);
}
}
// 取消注册事件并释放设备管理器
if (_deviceManager != null)
{
// 移除所有事件监听
_deviceManager.ImageReceived -= DeviceManager_ImageReceived;
_deviceManager.ConnectionStatusChanged -= DeviceManager_ConnectionStatusChanged;
_deviceManager.ConnectionException -= DeviceManager_ConnectionException;
// 释放设备管理器资源
_deviceManager.Dispose();
_deviceManager = null;
}
// 无论是否在设计模式下,都需要释放图像资源
// 释放Ping定时器
if (_pingTimer != null)
{
_pingTimer.Dispose();
_pingTimer = null;
}
if (imageBox != null && !imageBox.IsDisposed && imageBox.Image != null)
{
imageBox.Image.Dispose();
imageBox.Image = null;
}
// 释放图像缓冲区资源
if (_imageBuffer != null)
{
try
{
_imageBuffer.Dispose();
_imageBuffer = null;
Console.WriteLine("图像缓冲区资源已释放");
}
catch (Exception ex)
{
Console.WriteLine($"清理ImageBuffer资源异常: {ex.Message}");
}
}
// 释放LastImage资源
lock (_lastImageLock)
{
if (_lastImage != null)
{
try
{
_lastImage.Dispose();
_lastImage = null;
Console.WriteLine("LastImage资源已释放");
}
catch (Exception ex)
{
Console.WriteLine($"清理LastImage资源异常: {ex.Message}");
}
}
}
// 释放InfoImage资源
lock (_infoImageLock)
{
if (_infoImage != null)
{
try
{
_infoImage.Dispose();
_infoImage = null;
Console.WriteLine("InfoImage资源已释放");
}
catch (Exception ex)
{
Console.WriteLine($"清理InfoImage资源异常: {ex.Message}");
}
}
}
// 释放组件资源
if (components != null)
{
components.Dispose();
}
}
base.Dispose(disposing);
}
}
}