2010-04-02 7 views
14

मुझे एक स्थिति आई थी जिसके कारण देरी के बाद यूआई थ्रेड पर लैम्ब्डा अभिव्यक्ति चलाना आवश्यक था। मैं यह करने के लिए कई तरीके के बारे में सोचा और अंत में इस दृष्टिकोण.NET: देरी के बाद यूआई थ्रेड पर लैम्ब्डा निष्पादित करने का सबसे अच्छा तरीका?

Task.Factory.StartNew(() => Thread.Sleep(1000)) 
    .ContinueWith((t) => textBlock.Text="Done",TaskScheduler.FromCurrentSynchronizationContext()); 

पर बसे लेकिन वहाँ एक आसान तरीका है कि मैं याद किया है कि अगर मैं सोच रहा हूँ। एक छोटी, सरल या आसान तकनीक के लिए कोई सुझाव? मान लें कि .NET 4 उपलब्ध है।

+1

आप WPF [DispatcherTimer] का उपयोग उपयोग कर रहे हैं (http: // MSDN .microsoft.com/en-us/library/system.windows.threading.dispatchertimer.aspx) –

उत्तर

22

मुझे लगता है कि आपको जो मिला है वह बहुत अच्छा स्कॉट है।

एकमात्र मामूली समस्या जो मुझे लगता है कि कुछ इसके साथ हो सकता है, यह है कि आप अपनी देरी को निष्पादित करने के लिए थ्रेड को अवरुद्ध कर रहे हैं। बेशक यह एक पृष्ठभूमि धागा है, और समस्याओं का कारण होने की संभावना नहीं है जब तक कि आप इन कॉलों में से कई को एक साथ निष्पादित नहीं करते (प्रत्येक धागे को बांधते हैं), लेकिन यह अभी भी उप-शीर्ष है।

मैं इसके बजाय सुझाव दूंगा कि आप एल्गोरिदम को उपयोगिता विधि में कारक करते हैं, और थ्रेड का उपयोग करने से बचें। सो जाओ।

वहाँ स्पष्ट रूप से ऐसा करने का शायद असंख्य तरीके है, लेकिन यहां से एक है:

public static class UICallbackTimer 
{ 
    public static void DelayExecution(TimeSpan delay, Action action) 
    { 
     System.Threading.Timer timer = null; 
     SynchronizationContext context = SynchronizationContext.Current; 

     timer = new System.Threading.Timer(
      (ignore) => 
      { 
       timer.Dispose(); 

       context.Post(ignore2 => action(), null); 
      }, null, delay, TimeSpan.FromMilliseconds(-1)); 
    } 
} 

का उपयोग करें:

UICallbackTimer.DelayExecution(TimeSpan.FromSeconds(1), 
     () => textBlock.Text="Done"); 
बेशक

आप भी इस DelayExecution विधि है जो अन्य प्रकार का उपयोग करता है के एक कार्यान्वयन लिख सकता है टाइमर जैसे डब्ल्यूपीएफ डिस्पैचर टाइमर या विनफॉर्म टाइमर क्लास। मुझे यकीन नहीं है कि इन विभिन्न टाइमर का व्यापार क्या होगा। मेरा अनुमान डिस्पैचर टिमर होगा और WinForm के टाइमर वास्तव में विपरीत प्रकार के अनुप्रयोगों पर भी काम करेंगे।

संपादित करें:

फिर से पढ़ने मेरा उत्तर, मैं वास्तव में मैं एक विस्तार पद्धति है जिसके तुल्यकालन संदर्भों पर काम करता है में इस कारक के लिए परीक्षा की जाएगी लगता है - अगर आप इसके बारे में सोचते हैं, एक अधिक सामान्य बयान होगा कि आपको एक निश्चित देरी के बाद एक सिंक्रनाइज़ेशन संदर्भ में वापस पोस्ट करने में सक्षम होना चाहिए।

सिंक्रनाइज़ेशन कॉन्टेक्स्ट में पहले से ही क्यूइंग कार्य के लिए एक पोस्ट विधि है, जो मूल कॉलर पूरा होने पर अवरुद्ध नहीं करना चाहता है।क्या हम की जरूरत विलंब के बाद काम पोस्ट इस बात का एक संस्करण है, इसलिए बजाय:

public static class SyncContextExtensions 
{ 
    public static void Post(this SynchronizationContext context, TimeSpan delay, Action action) 
    { 
     System.Threading.Timer timer = null; 

     timer = new System.Threading.Timer(
      (ignore) => 
      { 
       timer.Dispose(); 

       context.Post(ignore2 => action(), null); 
      }, null, delay, TimeSpan.FromMilliseconds(-1)); 
    } 
} 

और उपयोग:

 SynchronizationContext.Current.Post(TimeSpan.FromSeconds(1), 
      () => textBlock.Text="Done"); 
+0

मुझे आपकी विस्तार विधि दृष्टिकोण पसंद है! यह एक साफ वाक्यविन्यास है और नींद() कॉल से बचाता है। परियोजना में एक स्थिर विस्तार वर्ग जोड़ने की आवश्यकता है, लेकिन यह एक बड़ा सौदा नहीं है। धन्यवाद! –

+0

बेकार काम करता है! – AVEbrahimi

+0

क्या देरी की कार्रवाई निष्पादित करने से पहले यह संभव है कार्रवाई रद्द करें? – Kiquenet

2

मुझे लगता है कि सबसे सरल तरीका System.Windows.Forms.Timer का उपयोग कर रहा है, अगर लैम्ब्डा कुछ यादृच्छिक कार्य नहीं है।

this._timer.Interval = 1000; 
this._timer.Tick += (s, e) => this.textBlock.Text = "Done"; 

यदि लैबडा में लूप में निष्पादित करने की आवश्यकता नहीं है, तो इसे जोड़ें;

this.timer1.Tick += (s, e) => this.timer1.Stop(); 

और फोन

this.timer1.Start(); 

जहां यह की जरूरत है।

एक और तरीका Invoke मेथोड का उपयोग कर रहा है।

delegate void FooHandler(); 

private void button1_Click(object sender, EventArgs e) 
     { 

      FooHandler handle =() => Thread.Sleep(1000); 
      handle.BeginInvoke(result => { ((FooHandler)((AsyncResult)result).AsyncDelegate).EndInvoke(result); this.textBox1.Invoke((FooHandler)(() => this.textBox1.Text = "Done")); }, null); 
     } 

Control.Invoke गारंटी देता है कि प्रतिनिधि यूआई धागा (जहां माता-पिता खिड़की मुख्य वर्णनकर्ता मौजूद है)

शायद बेहतर संस्करण मौजूद है निष्पादित किया जाएगा।

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