我有一个提供事件StkQuit
的外部应用程序。
我在一个静态类中订阅此事件,该类处理我的应用程序和[外部]应用程序之间的所有通信。我想使用另一个位于我的表单类的处理程序订阅StkQuit
事件。
此处理程序将通知用户外部应用程序已关闭。我希望在名为SubscribeToStkQuit
的静态类中有一个泛型方法,它接受委托作为参数,并将该委托(引用我的表单类中的处理程序)订阅到StkQuit
事件。
这可能吗?这是实现此类功能的最优雅/最简单的方式吗?
我的示例代码:
表单类
public delegate void dForceClose();
public void SubscribeToStkQuit(dForceClose forceClose)
{
UtilStk.SubscribeToStkQuit(forceClose = new dForceClose(ForceClose));
}
private void ForceClose()
{
MessageBox.Show("TEST");
}
静态类
private static AgUiApplication _stkUiApplication;
public static void SubscribeToStkQuit(Delegate subscribeHandler)
{
_stkUiApplication.OnQuit += subscribeHandler;
}
[更新]
根据评论我已更新代码:
public delegate void dForceClose(object sender, EventArgs e);
public void SubscribeToStkQuit(dForceClose forceClose)
{
UtilStk.SubscribeToStkQuit(forceClose = new dForceClose(ForceClose));
}
private void ForceClose(object sender, Eventargs e)
{
MessageBox.Show("TEST");
}
我仍然得到施法异常。任何想法??
[更新#2]
我仍然遇到这个问题。在我的静态类中,当OnQuit
触发时,我已经有了一个处理程序:
private static AgUiApplication _stkUiApplication;
public static bool CheckThatStkIsAvailable()
{
object stkApplication = null;
try
{
stkApplication = Marshal.GetActiveObject(_stkProgId);
_stkUiApplication = stkApplication as AgUiApplication;
_stkUiApplication.OnQuit += StkQuit;
return true;
}
catch (Exception)
{
// handle this
}
}
private static void StkQuit()
{
_stkUiApplication.OnQuit -= StkQuit;
Marshal.FinalReleaseComObject(_stkUiApplication);
Marshal.FinalReleaseComObject(_stkRoot);
}
这很好用。所以我想我会为_stkUiApplication创建一个公共属性,并以相同的方式从表单类订阅:
静态类
public static AgUiApplication StkUiApplication
{
get { return _stkUiApplication; }
}
表单类
private void SubscribeToStkQuit()
{
UtilStk.StkUiApplication.OnQuit += StkQuit;
}
private void StkQuit()
{
MessageBox("TEST");
}
答案 0 :(得分:3)
如果使用实例方法订阅静态事件,则在处理静态事件之前不会对实例进行垃圾回收(除非您取消订阅)。
这会导致内存泄漏。
除此之外,代码的问题在于ForceClose()
的签名与_stkUiApplication.OnQuit
的签名不一致ForceClose(object sender, SomeKindOfEventArgs e)
应为UtilStk.SubscribeToStkQuit(forceClose => (s, e){ForceClose();});
编辑:
对外部应用的引用是静态的:
private static AgUiApplication _stkUiApplication;
所以它会在你的申请期间存活。添加事件处理程序到
_stkUiApplication.OnQuit
将引用传递给表单类实例上的方法。此引用现在将在您的应用程序的生命周期内保留,因此不能进行垃圾回收。
要处理这种情况,要么在处理侦听对象时显式取消注册( - =)处理程序,要么使用静态处理程序处理静态事件。
我错误地认为你最初是在描述网页表单,这会改变一些事情(你可能只会实例化一个Form
),但无论如何,上述情况都适用。这是一种很好的做法。
解决您当前的问题: 您需要输入传递给的参数:
public static void SubscribeToStkQuit(Delegate subscribeHandler)
{
_stkUiApplication.OnQuit += subscribeHandler;
}
是_stkUiApplication.OnQuit
像
这样的东西public static void SubscribeToStkQuit(EventHandler<EventArgs> subscribeHandler)
{
_stkUiApplication.OnQuit += subscribeHandler;
}
然后你可以这样做:
public void SubscribeToStkQuit()
{
UtilStk.SubscribeToStkQuit((sender, args) => ForceClose(sender, args));
}
答案 1 :(得分:3)
是的,你可以!
但最好使用在参数化方面灵活的动作和函数(所有这些都在System命名空间中)。
无论如何,我还有另一个建议:为什么不使用事件访问器?您可以在静态类中创建一个:
public event EventHandler Quit { add { _stkUiApplication.OnQuit += value; } remove { _stkUiApplication.OnQuit -= value; } }
关于操作和功能,这些也是委托,因此您可以将它们作为任何委托的输入参数随处使用。
也许您可以使用事件访问器并以.NET方式执行,不是吗?