2009-07-16 9 views
9

मैं सी # के साथ नया हूं और मैं एक साधारण क्लाइंट सर्वर चैट एप्लिकेशन बनाने की कोशिश कर रहा हूं।किसी अन्य थ्रेड से GUI पर टेक्स्टबॉक्स को अपडेट करने के लिए

मेरे पास मेरे क्लाइंट विंडोज़ फॉर्म पर RichTextBox है और मैं उस नियंत्रण को सर्वर से अद्यतन करने की कोशिश कर रहा हूं जो किसी अन्य वर्ग में है। जब मैं इसे करने का प्रयास करता हूं तो मुझे त्रुटि मिलती है: "क्रॉस-थ्रेड ऑपरेशन मान्य नहीं है: टेक्स्टबॉक्स 1 को उस थ्रेड के अलावा किसी थ्रेड से एक्सेस किया गया है जिसे" "बनाया गया था।

यहाँ मेरे Windows फार्म के कोड:

private Topic topic; 
public RichTextBox textbox1; 
bool check = topic.addUser(textBoxNickname.Text, ref textbox1, ref listitems); 

विषय वर्ग:

public class Topic : MarshalByRefObject 
{ 
    //Some code 
public bool addUser(string user, ref RichTextBox textBox1, ref List<string> listBox1) 
{ 
    //here i am trying to update that control and where i get that exception 
    textBox1.Text += "Connected to server... \n"; 
} 

तो ऐसा करने के लिए? मैं किसी अन्य धागे से टेक्स्टबॉक्स नियंत्रण कैसे अपडेट कर सकता हूं?


मैं .NET remoting का उपयोग कर कुछ मूल चैट क्लाइंट/सर्वर एप्लिकेशन बनाने की कोशिश कर रहा हूं। मैं विंडोज़ फॉर्म क्लाइंट एप्लिकेशन और कंसोल सर्वर एप्लिकेशन को अलग .exe फ़ाइलों के रूप में बनाना चाहता हूं। यहां क्लाइंट से सर्वर फ़ंक्शन AddUser को कॉल करने का प्रयास कर रहा हूं और मैं AddUser फ़ंक्शन को अपने जीयूआई अपडेट करना चाहता हूं। मैंने कोड को संशोधित किया जैसा कि आपने जॉन को सुझाव दिया था लेकिन अब क्रॉस-थ्रेड अपवाद के बजाय मुझे यह अपवाद मिला है ... "सीरियलाइजेशन अपवाद: असेंबली में टाइप टॉपिक को धारावाहिक के रूप में चिह्नित नहीं किया गया है"

बीमार मेरे पूरे कोड को पोस्ट करें, इसे यथासंभव सरल रखने की कोशिश करेंगे।
कोई भी सुझाव स्वागत है। बहुत धन्यवाद।

सर्वर:

namespace Test 
{ 
    [Serializable] 
    public class Topic : MarshalByRefObject 
    { 
     public bool AddUser(string user, RichTextBox textBox1, List<string> listBox1) 
     { 
      //Send to message only to the client connected 
      MethodInvoker action = delegate { textBox1.Text += "Connected to server... \n"; }; 
      textBox1.BeginInvoke(action); 
      //... 
      return true; 
     } 

     public class TheServer 
     { 
      public static void Main() 
      { 

       int listeningChannel = 1099; 

       BinaryServerFormatterSinkProvider srvFormatter = new BinaryServerFormatterSinkProvider(); 
       srvFormatter.TypeFilterLevel = TypeFilterLevel.Full; 

       BinaryClientFormatterSinkProvider clntFormatter = new BinaryClientFormatterSinkProvider(); 

       IDictionary props = new Hashtable(); 
       props["port"] = listeningChannel; 

       HttpChannel channel = new HttpChannel(props, clntFormatter, srvFormatter); 
       // Register the channel with the runtime    
       ChannelServices.RegisterChannel(channel, false); 
       // Expose the Calculator Object from this Server 
       RemotingConfiguration.RegisterWellKnownServiceType(typeof(Topic), 
                "Topic.soap", 
                WellKnownObjectMode.Singleton); 
       // Keep the Server running until the user presses enter 
       Console.WriteLine("The Topic Server is up and running on port {0}", listeningChannel); 
       Console.WriteLine("Press enter to stop the server..."); 
       Console.ReadLine(); 
      } 
     } 
    } 

} 

विंडोज प्रपत्र ग्राहक:

// Create and register a channel to communicate to the server 
     // The Client will use the port passed in as args to listen for callbacks 

     BinaryServerFormatterSinkProvider srvFormatter = new BinaryServerFormatterSinkProvider(); 
     srvFormatter.TypeFilterLevel = TypeFilterLevel.Full; 
     BinaryClientFormatterSinkProvider clntFormatter = new BinaryClientFormatterSinkProvider(); 
     IDictionary props = new Hashtable(); 
     props["port"] = 0; 

     channel = new HttpChannel(props, clntFormatter, srvFormatter); 
     //channel = new HttpChannel(listeningChannel); 

     ChannelServices.RegisterChannel(channel, false); 
     // Create an instance on the remote server and call a method remotely 
     topic = (Topic)Activator.GetObject(typeof(Topic), // type to create 
     "http://localhost:1099/Topic.soap" // URI 
     ); 


     private Topic topic; 
     public RichTextBox textbox1; 
     bool check = topic.addUser(textBoxNickname.Text,textBox1, listitems); 

उत्तर

32

आप या तो BackgroundWorker, या Control उपयोग करने के लिए की जरूरत है। /BeginInvoke। बेनामी फ़ंक्शंस - या तो अज्ञात विधियां (सी # 2.0) या लैम्ब्डा एक्सप्रेशन (सी # 3.0) इससे पहले की तुलना में आसान बनाते हैं। नोट करने के लिए

public bool AddUser(string user, RichTextBox textBox1, List listBox1) 
{ 
    MethodInvoker action = delegate 
     { textBox1.Text += "Connected to server... \n"; }; 
    textBox1.BeginInvoke(action); 
} 

कुछ बातें:

आपके मामले में, आप करने के लिए अपने कोड बदल सकते हैं

  • नेट सम्मेलनों के अनुरूप करने के लिए, इस AddUser
  • आप बुलाया जाना चाहिए संदर्भ द्वारा टेक्स्टबॉक्स या सूची बॉक्स को पास करने की आवश्यकता नहीं है। मुझे संदेह है कि आप समझ नहीं पाएंगे कि ref वास्तव में क्या है - अधिक जानकारी के लिए my article on parameter passing देखें। पहले पाठ बॉक्स वास्तव में अद्यतन किया गया है, ताकि AddUser वापस आ सकते हैं -
  • Invoke और BeginInvoke के बीच अंतर यह है कि BeginInvoke प्रतिनिधि के लिए इंतजार नहीं होंगे यूआई धागे पर कहा जा इससे पहले कि यह जारी है। यदि आप असीमित व्यवहार नहीं चाहते हैं, तो Invoke का उपयोग करें।
  • मेरा कुछ सहित कई नमूने (में!) आप Control.InvokeRequired का उपयोग करके लोगों को यह देखने के लिए पाएंगे कि उन्हें Invoke/BeginInvoke पर कॉल करने की आवश्यकता है या नहीं। यह वास्तव में ज्यादातर मामलों में overkill है - Invoke/BeginInvoke बुला भले ही आप की जरूरत नहीं है में कोई वास्तविक नुकसान वहाँ है, और अक्सर हैंडलर केवल कभी एक गैर यूआई धागे से वैसे भी बुलाया जाएगा। चेक को छोड़कर कोड को सरल बनाता है।
  • जैसा कि मैंने पहले उल्लेख किया है, आप BackgroundWorker का भी उपयोग कर सकते हैं; यह विशेष रूप से सलाखों आदि के लिए उपयुक्त है, लेकिन इस मामले में यह संभवतः आपके वर्तमान मॉडल को रखना आसान है।

इस और अन्य थ्रेडिंग विषयों पर अधिक जानकारी के लिए, my threading tutorial या Joe Albahari's one देखें।

10

उपयोग आह्वान विधि

// Updates the textbox text. 
private void UpdateText(string text) 
{ 
    // Set the textbox text. 
    yourTextBox.Text = text; 
} 

अब, एक प्रतिनिधि विधि के समान हस्ताक्षर है कि पहले से परिभाषित किया गया है कि बनाने के लिए:

public delegate void UpdateTextCallback(string text); 

अपने धागा में, आप आह्वान पद्धति पर कॉल कर सकते हैं आपका टेक्स्टबॉक्स, प्रतिनिधि को कॉल करने के साथ-साथ पैरामीटर पास कर रहा है।

yourTextBox.Invoke(new UpdateTextCallback(this.UpdateText), 
      new object[]{”Text generated on non-UI thread.”}); 
संबंधित मुद्दे

 संबंधित मुद्दे