كيف يمكنني تفويض أسلوب AsyncCallback لـ Control.BeginInvoc؟(.شبكة)

StackOverflow https://stackoverflow.com/questions/1808636

سؤال

هل من الممكن استخدام Control.BeginInvine بأي شيء آخر غير طريقة "إطلاق النار والنسيان"؟أريد تغيير الطلب التالي لتفويض طريقة رد الاتصال حتى أتمكن من القيام بشيء ما عند اكتمال كل من مكالماتي غير المتزامنة.

this.BeginInvoke(new RefreshRulesDelegate(RefreshRules), new object[] { ctrl, ctrl.DsRules, ctrl.CptyId });  

سأكون قادرًا على القيام بذلك باستخدام مندوب عادي.

RefreshRulesDelegate del = new RefreshRulesDelegate(RefreshRules);
            del.BeginInvoke(ctrl, ctrl.DsRules, ctrl.CptyId, new AsyncCallback(RefreshCompleted), del);  

ولكن لأنني أتصل يتحكم.BeginInvoca لا يمكنني القيام بذلك لأنني أتلقى الخطأ "عملية الترابط غير صالحة".
هل من أحد يساعد؟

بالإضافة إلى بعض الإجابات التي تلقيتها، سأوضح "السبب".أحتاج إلى تحميل/تحديث عنصر تحكم على واجهة المستخدم الرسومية الخاصة بي دون قفل بقية التطبيق.يحتوي عنصر التحكم على العديد من عناصر التحكم (ruleListCtls) التي تتطلب جميعها استرداد مجموعة بيانات وتمريرها إليها.أي.

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

لقد وجدت أنه يمكنني القيام بذلك إذا قمت بتوفير طريقة رد اتصال المفوض ونقل أي رمز يعدل عناصر التحكم مرة أخرى إلى مؤشر ترابط واجهة المستخدم الرسومية الرئيسي الذي تم إنشاؤها عليه (لتجنب الخطأ المتقاطع)

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;
    }
}  

إليك ما ننتقل إليه في الموضوع الرئيسي بعد أن تلقينا رد الاتصال:

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;
        }
    }
}  

هذا يعمل الآن بشكل جيد.ومع ذلك، فإن المشكلة الرئيسية، بصرف النظر عن أنني لا أعتقد أن هذا الأمر أنيق بشكل خاص، هي التعامل مع الاستثناءات.ربما يكون هذا سؤالًا آخر، ولكن إذا ألقى RefreshRulesDs استثناءً، فسيتعطل تطبيقي لأن الخطأ لا يتم نسخه احتياطيًا في مؤشر ترابط واجهة المستخدم الرسومية (من الواضح) ولكن كاستثناء لم تتم معالجته.وإلى أن أتمكن من التقاط هذه الأشياء، سأضطر إلى القيام بهذه العملية برمتها بشكل متزامن.كيف يمكنني اكتشاف الخطأ بنجاح وتحميل بقية عناصر التحكم الخاصة بي؟أو كيف يمكنني تحقيق هذه العملية غير المتزامنة بطريقة أخرى، مع معالجة الاستثناءات المناسبة؟

هل كانت مفيدة؟

المحلول

فيما يتعلق بالجزء "هل من الممكن":لا، Control.BeginInvoke يستخدم ويندوز PostMessage() وهذا يعني أنه لا توجد إجابة.وهذا يعني أيضًا أنه يتم تنفيذ RefreshRulesDelegate على مؤشر الترابط الرئيسي، وليس على مؤشر ترابط الخلفية.

لذلك، استخدم delegate.BeginInvoke أو ThreadPool وعند الانتهاء من استخدامها Control.[Begin]Invoke() لتحديث واجهة المستخدم.

نصائح أخرى

يمكنك القيام بذلك:

this.BeginInvoke(delegate
{
    RefreshRules(ctrl, ctrl.DsRules, ctrl.CptyId);
    RefreshCompleted();
});

يحرر:

سأفكر في إزالة وسيطة IAsyncResult من الطريقة RefreshCompleted واستخدام الحل أعلاه.

إذا كنت بحاجة حقًا لسبب ما إلى الاحتفاظ بالوسيطة IAsyncResult.يمكنك تنفيذ طريقة تمديد للتحكم:

public static IAsyncResult BeginInvoke(this Control control, Delegate del, object[] args, AsyncCallback callback, object state)
{
    CustomAsyncResult asyncResult = new CustomAsyncResult(callback, state);
    control.BeginInvoke(delegate
    {
        del.DynamicInvoke(args);
        asyncResult.Complete();
    }, args);

    return asyncResult;
}

public static void EndInvoke(this Control control, IAsyncResult asyncResult)
{
    asyncResult.EndInvoke();
}

ستحتاج إلى تحديد فئة CustomAsyncResult الخاصة بك، ويمكنك الحصول على وثائق حول كيفية القيام بذلك هنا

هل تريد أن يحدث "الشيء الإضافي" في خيط عامل؟(وإلا فسوف تقوم بتشغيله في th RefreshRules طريقة).ربما مجرد استخدام ThreadPool.QueueUserItem:

ThreadPool.QueueUserWorkItem(delegate { /* your extra stuff */ });

في نهاية (أو بعد) الخاص بك RefreshRules طريقة؟

للحصول على معلومات، قد تجد أنه من الأسهل والأسهل الاتصال BeginInvoke بطريقة مجهولة أيضًا:

this.BeginInvoke((MethodInvoker) delegate {
    RefreshRules(ctrl, ctrl.DsRules, ctrl.CptyId);
    ThreadPool.QueueUserWorkItem(delegate { /* your extra stuff */ });
});

يؤدي هذا إلى تجنب إنشاء نوع المفوض، ويوفر إمكانية التحقق من النوع عند مكالمتك RefreshRules - لاحظ أنه يلتقط ctrl, ومع ذلك - لذا إذا كنت في حلقة فستحتاج إلى نسخة:

var tmp = ctrl;
this.BeginInvoke((MethodInvoker) delegate {
    RefreshRules(tmp, tmp.DsRules, tmp.CptyId);
    ThreadPool.QueueUserWorkItem(delegate { /* your extra stuff */ });
});
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top