2009-02-06 15 views
47

मैं यह नहीं समझ सकता कि सी # विंडोज फॉर्म एप्लिकेशन को थ्रेड से टेक्स्टबॉक्स में कैसे लिखना है। Program.cs में उदाहरण के लिए हमारे पास मानक main() उस रूप ड्रॉ:किसी अन्य थ्रेड से टेक्स्टबॉक्स को लिखना?

static void Main() 
{ 
    Application.EnableVisualStyles(); 
    Application.SetCompatibleTextRenderingDefault(false); 
    Application.Run(new Form1()); 
} 

फिर हम Form1.cs में है:

public Form1() 
{ 
    InitializeComponent(); 

    new Thread(SampleFunction).Start(); 
} 

public static void SampleFunction() 
{ 
    while(true) 
     WindowsFormsApplication1.Form1.ActiveForm.Text += "hi. "; 
} 

मैं यह पूरी तरह से गलत के बारे में जा रहा हूँ? अपने MainForm पर

public partial class Form1 : Form 
{ 
    public Form1() 
    { 
     InitializeComponent(); 
     new Thread(SampleFunction).Start(); 
    } 

    public void AppendTextBox(string value) 
    { 
     if (InvokeRequired) 
     { 
      this.Invoke(new Action<string>(AppendTextBox), new object[] {value}); 
      return; 
     } 
     textBox1.Text += value; 
    } 

    void SampleFunction() 
    { 
     // Gets executed on a seperate thread and 
     // doesn't block the UI while sleeping 
     for(int i = 0; i<5; i++) 
     { 
      AppendTextBox("hi. "); 
      Thread.Sleep(1000); 
     } 
    } 
} 

उत्तर

47

InvokeRequired

public void AppendTextBox(string value) 
{ 
    if (InvokeRequired) 
    { 
     this.Invoke(new Action<string>(AppendTextBox), new object[] {value}); 
     return; 
    } 
    ActiveForm.Text += value; 
} 

हालांकि पाठ बॉक्स चेकों स्थापित करने के लिए एक समारोह बनाने:

अद्यतन

यहाँ काम कर कोड bendewey से प्रदान की नमूना है अपनी स्थिर विधि में आप बस कॉल नहीं कर सकते हैं।

WindowsFormsApplication1.Form1.AppendTextBox("hi. "); 

आप आप बस अपने SampleFunction स्थिर नहीं कर सकते हैं कहीं Form1 पर एक स्थिर संदर्भ के लिए है, लेकिन यह वास्तव में सिफारिश की है या आवश्यक नहीं है, यदि ऐसा है तो फिर आप सिर्फ

AppendTextBox("hi. "); 
कॉल कर सकते हैं

यह एक अलग धागे पर संलग्न होगा और यदि आवश्यक हो तो इनवॉव कॉल का उपयोग करके यूआई में घुसपैठ कर देगा।

पूर्ण नमूना

public partial class Form1 : Form 
{ 
    public Form1() 
    { 
     InitializeComponent(); 
     new Thread(SampleFunction).Start(); 
    } 

    public void AppendTextBox(string value) 
    { 
     if (InvokeRequired) 
     { 
      this.Invoke(new Action<string>(AppendTextBox), new object[] {value}); 
      return; 
     } 
     textBox1.Text += value; 
    } 

    void SampleFunction() 
    { 
     // Gets executed on a seperate thread and 
     // doesn't block the UI while sleeping 
     for(int i = 0; i<5; i++) 
     { 
      AppendTextBox("hi. "); 
      Thread.Sleep(1000); 
     } 
    } 
} 
+0

मैं अपने कोड की कोशिश की है, और यह काफी मेरे लिए काम नहीं कर रहा। मैं उत्तर साथी की सराहना करता हूं। –

+0

अधिक विशेष रूप से, यह संकलित करता है, लेकिन टेक्स्टबॉक्स को लगातार लिखा नहीं जा रहा है। –

+0

क्या आप अपना प्रयास कोड भेज सकते हैं? – bendewey

1

Control.BeginInvoke विधि पर एक नज़र डालें। बिंदु किसी अन्य धागे से यूआई नियंत्रण कभी अपडेट नहीं करना है। BeginInvoke नियंत्रण के यूआई थ्रेड (आपके मामले में, फॉर्म) में कॉल प्रेषित करेगा।

फॉर्म को पकड़ने के लिए, नमूना फ़ंक्शन से स्थिर संशोधक को हटाएं और इसका उपयोग करें। BegginInvoke() जैसा कि एमएसडीएन के उदाहरणों में दिखाया गया है।

13

या

public partial class Form1 : Form 
{ 
    public Form1() 
    { 
     InitializeComponent(); 
     new Thread(SampleFunction).Start(); 
    } 

    void SampleFunction() 
    { 
     // Gets executed on a seperate thread and 
     // doesn't block the UI while sleeping 
     for (int i = 0; i < 5; i++) 
     { 
      this.Invoke((MethodInvoker)delegate() 
      { 
       textBox1.Text += "hi"; 
      }); 
      Thread.Sleep(1000); 
     } 
    } 
} 
2

क्या और भी आसान सिर्फ BackgroundWorker नियंत्रण का उपयोग करने के लिए है है ...

4

की तरह आप धागा है कि नियंत्रण का मालिक से कार्रवाई करने के लिए की जरूरत है आप कर सकते हैं।

कि मैं कैसे कर रहा हूँ कि बहुत ज्यादा कोड शोर जोड़े बिना:

/// <summary> 
/// Invokes the specified <paramref name="action"/> on the thread that owns  
/// the <paramref name="control"/>.</summary> 
/// <typeparam name="TControl">type of the control to work with</typeparam> 
/// <param name="control">The control to execute action against.</param> 
/// <param name="action">The action to on the thread of the control.</param> 
public static void Invoke<TControl>(this TControl control, Action action) 
    where TControl : Control 
{ 
    if (!control.InvokeRequired) 
    { 
    action(); 
    } 
    else 
    { 
    control.Invoke(action); 
    } 
} 
10

मैं BeginInvoke बजाय Invoke का प्रयोग करेंगे के रूप में:

control.Invoke(() => textBox1.Text += "hi"); 

कहाँ अधिभार आह्वान Lokad Shared Libraries से एक सरल विस्तार है जितनी बार संभव हो, जब तक कि आपको वास्तव में इंतजार करने की आवश्यकता नहीं होती है जब तक कि आपका नियंत्रण अपडेट नहीं किया जाता है (जो आपके उदाहरण में मामला नहीं है)।BeginInvoke WinForms संदेश कतार पर प्रतिनिधि को पोस्ट करता है और कॉलिंग कोड तुरंत आगे बढ़ने देता है (आपके मामले में SampleFunction में फॉर-लूप)। Invoke न केवल प्रतिनिधि को पोस्ट करता है, बल्कि यह पूरा होने तक भी प्रतीक्षा करता है।

तो अपने उदाहरण से विधि AppendTextBox में आप BeginInvoke उस तरह के साथ Invoke जगह लेंगे:

public void AppendTextBox(string value) 
{ 
    if (InvokeRequired) 
    { 
     this.BeginInvoke(new Action<string>(AppendTextBox), new object[] {value}); 
     return; 
    } 
    textBox1.Text += value; 
} 

खैर और आप और भी अधिक फैंसी प्राप्त करना चाहते हैं, वहाँ भी SynchronizationContext वर्ग, आप की सुविधा देता है जो मूल रूप से है Control.Invoke/Control.BeginInvoke जैसा ही करें, लेकिन WinForms नियंत्रण संदर्भ की आवश्यकता नहीं होने के लाभ के साथ। HereSynchronizationContext पर एक छोटा सा ट्यूटोरियल है।

3

सबसे सरल, प्रतिनिधियों

if(textBox1.InvokeRequired == true) 
    textBox1.Invoke((MethodInvoker)delegate { textBox1.Text = "Invoke was needed";}); 

else 
    textBox1.Text = "Invoke was NOT needed"; 
2

यहाँ के बारे में देखभाल के बिना है कि मैं क्या CrossThreadException और एक अन्य धागे से पाठ बॉक्स के लिए लिख से बचने के लिए किया है।

यहां मेरा बटन क्लिक फ़ंक्शन है- मैं एक यादृच्छिक संख्या धागे उत्पन्न करना चाहता हूं और फिर getID() को कॉल करके अपनी आईडी प्राप्त करना चाहता हूं; उस कार्यकर्ता धागे में होने के दौरान विधि और टेक्स्टबॉक्स मान।

private void btnAppend_Click(object sender, EventArgs e) { 

     Random n = new Random(); 

     for (int i = 0; i < n.Next(1,5); i++) 
     { 
      label2.Text = "UI Id" + ((Thread.CurrentThread.ManagedThreadId).ToString()); 
      Thread t = new Thread(getId); 
      t.Start(); 
     } 

    } 

यहाँ getId (workerThread) कोड

public void getId() 
    { 
     int id = Thread.CurrentThread.ManagedThreadId; 
     //Note that, I have collected threadId just before calling 
     //*this.Invoke* 
     //method else it would be same as of UI thread inside the below code 
     //block 
     this.Invoke((MethodInvoker)delegate() 
     { 
      inpTxt.Text += "My id is" +"--"+id+Environment.NewLine; 
     }); 
संबंधित मुद्दे