无法在单击按钮时将 Com Interop 事件从 Winforms(form) 引发到 VB

Unable to raise Com Interop event on button click from a Winforms(form) to VB

我用 C# 编写了一个 COM Interop 可见 class 库。如果我打开 vb6 对象浏览器并查看暴露的成员,我会看到每个暴露的成员都有一个事件。

在我的互操作中,我有一个带有一个按钮的表单,因此一旦用户单击该按钮,就需要调用该事件,但即使我在单击按钮时调用了 com 可见事件,它也没有发生。但是或者,如果我从 vb6 调用一个 public C# 函数并且在函数内部调用了 com 可见事件,那么该事件将在 vb6.0

中触发

下面是我的 C# 代码

public partial class Form1 : Form, EventsInf
{
    public delegate void GetData_delegate(string serviceid);
    public event GetData_delegate GetData;
    public Form1()
    {
        InitializeComponent();
    }
    private void button1_Click(object sender, EventArgs e)
    {
        MessageBox.Show("Button click entered");
        GetData?.Invoke("test");
    }
    public void raiseevent()
    {
        MessageBox.Show("Event raised from function");
        GetData?.Invoke("test");
    }
   public void show()
    {
        Form1 f1 = new Form1();
        f1.ShowDialog();
    }

我的界面:

[InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIDispatch)]
[ComVisible(true)]
public interface Interface
{
    void GetData(string serviceid);
}

我的活动信息:

[ComVisible(true)]
public interface EventsInf
{
    void raiseevent();
}

VB6.0代码:

Private WithEvents test As ClassLibrary5.Form1
Private obj As ClassLibrary5.Class1

Private Sub Form_Load()
Set obj = New ClassLibrary5.Class1
Set test = New ClassLibrary5.Form1
test.raiseevent
Me.Visible = False
obj.Show
End Sub

Private Sub test_GetData(ByVal serviceid As String)

End Sub

请参考屏幕截图,其中我已将 C# dll 转换为 tlb 并将其添加为对我的 vb6 项目的引用。现在在执行 vb 6 项目时,winform 的 (form window) 被启动。但是,在按下 'click me' 按钮后,断点没有被击中。

您确实应该遵循公开事件的标准约定。如果您想引发一个提供文本数据的事件并在用户单击 Button 时引发该事件,那么它应该如下所示:

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }

    public event EventHandler<DataAvailableEventArgs> DataAvailable;

    protected virtual void OnDataAvailable(DataAvailableEventArgs e)
    {
        DataAvailable?.Invoke(this, e);
    }
}

public class DataAvailableEventArgs : EventArgs
{
    public string Data { get; }

    public DataAvailableEventArgs(string data)
    {
        Data = data;
    }
}

然后您通过调用 OnDataAvailable 方法并传递一个 DataAvailableEventArgs 对象来引发事件,例如

OnDataAvailable(new DataAvailableEventArgs("test"));

您可以从 ButtonRaiseDataAvailable 方法的 Click 事件处理程序或任何地方执行此操作。事件处理程序将与其他任何事件处理程序一样,即 sender 参数将是引发事件的对象,而 e 参数将包含数据,例如

Dim data As String = e.Data

如果您真的想定义自己的委托(也许 COM 需要;不确定)那么您可以这样做:

public delegate void DataAvailableEventHandler(object sender, DataAvailableEventArgs e);

还有这个:

public event DataAvailableEventHandler DataAvailable;

在 C# 中,您有两个不同的名称 GetData。这似乎是一个错误。

  • 表格class中有event ... GetData

  • 并且界面中有正则函数GetData Interface.

并且该表单无论如何都没有实现该接口。 (为什么甚至需要它?)

所以我认为就 VB6 而言,您的 test_GetData 并不存在。在 IDE 中,您应该在左侧下拉菜单 IIRC 中看到 test,在右侧下拉菜单中看到 GetData 以及任何其他事件。但它实际上只是在左侧显示“一般”。

您是否必须手动输入 Private Sub test_GetData ...

根本原因: 我在 class 中写了 'f1.ShowDialog();' ,其中 f1 是表单对象。

修复: 通过在 public 函数中使用 'this.Show();' 重写表单代码解决了这个问题。

C# 代码:

private void button1_Click(object sender, EventArgs e)
    {
        GetData?.Invoke("test");
    }    
    public void raiseevent()
    {
        this.Show();
        MessageBox.Show("Event raised from function");
    }

VB6.0

 Private WithEvents test As ClassLibrary5.Form1
 Private Sub Form_Load()
 Set test = New ClassLibrary5.Form1
 test.raiseevent
 Me.Visible = False
 End Sub

 Private Sub test_GetData(ByVal serviceid As String)

 End Sub