إطار عمل/خيوط مضغوط - يتم عرض messageBox على عناصر التحكم الأخرى بعد تحديد الخيار

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

سؤال

أنا أعمل على تطبيق يجمع مجموعة من التحديثات ويثبتها من خادم خارجي، وأحتاج إلى بعض المساعدة في عملية الترابط.يتبع المستخدم هذه العملية:

  • زر النقرات
  • يتحقق الأسلوب من التحديثات، ويتم إرجاع العدد.
  • إذا كان أكبر من 0، فاسأل المستخدم إذا كان يريد التثبيت باستخدام messageBox.Show().
  • إذا كانت الإجابة بنعم، فسيتم تشغيله من خلال حلقة واستدعاء BeginInvoc() على طريقة run() لكل تحديث لتشغيله في الخلفية.
  • يحتوي فصل التحديث الخاص بي على بعض الأحداث التي يتم استخدامها لتحديث شريط التقدم وما إلى ذلك.

تحديثات شريط التقدم جيدة، ولكن لا يتم مسح messageBox بالكامل من الشاشة لأن حلقة التحديث تبدأ مباشرة بعد أن ينقر المستخدم على نعم (انظر لقطة الشاشة أدناه).

  • ما الذي يجب علي فعله حتى يختفي صندوق الرسائل على الفور قبل بدء حلقة التحديث؟
  • هل يجب أن أستخدم المواضيع بدلاً من BeginInvoc()؟
  • هل يجب أن أقوم بالتحقق الأولي من التحديث في موضوع منفصل واستدعاء messageBox.Show() من هذا الموضوع؟

شفرة

// Button clicked event handler code...
DialogResult dlgRes = MessageBox.Show(
    string.Format("There are {0} updates available.\n\nInstall these now?", 
    um2.Updates.Count), "Updates Available", 
    MessageBoxButtons.YesNo, 
    MessageBoxIcon.Question, 
    MessageBoxDefaultButton.Button2
);

if (dlgRes == DialogResult.Yes)
{
    ProcessAllUpdates(um2); 
}

// Processes a bunch of items in a loop
private void ProcessAllUpdates(UpdateManager2 um2)
{
    for (int i = 0; i < um2.Updates.Count; i++)
    {
        Update2 update = um2.Updates[i];

        ProcessSingleUpdate(update);

        int percentComplete = Utilities.CalculatePercentCompleted(i, um2.Updates.Count);

        UpdateOverallProgress(percentComplete);
    }
}

// Process a single update with IAsyncResult
private void ProcessSingleUpdate(Update2 update)
{
    update.Action.OnStart += Action_OnStart;
    update.Action.OnProgress += Action_OnProgress;
    update.Action.OnCompletion += Action_OnCompletion;

    //synchronous
    //update.Action.Run();

    // async
    IAsyncResult ar = this.BeginInvoke((MethodInvoker)delegate() { update.Action.Run(); });
}

لقطة شاشة

Windows Mobile Bug

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

المحلول

لا يتم تحديث واجهة المستخدم الخاصة بك لأن كل العمل يحدث في سلسلة رسائل واجهة المستخدم.مكالمتك إلى:

this.BeginInvoke((MethodInvoker)delegate() {update.Action.Run(); }) 

يقول استدعاء update.Action.Run() على مؤشر الترابط الذي أنشأ "هذا" (النموذج الخاص بك)، وهو مؤشر ترابط واجهة المستخدم.

Application.DoEvents()

سيعطي بالفعل مؤشر ترابط واجهة المستخدم الفرصة لإعادة رسم الشاشة، ولكنني سأميل إلى إنشاء مندوب جديد، والاتصال بـ BeginInvocation بشأن ذلك.

سيؤدي هذا إلى تنفيذ وظيفة update.Action.Run() على مؤشر ترابط منفصل مخصص من تجمع مؤشرات الترابط.يمكنك بعد ذلك الاستمرار في التحقق من IAsyncResult حتى اكتمال التحديث، والاستعلام عن كائن التحديث لمعرفة مدى تقدمه بعد كل عملية تحقق (لأنه لا يمكنك مطالبة مؤشر الترابط الآخر بتحديث شريط التقدم/واجهة المستخدم)، ثم استدعاء Application.DoEvents().

من المفترض أيضًا أن تتصل بـ EndInvoc() بعد ذلك وإلا فقد ينتهي بك الأمر إلى تسرب الموارد

سأميل أيضًا إلى وضع زر إلغاء في مربع حوار التقدم وإضافة مهلة، وإلا إذا توقف التحديث (أو استغرق وقتًا طويلاً) فسيتم قفل تطبيقك إلى الأبد.

نصائح أخرى

هل حاولت وضع أ

Application.DoEvents()

هنا

if (dlgRes == DialogResult.Yes)
{
   Application.DoEvents(); 
   ProcessAllUpdates(um2); 
}

@ جون سيبلي

يمكنك الابتعاد عن لا استدعاء EndInvocation عند التعامل مع WinForms دون أي عواقب سلبية.

الاستثناء الوحيد الموثق للقاعدة الذي أعرفه موجود في Windows Forms، حيث يُسمح لك رسميًا بالاتصال بـ Control.BeginInvoc دون الحاجة إلى الاتصال بـ Control.EndInvoc.

ولكن في جميع الحالات الأخرى عند التعامل مع نمط Begin/End Async، يجب أن تفترض أنه سوف يتسرب، كما ذكرت.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top