订阅的单一实例类事件未触发



订阅的单例方法未触发 - 嵌套窗口窗体

向旧版应用程序添加对新移动设备的支持。

基于本文实现的单例类 在单一实例类上创建事件

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"是对应用程序中根窗体的引用,此代码驻留在我的"应用程序对象"中,它是整个应用程序的根对象,因此可以在任何地方访问。

相关内容

  • 没有找到相关文章