订阅的单例方法未触发 - 嵌套窗口窗体
向旧版应用程序添加对新移动设备的支持。
基于本文实现的单例类 在单一实例类上创建事件
public sealed class Singleton
{
static readonly Singleton instance=new Singleton();
// Explicit static constructor to tell C# compiler
// not to mark type as beforefieldinit
static Singleton()
{
}
Singleton()
{
}
public static Singleton Instance
{
get
{
return instance;
}
}
}
在创建时,每个窗体将本地方法订阅到条形码对象的读取方法
singleton.Instance.scanEngine.BarcodeRead += new BarcodeReadEventHandler(FormA_BarcodeReadMethod);
关闭时,每个窗体取消订阅条形码对象读取方法
单身 人士。Instance.scanEngine.BarcodeRead -= new BarcodeReadEventHandler(FormA_BarcodeReadMethod);
场景 #1
- 从主菜单窗体调用 FormA
- singleton BarcodeReader.BarcodeScan 事件为空;
- 已创建表单
FormA 事件订阅单例 BarcodeReader.BarcodeScan 事件
"单身人士。Instance.scanEngine.BarcodeRead += new BarcodeReadEventHandler(FormA_BarcodeReadMethod);'
singleton BarcodeReader.BarcodeScan 事件不为空;
- 条形码扫描并FormA_BarcodeReadMethod火灾。
窗体 A 已关闭,窗体 A 事件取消订阅到单例
BarcodeReader.BarcodeScan 事件单例。Instance.scanEngine.BarcodeRead -= new BarcodeReadEventHandler(FormA_BarcodeReadMethod);
singleton BarcodeReader.BarcodeScan 事件为空;
- 返回主菜单窗体
还有 5 种其他形式从主屏幕调用,表现正常,
如上所述在一种情况下,具有扫描仪订阅的表单调用另一个也需要扫描仪订阅的表单
场景 #2
- 从主菜单窗体调用窗体
- singleton BarcodeReader.BarcodeScan 事件为空;
- 已创建表单 B
表单 B 事件订阅单例
单身 人士。Instance.scanEngine.BarcodeRead += new BarcodeReadEventHandler(FormB_BarcodeReadMethod);
singleton BarcodeReader.BarcodeScan 事件不为空;
- 条形码扫描并FormB_BarcodeReadMethod火灾。
处理触发的事件时,FormB 按如下方式调用 FormC
FormB 事件取消订阅单例 BarcodeReader。BarcodeScan 事件
单身 人士。Instance.scanEngine.BarcodeRead -= new BarcodeReadEventHandler(FormB_BarcodeReadMethod);
singleton BarcodeReader.BarcodeScan 事件为空;
- 已创建表单C
FormC 事件订阅单例 BarcodeReader.BarcodeScan 事件
单身 人士。Instance.scanEngine.BarcodeRead += new BarcodeReadEventHandler(FormC_BarcodeReadMethod);
singleton BarcodeReader.BarcodeScan 事件不为空;
- 条形码扫描,FormC_BarcodeReadMethod不触发。 FormC
已关闭,FormC 事件取消订阅单例 BarcodeReader。BarcodeScan 事件
单身 人士。Instance.scanEngine.BarcodeRead -= new BarcodeReadEventHandler(FormC_BarcodeReadMethod);
singleton BarcodeReader.BarcodeScan 事件为空; - 控制返回到表单B - FormB 事件订阅 singleton BarcodeReader.BarcodeScan eventsingleton。Instance.scanEngine.BarcodeRead += new BarcodeReadEventHandler(FormB_BarcodeReadMethod); - singleton BarcodeReader.BarcodeScan 事件不为空; - 条形码扫描和FormB_BarcodeReadMethod火灾。
预期的结果是订阅的 FormC 事件会触发,但它没有,我无法弄清楚为什么会这样。
任何帮助非常感谢。
对评论#1的回应
在窗体 B 中,决定调用 FormC 在表单 B 上,扫描仪事件已取消订阅
clsApplicationController.Instance.scanEngineIntermec.BarcodeRead -= new
BarcodeReadEventHandler(this.frmB_Intermec_OnRead);
this.Update();
Application.DoEvents();
FormC 的调用方式如下
using (formC _formC = new formC())
{
_formC.cUser = _cUser;
var _result = _formC.ShowDialog();
if (_result != DialogResult.OK) return;
}
事件在 FormC 构造函数中订阅
clsApplicationController.Instance.scanEngine.BarcodeRead += new
BarcodeReadEventHandler(this.frmC_OnRead);
this.Update();
Application.DoEvents();
对评论#2的回应
已订阅但未触发的 FormC 事件
void formC_OnRead(object sender, BarcodeReadEventArgs bre)
{
try {
ProcessScan(bre.strDataBuffer, sender);
}
catch (Exception exp)
{
MessageBox.Show(exp.Message);
}
}
formC_OnRead 方法订阅到 FormC 构造函数中的 Instance.scanEngineIntermec.BarcodeRead 事件。 进程扫描是通用的,可供所有扫描仪类型使用。 在工作表单上实施相同的方法和方法
为什么取消订阅新的事件处理程序而不在此处减去现有处理程序:
clsApplicationController.Instance.scanEngineIntermec.BarcodeRead -= new BarcodeReadEventHandler(this.frmB_Intermec_OnRead);
通常这应该是: clsApplicationController.Instance.scanEngineIntermec.BarcodeRead -= this.frmB_Intermec_OnRead;
我不确定,但是 -=new 会取消订阅新的事件处理程序。这有意义吗?-=新用于您的所有表单?!
另请参阅 https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/events/how-to-subscribe-to-and-unsubscribe-from-events
!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 失败的代码是:
void Intermec_OnRead(object sender, BarcodeReadEventArgs bre)
{
try
{
this.textBox1.Text = bre.strDataBuffer;
this.textBox1.Text += "rn" + this.Name;
this.textBox1.Text += "rn" + sender.ToString();
this.Update();
if (_runFormC)
{
//MessageBox.Show(this.textBox1.Text);
System.Threading.Thread.Sleep(5000);
this.barcodeScanner_unSubscribe();
using (FormC frmC = new FormC())
{
var _result = frmC.ShowDialog();
if (_result != DialogResult.OK) return;
}
this.barcodeScanner_subscribe();
this.textBox1.Text = string.Empty;
}
}
catch (Exception exp)
{
MessageBox.Show(exp.Message);
}
}
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 如果从Button_Click处理程序调用 formC,则一切正常。
当我使用队列、锁和线程时,如果队列中有内容,则启动 formC,FormC 工作正常。 更改了所有订阅() 取消订阅() 以从激活/停用处理程序调用。
我通常喜欢抽象一点条形码处理,以便整个应用程序不依赖于供应商 SDK,从而在需要时更轻松地移植应用程序。 我将跳过该切线的详细信息,但这种方法也简化了整个应用程序的条形码处理。
保持条形码管理器单一实例,并让他成为接触条形码 SDK 对象的唯一实体。 通过调用单一实例条形码管理器,让您的表单或其他对象注册它们对接收条形码通知的兴趣,并在堆栈中维护它们,以便您可以将条形码通知路由到最顶层的侦听器。 因此,在窗体 A 处理条形码的情况下,窗体 A 调用对话框 B 也处理对话框,则不必对任何内容进行微观管理。 当显示窗体或对话框时,它会在"加载"或"激活"中调用BarcodeManager.Instance.PushBarcodeListener(this)
。 当它关闭或停用时,您拨打BarcodeManager.Instance.PopBarcodeListener(this)
. 如果您始终使用它,条形码管理器将知道当前/顶级侦听器是谁,并仅通知该对象。
侦听器本身是一个独立于 SDK 的接口,任何想要接收条形码事件的对象都实现了该接口。 我们称之为 IBarcodeListener,并将定义一个传入条形码就绪数据的方法:
void HandleBarcode(BarcodeReadEventArgs evt);
(您甚至可以支持侦听器遍历,其中事件在堆栈中冒泡,直到它被处理,但现在让我们保持简单)。
在条形码管理器单例中:
private void PushBarcodeListener(IBarcodeListener l)
{
m_listeners.Push(l);
if (m_listeners.Count == 1)
{
// as soon as you have an interested party, add your one and only
// event handler to the SDK object and enable it (the exact details
// of this are SDK dependent).
}
}
private void PopBarcodeListener(IBarcodeListener l)
{
if (!Object.ReferenceEquals(l, m_listeners.Peek())
Throw new Exception("Only the active BarcodeListener can be removed");
m_listeners.Pop();
if (m_listeners.Count == 0)
{
// if no one is interested in barcodes, stop listening by disabling the SDK
// object and removing the event handler
}
}
当然,在唯一的 SDK 事件处理程序中,您可以像这样通知顶级侦听器:
if (m_listeners.Count != 0)
m_listeners.Peek().HandleBarcode(evt)
免责声明,此代码未经过语法检查,我只是从内存中执行此操作。 您将需要修复拼写错误。
有关此添加的上下文,请参阅注释。
这是我用来在 UI 线程"异步"上运行代码的一些代码的示例。 请注意,如果从 UI 线程调用,它基本上会在消息泵处理完所有当前 Windows 消息后运行:
public System.IAsyncResult BeginInvoke(System.Delegate method)
{
return base.MainForm.BeginInvoke(method);
}
public System.IAsyncResult BeginInvoke(System.Delegate method, params object[] args)
{
return base.MainForm.BeginInvoke(method, args);
}
请注意,"MainForm"是对应用程序中根窗体的引用,此代码驻留在我的"应用程序对象"中,它是整个应用程序的根对象,因此可以在任何地方访问。