我试图使用一个包含少量事件的dll文件。当我尝试使用下面的代码时,我得到:
"类型' System.InvalidCastException'"
的例外情况
和
"无法投射#q; qweqwe_po.MyHandler'输入 ' System.ComponentModel.ISynchronizeInvoke'"
我不知道为什么会这样,需要一些帮助。如果我在Form1或Form2中使用MyHandler中的代码,它可以正常工作,因此我猜测我的委托有问题。有人能看出我做错了吗?
故障在行(MyHandler)上触发:
((ISynchronizeInvoke)d.Target).BeginInvoke(d, new object[] { this, e });
Form1
public partial class Form1 : Form
{
MyHandler obj;
public Form1()
{
InitializeComponent();
obj = new MyHandler();
}
private void Form1_Load(object sender, EventArgs e)
{
using (Form2 f = new Form2(obj, new Random().Next(20,80)+1))
{
f.ShowDialog();
}
}
}
窗体2
public partial class Form2 : Form
{
private MyHandler obj;
public Form2(MyHandler p_obj, double sum)
{
InitializeComponent();
obj = p_obj;
textBox1.Text = sum.ToString();
}
}
MyHandler的
public class MyHandler
{
private figure fig;
public event FigureEventHandler FigureEvent;
private double m_Sum;
public MyHandler()
{
init();
}
public void init()
{
fig = new figure();
// PIM event
fig.OnStatus += new IFigureEvents_OnStatusEventHandler(fig_OnStatus);
fig.OnReturn += new IFigureEvents_OnReturnEventHandler(fig_OnReturn);
FigureEvent += new FigureEventHandler(MainWindow_FigureEvent);
int res = 0;
if ((res = fig.open("192.168.16.68") != 0)
{
Console.WriteLine("figure.dll open failed. Error: " + res);
return;
}
if ((res = fig.startConnection()) != 0)
Console.WriteLine("Error starting com test");
}
public void fig_OnStatus(short statusType)
{
OnFigureEvent(new FigureEventArgs(integrationEvents.STATUS, statusType));
}
public void fig_OnReturn()
{
OnFigureEvent(new FigureEventArgs(integrationEvents.RESULT, 0));
}
protected virtual void OnFigureEvent(FigureEventArgs e)
{
if (FigureEvent != null)
{
foreach (Delegate d in FigureEvent.GetInvocationList())
((ISynchronizeInvoke)d.Target).BeginInvoke(d, new object[] { this, e });
}
}
public void MainWindow_FigureEvent(object sender, FigureEventArgs e)
{
switch (e.IntegrationEvent)
{
case integrationEvents.STATUS:
// status logic
case integrationEvents.RESULT:
//result logic
}
}
public bool Send(transTypes p_TransType, double p_Value)
{
int res = 0;
if (p_TransType == transTypes.TRANS_NONE || fig.Busy != 0)
return false;
res = fig.Send(0x30);
if (res != 0)
Console.WriteLine("Error calling Send(): " + res);
return !Convert.ToBoolean(res);
}
}
public class FigureEventArgs : EventArgs
{
private readonly integrationEvents integrationEvent = integrationEvents.NONE;
private readonly short statusType = 0;
public FigureEventArgs(integrationEvents integrationEvent, short statusType)
{
this.integrationEvent = integrationEvent;
this.statusType = statusType;
}
public integrationEvents IntegrationEvent { get { return integrationEvent; } }
public short StatusType { get { return statusType; } }
}
public delegate void FigureEventHandler(object sender, FigureEventArgs e);
}
答案 0 :(得分:1)
你正在破坏东西。原始代码将相关控件(旧MainWindow_FigureEvent
)的UI线程上的事件回调设置为marh。
foreach (Delegate d in FigureEvent.GetInvocationList())
((ISynchronizeInvoke)d.Target).BeginInvoke(d, new object[] { this, e });
这基本上说"将事件的调用链中添加的所有委托调用,并在"中定义它们的类的实例的线程上调用它们。
因此,如果您从与原始控件的UI线程不同的线程触发事件,则委托执行将被编组到UI线程,而不是继续执行导致事件触发的线程。
多线程很难
你必须非常小心。编写原始代码的人有理由这样做。了解原因。确保它们是否有意义。如果没有,您可以使用FigureEvent()
代替for-each。但是,如果它们仍然有意义,那么你在这里尝试的所有东西都无法工作 - 你通过向{{1添加回调函数 - 抛弃了关于你需要编组回来的线程的信息。 }}而不是MyHandler
。
改变这样的事情会带来大量的副作用。听起来你并不能完全处理所涉及的复杂问题,所以如果可能的话,尝试与更多经验丰富的多线程人员合作。如果不可能,请尽量保持与原始实施尽可能接近。听起来你正试图摆脱一些重复的代码。但是,很难给出任何有关如何正确处理此问题的直接指示,因为这是您未显示的代码部分。但主要的想法是不要通过像这样的Form
类来处理这个问题,而是将实现的公共部分推到一个单独的类中,同时将事件处理程序保留在MyHandler
上。您可能需要在这里和那里重写几个位,添加一些接口,可能是继承。
回到我们所拥有的代码摘录,请注意以下将事件处理程序移动到Form
时发生的变化:
MyHandler
不再是表格。这会导致您d.Target
。InvalidCastException
不再是表格。哎呀。您确定事件处理程序不希望this
参数成为表单吗?事实上,您完全抛弃了有关表单的信息。您正在使用的架构并不是很明显,因此我无法向您展示如何解决所有问题,但至少您应该在路上:)