يقوم WebClient.DownloadDataAsync بتجميد واجهة المستخدم الخاصة بي

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

  •  06-07-2019
  •  | 
  •  

سؤال

لدي في منشئ النموذج الخاص بي، بعد التهيئة Component الكود التالي:

using (WebClient client = new WebClient())
{
    client.DownloadDataCompleted += new DownloadDataCompletedEventHandler(client_DownloadDataCompleted);
    client.DownloadDataAsync("http://example.com/version.txt");
}

عندما أبدأ النموذج الخاص بي، لا تظهر واجهة المستخدم حتى يتم رفع Client_DownloadDataCompleted.طريقة Client_DownloadDataCompleted فارغة، لذا لا توجد مشكلة هناك.

ما الذي أفعله خطأ؟كيف من المفترض القيام بذلك دون تجميد واجهة المستخدم؟

شكرا على وقتك.
أطيب التحيات.

الكود الكامل:

Program.cs

using System;
using System.Windows.Forms;

namespace Lala
{
    static class Program
    {
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new Form1());
        }
    }
}

Form1.cs

using System;
using System.Net;
using System.Windows.Forms;

namespace Lala
{
    public partial class Form1 : Form
    {
        WebClient client = new WebClient();

        public Form1()
        {
            client.DownloadDataCompleted += new DownloadDataCompletedEventHandler(client_DownloadDataCompleted);
            client.DownloadDataAsync(new Uri("http://www.google.com"));
            InitializeComponent();
        }

        void client_DownloadDataCompleted(object sender, DownloadDataCompletedEventArgs e)
        {
            textBox1.Text += "A";
        }
    }

    partial class Form1
    {
        /// <summary>
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.IContainer components = null;

        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        #region Windows Form Designer generated code

        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            this.button1 = new System.Windows.Forms.Button();
            this.textBox1 = new System.Windows.Forms.TextBox();
            this.SuspendLayout();
            // 
            // button1
            // 
            this.button1.Location = new System.Drawing.Point(12, 12);
            this.button1.Name = "button1";
            this.button1.Size = new System.Drawing.Size(75, 23);
            this.button1.TabIndex = 0;
            this.button1.Text = "button1";
            this.button1.UseVisualStyleBackColor = true;
            // 
            // textBox1
            // 
            this.textBox1.Location = new System.Drawing.Point(12, 41);
            this.textBox1.Multiline = true;
            this.textBox1.Name = "textBox1";
            this.textBox1.Size = new System.Drawing.Size(468, 213);
            this.textBox1.TabIndex = 1;
            // 
            // Form1
            // 
            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.ClientSize = new System.Drawing.Size(492, 266);
            this.Controls.Add(this.textBox1);
            this.Controls.Add(this.button1);
            this.Name = "Form1";
            this.Text = "Form1";
            this.ResumeLayout(false);
            this.PerformLayout();

        }

        #endregion

        private System.Windows.Forms.Button button1;
        private System.Windows.Forms.TextBox textBox1;
    }
}
هل كانت مفيدة؟

المحلول

الآن بعد أن حصلنا على الكود الكامل، أستطيع أن أقول إنني بالتأكيد لا أرى المشكلة - ليس تمامًا كما هو موضح، على أي حال.

لقد حصلت على القليل من التسجيل للإشارة إلى ما قبل وبعد مكالمات DownloadDataAsync، ومتى يتم تشغيل المعالج المكتمل.إذا قمت بتنزيل ملف كبير عبر شبكة الجيل الثالث، فهناك يكون توقف مؤقت بين "قبل" و"بعد" لكن واجهة المستخدم تظهر قبل فترة طويلة من اكتمال تنزيل الملف.

لدي شك في أن يتصل يتم بشكل متزامن، ولكن التنزيل الفعلي يكون غير متزامن.لا يزال هذا أمرًا مؤسفًا بالطبع - وربما يكون وضع كل ذلك في موضوع مختلف هو الطريق الصحيح - ولكن إذا كنت على حق، فهو على الأقل يستحق المعرفة.

نصائح أخرى

واجهت نفس المشكلة، ووجدت الحل.مناقشة معقدة للغاية هنا:http://social.msdn.microsoft.com/Forums/en-US/a00dba00-5432-450b-9904-9d343c11888d/webclient-downloadstringasync-freeze-my-ui?forum=ncl

باختصار، تكمن المشكلة في قيام عميل الويب بالبحث عن خوادم بروكسي وتعليق التطبيق.الحل التالي يساعد:

WebClient webClient = new WebClient();
webClient.Proxy = null;
... Do whatever else ...

تريد تشغيل التنزيل في موضوع مختلف، راجع هذا كنقطة بداية.

أظن بشدة أن الأمر يتعلق بالتخلص من WebClient بينما لا تزال تستخدمه لإجراء مكالمة غير متزامنة.

حاول إزالة عبارة الاستخدام، واستدعاء Dispose في معالج الأحداث بدلاً من ذلك.(أو للاختبار فقط، فلا تقلق بشأن التخلص منه على الإطلاق.

إذا كان بإمكانك نشر أ برنامج قصير ولكن كامل الذي يوضح المشكلة، سيكون ذلك مفيدًا حقًا.

بالإضافة إلى التخلص من شيء ربما لا يزال قيد تشغيل المكالمة غير المتزامنة التي ذكرها أشخاص آخرون، أود أن أوصي بشدة بعدم القيام بأشياء ثقيلة مثل هذه في مُنشئ النموذج.

قم بذلك من خلال تجاوز OnLoad بدلاً من ذلك، حيث ستتمكن أيضًا من التحقق من خاصية DesignMode التي ستساعدك على تجنب عدة مستويات من الجحيم مع مصمم نماذج VS.

غير محذوفة: كما يفكر الكثيرون في استخدام الكتلة مثلي، فقد أكدت ذلك لا متعلق ب.

هل يمكنك إزالة كتلة الاستخدام، أعتقد أنها في انتظار التخلص من مثيل عميل الويب.

تنزيل DataAsync مقابل.تنزيل البيانات في موضوع غير واجهة المستخدم:

يعد DownloadDataAsync أمرًا رائعًا لأنه لا يربط فعليًا مؤشر ترابط حتى معالجة DownloadDataCompletedEvent، بعد تقديم الطلب واستجابة الخادم.

أعتقد أن Jon Skeet يسير على الطريق الصحيح - لقد قرأت أن تحليل DNS يجب أن يكتمل بشكل متزامن قبل وضع طلب HTTP غير المتزامن في قائمة الانتظار وإرجاع استدعاء DownloadDataAsync.

هل يمكن أن يكون قرار DNS بطيئًا؟

لقد اختبرت للتو نفس الشيء في مشروع WPF ضمن VS2010، .NET 4.

أقوم بتنزيل ملف يحتوي على شريط تقدم لإظهار النسبة المئوية المكتملة باستخدام WebClient.DownloadDataCompleted وما إلى ذلك.

ولدهشتي، وجدت نفس الشيء الذي ذكره @Dan:داخل مصحح الأخطاء يقوم بحظر الخيط بطريقة مضحكة.في تصحيح الأخطاء، يتم تحديث مقياس التقدم الخاص بي بنسبة 1%، ثم لا يفعل شيئًا لفترة من الوقت، ثم يتم تحديثه مرة أخرى فجأة بنسبة 100%.(تتم طباعة عبارات Debug.WriteLn بسلاسة طوال الوقت).وبين هذين الوقتين، يتم تجميد واجهة المستخدم.

ولكن خارج مصحح الأخطاء، يتحرك شريط التقدم بسلاسة من 0% إلى 100%، ولا تتجمد واجهة المستخدم أبدًا.وهو ما كنت تتوقعه.

جرب هذا:

client.Proxy = GlobalProxySelection.GetEmptyProxy();

هذا يبدو غريبا بعض الشيء بالنسبة لي.

حاول الاحتفاظ بمرجع عضو في WebClient حتى لا تدمره في المُنشئ، ربما يتم حظره على العميل.Dispose()

تحاول عبارة use() استدعاء Dispose() الخاص بـ WebClient أثناء استمرار التنزيل.من المحتمل أن تنتظر طريقة التخلص انتهاء التنزيل قبل المتابعة.

حاول عدم استخدام عبارة use() وتخلص من WebClient في حدث DownloadDataCompleted.

يمكنني تشغيل الكود الخاص بك بشكل جيد.ويظهر النموذج ويتم الانتهاء من التنزيل بعد ظهور النموذج.

ليس لدي أي تجميد كما ذكرت.

أعتقد أن الأمر له علاقة بالبيئة التي تديرها بداخله.

ما هو إصدار .NET/Visual Studio الذي تستخدمه؟

لقد قمت بتجربة الكود الخاص بك وهو يعمل بشكل جيد.

هل يمكنك نشر الطريقة الرئيسية (Args[]) وقيمة a و b عند تشغيل هذا:

    int a, b;
    ThreadPool.GetMaxThreads(out a, out b);

لقد جربته في .NET 3.5 وVS2008.أنا في حيرة من أمري، لكني مقتنع أن الأمر يتعلق بالإعداد الموجود على جهازك.ليس الرمز.تحقق من هذه الأشياء:

  • تحقق من تجمع الخيوط (أعلاه).أحصل على = 250 ب = 1000
  • قم بتعطيل جميع المكونات الإضافية التابعة لجهات خارجية
  • تحميل VS "نظيف" (هل قمت بإعادة التشغيل)
  • أغلق أكبر عدد ممكن من البرامج/الخدمات
  • تحقق من تكوين IE الخاص بك.أعتقد أن هذا الفصل يستخدم رمز/إعدادات IE
  • جدار الحماية؟مضاد للفيروسات؟
  • جربه على كمبيوتر آخر

امممم....مجرد فضول

هل لديك أي جدران الحماية على؟

أي جدران الحماية على الإطلاق على جهازك؟

ربما ZoneAlarm؟

في تجربتي، فإنه يقوم بحظر الخيط عند تشغيل تصحيح أخطاء المشروع (تشغيله داخل Visual Studio) وعند الوصول إلى الخادم لأول مرة.

عند تشغيل ملف exe المترجم، لا يمكن إدراك الحظر.

لا تزال هذه المشكلة مستمرة حتى في VS2015.لقد اكتشفت ذلك أخيرًا، فلا حرج في الكود الذي يستخدمه الأشخاص، المشكلة في الواقع هي مدى سرعة كتابة البيانات إلى عنصر تحكم التسمية وهذا ما يوقف العملية ويتسبب في تجميد واجهة المستخدم الخاصة بك.حاول استبدال التسميات التي تشير إليها بمربعات النص في معالجات التقدم التي تم تغييرها.أدى هذا إلى حل جميع التأخيرات في واجهة المستخدم بالنسبة لي، وآمل أن يساعد هذا الآخرين لأنني أمضيت ساعات في محاولة معرفة سبب عمل الكود في بعض الأحيان دون الآخرين.

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