C#:如何在父事件完成执行之前立即引发子事件?
我正在利用第三方的API来控制他们的硬件。它们的方法永远不会返回值,而只会触发事件,这些事件将返回在更改值时发生的值或异常。我猜这就像UI事件一样 假设有一个事件处理程序C#:如何在父事件完成执行之前立即引发子事件?,c#,winforms,C#,Winforms,我正在利用第三方的API来控制他们的硬件。它们的方法永远不会返回值,而只会触发事件,这些事件将返回在更改值时发生的值或异常。我猜这就像UI事件一样 假设有一个事件处理程序button\u Click(),除了调用其他函数外,我还使用它调用函数ThirdPartyAPI.SetSomeStuffConfig(一些参数…)。调用第三方函数后,我需要立即访问只能通过该函数事件的事件处理程序访问的值或异常。问题是,第三方函数引发的事件只有在按钮\u Click()完成后才会执行 有什么解决方案或编码模式
button\u Click()
,除了调用其他函数外,我还使用它调用函数ThirdPartyAPI.SetSomeStuffConfig(一些参数…
)。调用第三方函数后,我需要立即访问只能通过该函数事件的事件处理程序访问的值或异常。问题是,第三方函数引发的事件只有在按钮\u Click()
完成后才会执行
有什么解决方案或编码模式可以用来解决这个问题吗?在按钮\u Click()
的事件处理程序完成执行之前,是否可以触发并运行第三方的事件/事件处理程序
也就是说,我想在调用按钮中的第三方函数后立即访问值和异常
尝试过的解决方案
我尝试的是将按钮\u Click()
分为两部分。调用ThirdPartyAPI.SetSomeStuffConfig(一些参数…
后发生的部分将被放入第三方的事件处理程序中。然而,这是非常麻烦和限制性的
第三方API的示例代码
public void Stuff_SetConfig(int id, int mode, string Exception)
{
//returns the new ID, Mode and exception if unable to set ID or Mode on the hardware
this.ID = id;
this.Mode = mode;
}
private void button_Click(object sender, EventArgs e)
{
ThirdParty.Stuff newStuff = new ThirdParty.Stuff();
newStuff.StuffSetConfig += new ThirdParty.IThirdPartyStuffEvents_StuffSetConfigEventHandler(Stuff_SetConfig);
//call some functions...
newStuff.SetConfig(5, 10); //triggers StuffSetConfigEventHandler
//call other functions...
Console.WriteLine("ID is " + this.ID + " and this.Mode is " + this.Mode); //ID and Mode is empty because the Stuff_SetConfig event handler has not yet run.
}
(取决于所包装的API是否与EAP相似)
在(EAP)中,您调用一个异步方法,并期望在工作完成时引发事件—无论成功与否。这是在.NET中编写异步代码的旧模式。当微软推出Task
时,尤其是在他们将async
和await
添加到该语言中之后,人们对修改旧模式非常感兴趣,使其看起来像(TAP)的现代Task
返回方法
不幸的是,转换EAP不如适应旧的APM(.NET的原始异步模式)那么简单。然而,它们确实提供了一些帮助。他们的示例是带有DownloadFileAsync
方法和DownloadFileCompleted
事件的旧类。以下是他们的改编:
(取决于所包装的API是否与EAP相似)
在(EAP)中,您调用一个异步方法,并期望在工作完成时引发事件—无论成功与否。这是在.NET中编写异步代码的旧模式。当微软推出Task
时,尤其是在他们将async
和await
添加到该语言中之后,人们对修改旧模式非常感兴趣,使其看起来像(TAP)的现代Task
返回方法
不幸的是,转换EAP不如适应旧的APM(.NET的原始异步模式)那么简单。然而,它们确实提供了一些帮助。他们的示例是带有DownloadFileAsync
方法和DownloadFileCompleted
事件的旧类。以下是他们的改编:
您可以共享任何代码示例吗?如果公开事件的类没有为您公开触发事件的方法(我敢说它无论如何都不应该这样做),那么就没有正确的方法触发该事件。据我所知,仅仅运行所连接的事件处理程序是不够的,还需要暴露事件的类中的数据,在这种情况下,此注释的第一句话仍然有效。@Progressive我添加了一个代码示例。希望它能为所有人提供一些见解。@LasseVågsætherKarlsen有一个类,尽管听起来很奇怪,但为了访问某些属性。例如,object.GetConfig()
,该类的方法只会触发一个事件,而不返回任何内容。我不确定设计这样一个类的基本原理,但我认为Damien是有道理的。这是一个非常常见的要求,通常通过将公共代码移动到另一个方法中来解决,所以你也可以自己调用它。这也是获得正确代码的最佳方法,您不太可能真的打算一次又一次地创建新的Stuff对象。form类的构造函数往往是创建对象的正确位置。您可以共享任何代码示例吗?如果公开事件的类没有为您公开触发事件的方法(我敢说它无论如何都不应该这样做),那么不,没有正确的方法触发该事件。据我所知,仅仅运行所连接的事件处理程序是不够的,还需要暴露事件的类中的数据,在这种情况下,此注释的第一句话仍然有效。@Progressive我添加了一个代码示例。希望它能为所有人提供一些见解。@LasseVågsætherKarlsen有一个类,尽管听起来很奇怪,但为了访问某些属性。例如,object.GetConfig()
,该类的方法只会触发一个事件,而不返回任何内容。我不确定设计这样一个类的基本原理,但我认为Damien是有道理的。这是一个非常常见的要求,通常通过将公共代码移动到另一个方法中来解决,所以你也可以自己调用它。这也是获得正确代码的最佳方法,您不太可能真的打算一次又一次地创建新的Stuff对象。form类的构造函数往往是创建对象的正确位置。似乎是可行的。我会调查的。顺便说一句,我已经用示例代码更新了这个问题。@Mark-我尝试了一个厚颜无耻的改编。非常厚颜无耻(我是说很好!)。我会尽快尝试的,似乎可行。我会调查的。顺便说一句,我已经用示例代码更新了这个问题。@Mark-我尝试了一个厚颜无耻的改编。非常厚颜无耻(我是说很好!)。不会
public static Task<string> DownloadStringAsync(Uri url)
{
var tcs = new TaskCompletionSource<string>();
var wc = new WebClient();
wc.DownloadStringCompleted += (s,e) =>
{
if (e.Error != null)
tcs.TrySetException(e.Error);
else if (e.Cancelled)
tcs.TrySetCanceled();
else
tcs.TrySetResult(e.Result);
};
wc.DownloadStringAsync(url);
return tcs.Task;
}
private async void button_Click(object sender, EventArgs e)
{
ThirdParty.Stuff newStuff = new ThirdParty.Stuff();
//call some functions...
var tcs = new TaskCompletionSource<int>();
int mode;
newStuff.SetConfig += (_id, _mode, ex) =>
{
if(!string.IsNullOrWhitespace(ex))
{
tcs.TrySetException(new Exception(ex));
}
else
{
mode = _mode;
tcs.TrySetResult(_id);
}
}
newStuff.SetConfig(5, 10);
//call other functions...
var id = await tcs.Task;
Console.WriteLine("ID is " + id + " and this.Mode is " + mode);
}