如何为Control.BeginInvoke委派AsyncCallback方法?(.净)

She*_*eed 5 .net c# begininvoke asynccallback

是否可以在"火与忘"方式之外使用Control.BeginInvoke?我想更改以下请求以委托回调方法,以便我可以在每个异步调用完成时执行某些操作.

this.BeginInvoke(new RefreshRulesDelegate(RefreshRules), new object[] { ctrl, ctrl.DsRules, ctrl.CptyId });  
Run Code Online (Sandbox Code Playgroud)

我可以用普通的delegate.BeginInvoke这样做

RefreshRulesDelegate del = new RefreshRulesDelegate(RefreshRules);
            del.BeginInvoke(ctrl, ctrl.DsRules, ctrl.CptyId, new AsyncCallback(RefreshCompleted), del);  
Run Code Online (Sandbox Code Playgroud)

但因为我正在调用Control .BeginInvoke,因为我得到"跨线程操作无效"错误,所以无法执行此操作.
有人帮吗?

对于收到的一些答案,我将澄清"为什么".我需要在我的GUI上加载/刷新一个Control,而不需要锁定应用程序的其余部分.该控件包含许多控件(ruleListCtls),这些控件都需要检索数据集并将其传递给它们.即

public void RefreshAll()
{
    foreach (LTRFundingRuleListControl ctrl in ruleListCtls)
    {
        this.BeginInvoke(new RefreshRulesDelegate(RefreshRules), new object[]{ctrl,ctrl.DsRules, ctrl.CptyId });   
    }
}  
Run Code Online (Sandbox Code Playgroud)

我发现如果我提供一个委托回调方法并将修改控件的任何代码移回到创建它们的主GUI线程上(以避免跨线程错误),我可以这样做

public void RefreshAll()
{
    IntPtr handle; 
    foreach (LTRFundingRuleListControl ctrl in ruleListCtls)
    {
        handle = ctrl.Handle;
        RefreshRulesDsDelegate del = new RefreshRulesDsDelegate(RefreshRulesDs);
        del.BeginInvoke(ctrl.DsRules, ctrl.CptyId, handle, out handle, new AsyncCallback(RefreshCompleted), del);
    }        
}

private void RefreshCompleted(IAsyncResult result)
{
    CptyCatRuleDataSet dsRules;
    string cptyId;
    IntPtr handle;

    AsyncResult res = (AsyncResult) result;

    // Get the handle of the control to update, and the dataset to update it with
    RefreshRulesDsDelegate del = (RefreshRulesDsDelegate) res.AsyncDelegate;
    dsRules = del.EndInvoke(out handle,res);

    // Update the control on the thread it was created on
    this.BeginInvoke(new UpdateControlDatasetDelegate(UpdateControlDataset), new object[] {dsRules, handle});
}

public delegate CptyCatRuleDataSet RefreshRulesDsDelegate(CptyCatRuleDataSet dsRules, string cptyId, IntPtr ctrlId, out IntPtr handle);
private CptyCatRuleDataSet RefreshRulesDs(CptyCatRuleDataSet dsRules, string ruleCptyId, IntPtr ctrlId, out IntPtr handle)
{
    try
    {
        handle = ctrlId;
        int catId = ((CptyCatRuleDataSet.PSLTR_RULE_CAT_CPTY_SelRow)dsRules.PSLTR_RULE_CAT_CPTY_Sel.Rows[0]).RULE_CAT_ID;
            return ltrCptyRulesService.GetCptyRules(ruleCptyId, catId);
    }
    catch (Exception ex)
    {
        throw ex;
    }
}  
Run Code Online (Sandbox Code Playgroud)

以下是我们对收到回调的主线程的详细信息:

private delegate void UpdateControlDatasetDelegate(CptyCatRuleDataSet dsRules, IntPtr ctrlId);
private void UpdateControlDataset(CptyCatRuleDataSet dsRules, IntPtr ctrlId)
{
    IEnumerator en = ruleListCtls.GetEnumerator();
    while (en.MoveNext())
    {
        LTRFundingRuleListControl ctrl = en.Current as LTRFundingRuleListControl;
        if (ctrl.Handle == ctrlId)
        {
            ctrl.DsRules = dsRules;
        }
    }
}  
Run Code Online (Sandbox Code Playgroud)

这现在工作正常.然而,除了我认为这不是特别优雅之外,主要问题是异常处理.也许这是另一个问题,但是如果RefreshRulesDs抛出异常,那么我的应用程序崩溃,因为错误没有冒泡回GUI线程(显然),但是作为未处理的异常.直到我能抓住这些,然后我将不得不同步完成整个操作.如何成功捕获错误并加载其余控件?或者我如何通过适当的异常处理以另一种方式实现此异步操作?

Hen*_*man 5

关于“是否可能”部分:不,Control.BeginInvoke使用Windows PostMessage(),这意味着没有答案。这也意味着 RefreshRulesDelegate 在主线程上执行,而不是在后台线程上执行。

因此,请使用delegate.BeginInvokeThreadPool,并在它们完成后用于Control.[Begin]Invoke()更新 UI。