【问题标题】:Invoke method on event handler in Delphi在 Delphi 中的事件处理程序上调用方法
【发布时间】:2013-12-25 19:09:13
【问题描述】:

如下使用 SDK 的 C# 编写的代码示例(进程内 COM 对象) 我创建了一个类:TSwitcherMonitor,现在我必须将回调函数分配给我的对象属性:OnSwitcherDisconnected 属性。我在 C# 中有这个调用示例,注释讨论了 lambda 表达式的双重使用。我已经对此进行了谷歌搜索,似乎 Delphi 没有 lambda 表达式。

这是 C# 中的调用: Q1:有一种方法可以在 Delphi 中使用 invoke 方法执行相同的操作,还是我们必须以不同的方式执行此操作?

//Create callbacks object
  m_switcherMonitor := TSwitcherMonitor.Create(Application.Handle);
  // note: this invoke pattern ensures our callback is called in the main thread. We are making double
  // use of lambda expressions here to achieve this.
  // Essentially, the events will arrive at the callback class (implemented by our monitor classes)
  // on a separate thread. We must marshell these to the main thread, and we're doing this by calling
  // invoke on the Windows Forms object. The lambda expression is just a simplification./
  m_switcherMonitor.OnSwitcherDisconnected += new SwitcherEventHandler((s, a) => this.Invoke((Action)(() => SwitcherDisconnected())));

Q2:我唯一想要的就是在使用 SDK 时进行有效的回调。我的 TSwitcherEventHandler 声明是否正确?

作为参考,这里是我的 TSwitcherEventHandler 声明和我的 TSwitcherMonitor 类:

Type
{TSwitcherEventHandler}
  TSwitcherEventHandler = procedure(const sender: TObject; const args: TObject) of object;

{TSwitcherMonitor}
  TSwitcherMonitor = Class(TComObject, IBMDSwitcherCallback)
  private
    FHwnd: HWND;
    FSwitcherDisconnected: TSwitcherEventHandler;
  published
    constructor Create(hWnd: HWND);
  public
    function Notify(eventType: _BMDSwitcherEventType): HResult; stdcall;
    property OnSwitcherDisconnected: TSwitcherEventHandler read FSwitcherDisconnected write FSwitcherDisconnected;
  end;

implementation
{ TSwitcherMonitor }
constructor TSwitcherMonitor.Create(hWnd: HWND);
begin
  FHwnd:= hWnd;
end;

function TSwitcherMonitor.Notify(eventType: _BMDSwitcherEventType): HRESULT; stdcall;
begin
  if eventType = bmdSwitcherEventTypeDisconnected then
    if assigned(FSwitcherDisconnected) then
      FSwitcherDisconnected(self, nil);

  result := S_OK;
end;

【问题讨论】:

  • 很难看出 C# 的作用。这不是一个纯粹的德尔福问题吗? Delphi 具有等效于 C# lambdas 的匿名过程。
  • @Heffernan,圣诞快乐! ,C#来作为我在C#中的例子,我不理解事件句柄分配的“invoke((action)”部分。
  • 另外,在这行代码中,当在 C# 中将事件处理程序分配给 OnSwitcherDisconnected 时,它使用 SwitcherEventHandle 的“=+ new”,这是我的 TSwitcherEventHandle,但这不是一个对象,并且我无法创建它的实例。这是我不明白的,我不知道如何在 Delphi 中编写这个调用。
  • Invoke 在主线程上运行代码。在 Delphi 中它是 TThread.Synchronize。
  • 这还没有完成(更多工作正在进行中),但如果我理解得很好,调用将如下所示:m_switcherMonitor.OnSwitcherDisconnected := TThread.Synchronize(TSwitcherEventHandler);

标签: delphi


【解决方案1】:

我不是“Delphi 专家”,但正如许多人所说,Delphi Rocks 是舒尔!

C# 行:

m_switcherMonitor.OnSwitcherDisconnected += new SwitcherEventHandler((s, a) => this.Invoke((Action)(() => SwitcherDisconnected())));

在Delphi中可以简单地翻译为:

m_switcherMonitor.OnSwitcherDisconnected := switcherMonitor_OnSwitcherDisconnected;

现在我的示例应用程序可以工作了。 Delphi 使用指针做一些自动工作,当在 Delphi 中翻译 C# 或 C++ 代码时,只需将其写入更简单的表达式,Delphi 就可以完成这项工作。一开始,当我们试图了解事物的工作原理时,使用这种黑魔法很奇怪而且很难,但正如他们所宣传的那样,Delphi 无疑是真正的 RAD。

【讨论】:

  • Myabe 的混淆仅仅是由问题措辞中使用的单词引起的。您展示的是如何为事件分配处理程序。事件只不过是具有非常特定数据类型的属性:过程类型。与任何其他属性一样,您可以为事件赋值。这个值也必须是一个过程类型,这意味着这里是指向类方法的指针。这就是您正确使用运算符:= 的原因。 Delphi 没有对 C# 等多播事件的本机支持,因此某个事件可以触发一个且只有一个处理程序。这就是为什么您分配一个处理程序而不是添加一个。
  • @AlexSC,非常有用的解释。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-12-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多