خطأ في ترجمة C#:"لا يمكن استدعاء Invoc أو BeginInvocation على عنصر التحكم حتى يتم إنشاء مقبض النافذة."

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

سؤال

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

رمز النموذج الرئيسي:

using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.IO;
using System.Data.OleDb;
using System.Collections.Specialized;
using System.Text;
using System.Threading;

delegate void logAdd(string message);

namespace LCR_ShepherdStaffupdater_1._0
{
    public partial class Main : Form
    {
        public Main()
        {
            InitializeComponent();
        }

        public void add(string message)
        {
            this.Log.Items.Add(message);
        }
        public void logAdd(string message)
        {   /////////////////////////// COMPILER ERROR BELOW ///////////
            this.Invoke(new logAdd(add), new object[] { message }); // Compile error occurs here     
        }////////////////////////////// COMPILER ERROR ABOVE ///////////

        private void exitProgramToolStripMenuItem_Click(object sender, EventArgs e) 
        {
            Application.Exit(); 
        }
        private void aboutToolStripMenuItem1_Click(object sender, EventArgs e)
        {
            Form aboutBox = new AboutBox1(); 
            aboutBox.ShowDialog(); 
        }

        private void settingsToolStripMenuItem_Click(object sender, EventArgs e)
        {
        }

        private void settingsToolStripMenuItem1_Click(object sender, EventArgs e)
        {
            settingsForm.settings.ShowDialog();
        }

        private void synchronize_Click(object sender, EventArgs e)
        {
            string message = "Here my message is"; // changed this
            ErrorLogging.updateLog(message);  // changed this
        }

    }

    public class settingsForm 
    {
        public static Form settings = new Settings();
    }

}

رمز فئة التسجيل:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace LCR_ShepherdStaffupdater_1._0
{
    public class Logging
    {
        static Main mainClass = new Main();
        static logAdd logAddDelegate;

        public static void updateLog(string message)
        {
            logAddDelegate = mainClass.logAdd;
            logAddDelegate(message);
        }
    }
}
  • تجميع خطأ:

    DOCTYPE html> <html lang=en> <meta charset=utf-8> <meta name=viewport content="initial-scale=1, minimum-scale=1, width=device-width"> <title>Error 400 (Bad Request)!!1</title> <style> *{margin:0;padding:0}html,code{font:15px/22px arial,sans-serif}html{background:#fff;color:#222;padding:15px}body{margin:7% auto 0;max-width:390px;min-height:180px;padding:30px 0 15px}* > body{background:url(//www.google.com/images/errors/robot.png) 100% 5px no-repeat;padding-right:205px}p{margin:11px 0 22px;overflow:hidden}ins{color:#777;text-decoration:none}a img{border:0}@media screen and (max-width:772px){body{background:none;margin-top:0;max-width:none;padding-right:0}}#logo{background:url(//www.google.com/images/branding/googlelogo/1x/googlelogo_color_150x54dp.png) no-repeat;margin-left:-5px}@media only screen and (min-resolution:192dpi){#logo{background:url(//www.google.com/images/branding/googlelogo/2x/googlelogo_color_150x54dp.png) no-repeat 0% 0%/100% 100%;-moz-border-image:url(//www.google.com/images/branding/googlelogo/2x/googlelogo_color_150x54dp.png) 0}}@media only screen and (-webkit-min-device-pixel-ratio:2){#logo{background:url(//www.google.com/images/branding/googlelogo/2x/googlelogo_color_150x54dp.png) no-repeat;-webkit-background-size:100% 100%}}#logo{display:inline-block;height:54px;width:150px} </style> <a href=//www.google.com/><span id=logo aria-label=Google></span></a> <p><b>400.</b> <ins>That’s an error.</ins> <p>Your client has issued a malformed or illegal request. <ins>That’s all we know.</in

لقد حاولت بالفعل إنشاء مؤشر على عنصر السجل...ولكن ذلك لم ينجح.المشكلة هي أنه ليس لدي أدنى فكرة عما أفعله وقد بحثت في Google على نطاق واسع فقط للعثور على إجابات غامضة.

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

شكرًا لك!!!

يحرر:

مشروعي كبير إلى حد ما، ولكن هذه هي العناصر الوحيدة التي تسبب هذه المشكلة بالتحديد.

سجل هو RichTextBox1 الخاص بي (Log.Items.Add(message)) لقد قمت بإعادة تسميته إلى Log بحيث يسهل إعادة كتابته.

أنا أتصل بـupdateLog(message) من نموذج مختلف...اسمح لي بتحديث ذلك هنا (على الرغم من أنه لا يوجد فرق حيث أتصل بـupdateLog(message) منه لا يزال يعطيني هذا الخطأ)

سيتعين عليكم يا رفاق أن تجعلوا الأمور أكثر بساطة بالنسبة لي... وأن تقدموا أمثلة.لا أفهم نصف كل ما تقولونه هنا يا رفاق...ليس لدي أدنى فكرة عن كيفية العمل مع استدعاء الأساليب والمقابض.لقد بحثت في حماقة منه أيضًا ...

التعديل الثاني:

أعتقد أنني حددت المشكلة، لكن لا أعرف كيفية إصلاحها.

في فصل التسجيل الخاص بي، أستخدم هذا الرمز لإنشاء mainClass:

static MainClass = new Main();

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

عندما أتصل بـ updateLog(message) أعتقد أنني أحاول تحديث السجل (richtextbox) في الكيان الثاني لـ Main() والمعروف أيضًا باسم mainClass.بالطبع، سيؤدي القيام بذلك إلى حدوث هذا الاستثناء لأنني لم أر حتى تلك النسخة المتماثلة من الإصدار الرئيسي الحالي الذي أستخدمه.

وهذا ما أسعى إليه، شكرًا لأحد الأشخاص الذين أجابوا:

Main mainClass = Application.OpenForms.OfType<Main>().First();
logAddDelegate = mainClass.logAdd; 
logAddDelegate(message);

أحتاج إلى إنشاء mainClass ليس باستخدام عامل التشغيل new() لأنني لا أريد إنشاء مخطط جديد للنموذج الذي أريد أن أتمكن من تحرير النموذج الحالي.

الكود أعلاه لا يعمل، ولم أتمكن حتى من العثور على التطبيق.هل هذا حتى بناء جملة C#؟

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

التعديل النهائي:

لقد اكتشفت ذلك بفضل أحد المستخدمين أدناه.هذا هو الكود المحدث الخاص بي:

رمز النموذج الرئيسي:

using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.IO;
using System.Data.OleDb;
using System.Collections.Specialized;
using System.Text;
using System.Threading;

delegate void logAdd(string message);

namespace LCR_ShepherdStaffupdater_1._0
{
    public partial class Main : Form
    {
        private static Main mainFormForLogging;
        public static Main MainFormForLogging
        {
            get
            {
                return mainFormForLogging;
            }
        }

        public Main()
        {
            InitializeComponent();
            if (mainFormForLogging == null)
            {
                mainFormForLogging = this;
            }
        }

        public void add(string message)
        {
            this.Log.Items.Add(message);
        }
        public void logAdd(string message)
        {
            this.Log.BeginInvoke(new logAdd(add), new object[] { message });
        }

        private void exitProgramToolStripMenuItem_Click(object sender, EventArgs e) 
        {
            Application.Exit(); 
        }
        private void aboutToolStripMenuItem1_Click(object sender, EventArgs e)
        {
            Form aboutBox = new AboutBox1(); 
            aboutBox.ShowDialog(); 
        }

        private void settingsToolStripMenuItem_Click(object sender, EventArgs e)
        {
        }

        private void settingsToolStripMenuItem1_Click(object sender, EventArgs e)
        {
            settingsForm.settings.ShowDialog();
        }

        private void synchronize_Click(object sender, EventArgs e)
        {
            add("test");
            Logging.updateLog("testthisone");
            //DatabaseHandling.createDataSet();
        }

    }

    public class settingsForm 
    {
        public static Form settings = new Settings();
    }

}

رمز فئة التسجيل:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace LCR_ShepherdStaffupdater_1._0
{
    public class Logging
    {

        static Main mainClass = Main.MainFormForLogging;
        static logAdd logAddDelegate;

        public static void updateLog(string message)
        {
            logAddDelegate = mainClass.logAdd;
            logAddDelegate(message);
        }
    }
}
هل كانت مفيدة؟

المحلول

حسنًا، سأبدأ من جديد.

لكي تفهم ما يحدث، تحتاج إلى فهم كيفية ارتباط .NET وWindows ببعضهما البعض.يعمل .NET على نظام التشغيل Windows ويشتمل على العديد من مفاهيم Win32 الأصلية مثل النافذة وعرض القائمة ومربع التحرير (اسم Win32 لمربع نص قياسي).هذا يعني أنه يمكن أن يكون لديك مثيل .NET صالح لمربع نص أو نموذج، ولكن ليس لديك إصدار Windows الأساسي لذلك العنصر (EditBox أو Window) حتى الآن.عندما يكون HandleCreated صحيحًا، يتم إنشاء إصدار Windows للعنصر.

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

الطريقة العامة لتشغيل التطبيق هي استدعاء Application.Run(new Main()) في أسلوب بدء التشغيل الخاص بك، والذي يكون عادة في فئة البرنامج ويسمى Main.أنت بحاجة إلى أن يشير المسجل الخاص بك إلى هذا المثيل لـ main.

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

public partial class Main : Form
{
    private static Main mainFormForLogging;
    public static Main MainFormForLogging
    {
        get
        {
            return mainFormForLogging;
        }
    }

    public Main()
    {
        InitializeComponent();

        if (mainFormForLogging == null)
        {
            mainFormForLogging = this;
        }
    }

    protected void Dispose(bool disposing)
    {
         if (disposing)
         {
             if (this == mainFormForLogging)
             {
                mainFormForLogging = null;
             }
         }

         base.Dispose(disposing);
    }
}

نصائح أخرى

لقد قمت بحل هذه المشكلة في الماضي باستخدام الطريقة التالية:

private void invokeOnFormThread(MethodInvoker method)
{
    if (IsHandleCreated)
         Invoke(new EventHandler(delegate { method(); }));
    else
        method();
}

يتصل invokeOnFormThread بدلاً من الاستدعاء.سيستخدم مؤشر ترابط النموذج فقط إذا تم إنشاء مؤشر بالفعل، وإلا فإنه سيستخدم مؤشر ترابط المتصل.

عندما تحصل على هذا الخطأ، فهذا يعني دائمًا أنك حاولت التعامل مع عنصر تحكم أو نموذج قبل إنشائه فعليًا.

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

في هذه الحالة، يمكن التخلص من معظم الأخطاء عن طريق تعيين علامة في نهاية حدث تحميل النموذج ومحاولة التعامل مع عناصر تحكم النموذج فقط بعد تعيين تلك العلامة.

إنه خطأ في وقت التشغيل، وليس خطأ في المترجم.

يجب أن يتم عرض النموذج "الرئيسي" الخاص بك (ومن ثم تم إنشاء مقبض النافذة) قبل أن تتمكن من إجراء مكالمات إلى BeginInvention أو الاستدعاء عليه.

ما أفعله عادةً في هذه المواقف هو ترك الأمر للنموذج لتحديد ما إذا كان يحتاج إلى استخدام استدعاء BeginInvoc أو Invoc.يمكنك اختبار ذلك من خلال استدعاء InvocRequired (راجع MSDN).

لذا بالنسبة للمبتدئين، سأتخلص من استدعاء logAddDelegate في طريقة updateLog الخاصة بفئة Loggin.ما عليك سوى إجراء اتصال مباشر بالنموذج لإضافة سجل.مثل ذلك:

public partial class Main : Form
{
    public Main()
    {
        InitializeComponent();
    }

    private delegate void AddNewLogMessageEventHandler(string message);

    public void AddLogMessage(string message)
    {
        object[] args = new object[1];
        args[0] = message;

        if (InvokeRequired)
            BeginInvoke(new AddNewLogMessageEventHandler(AddLog), args);
        else
            Invoke(new AddNewLogMessageEventHandler(AddLog), args);
    }

    private void AddLog(string message)
    {
        this.Log.Items.Add(message);
    }
 }

}

لذا يمكنك أن ترى أن النموذج نفسه هو المسؤول عن تحديد ما إذا كان يحتاج إلى استدعاء الطريقة بشكل غير متزامن أم لا.

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

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

فكر في الفصل باعتباره "مخططًا".كل مثيل للفئة (تم إنشاؤه باستخدام الكلمة "جديد") هو كائن آخر تم إنشاؤه من المخطط.إن مجرد مشاركة كائنين (في هذه الحالة، النموذجان الرئيسيان) في نفس المخطط، لا يعني أنه يمكنك استخدامهما بالتبادل.في هذه الحالة، لديك بالفعل نموذج رئيسي، وتريد "إعادة استخدامه".يمكنك المحاولة:

MainClass myMainForm = Application.OpenForms.OfType<MainClass>().First();
logAddDelegate = myMainForm.logAdd; 
logAddDelegate(message);

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

أتمنى أن يساعدك هذا.

هذا للمساعدة في حالة وقوع أي شخص آخر في هذا الأمر.مشكلتي:فب.نت:DOCTYPE html> <html lang=en> <meta charset=utf-8> <meta name=viewport content="initial-scale=1, minimum-scale=1, width=device-width"> <title>Error 400 (Bad Request)!!1</title> <style> *{margin:0;padding:0}html,code{font:15px/22px arial,sans-serif}html{background:#fff;color:#222;padding:15px}body{margin:7% auto 0;max-width:390px;min-height:180px;padding:30px 0 15px}* > body{background:url(//www.google.com/images/errors/robot.png) 100% 5px no-repeat;padding-right:205px}p{margin:11px 0 22px;overflow:hidden}ins{color:#777;text-decoration:none}a img{border:0}@media screen and (max-width:772px){body{background:none;margin-top:0;max-width:none;padding-right:0}}#logo{background:url(//www.google.com/images/branding/googlelogo/1x/googlelogo_color_150x54dp.png) no-repeat;margin-left:-5px}@media only screen and (min-resolution:192dpi){#logo{background:url(//www.google.com/images/branding/googlelogo/2x/googlelogo_color_150x54dp.png) no-repeat 0% 0%/100% 100%;-moz-border-image:url(//www.google.com/images/branding/googlelogo/2x/googlelogo_color_150x54dp.png) 0}}@media only screen and (-webkit-min-device-pixel-ratio:2){#logo{background:url(//www.google.com/images/branding/googlelogo/2x/googlelogo_color_150x54dp.png) no-repeat;-webkit-background-size:100% 100%}}#logo{display:inline-block;height:54px;width:150px} </style> <a href=//www.google.com/><span id=logo aria-label=Google></span></a> <p><b>400.</b> <ins>That’s an error.</ins> <p>Your client has issued a malformed or illegal request. <ins>That’s all we know.</in

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

logAddDelegate(message);

أعتقد أنك تتصل بهذا قبل رفع الحدث Form_Load.قم بإصلاح الكود الخاص بك لانتظار تحميل النموذج قبل الاتصال بـ logAddDelegate(...) أي.قبل استدعاء Logging.updateLog()

هل هذا هو الكود الخاص بك بالضبط؟انت تتصل this.Log.Items.Add(message); في طريقة add(string) الخاصة بك، لكن فئة التسجيل الخاصة بك تسمى Logging، وليس Log.هل لديك نموذج آخر يسمى السجل ربما؟إذا لم يتم إنشاء هذا النموذج عند استدعاء أسلوب الإضافة، فسوف تحصل على هذا الاستثناء.

لقد وجدت InvokeRequired غير موثوق بها، لذلك أنا ببساطة استخدم

if (!this.IsHandleCreated)
{
    this.CreateHandle();
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top