2012-12-20 9 views
5

मैं समझने की कोशिश कर रहा हूं कि डेटा के एक सेट को असीमित रूप से डेटा के सेट को पकड़ने के लिए सही कोड क्या है जब मुझे क्लाइंट lib की पहुंच नहीं है, तो मैं पुनर्प्राप्त करने के लिए उपयोग कर रहा हूं डेटा। मैं एक एंडपॉइंट और डेट रेंज निर्दिष्ट करता हूं और मुझे प्लेलिस्ट की एक सूची पुनर्प्राप्त करना है। मेरे पास अब स्टार्ट() कॉल के बाद कभी वापस नहीं आता है। नोट: यह WinForm में चल रहा है। मैं कार्य को बेहतर ढंग से समझने की कोशिश कर रहा हूं और सिर्फ प्रतीक्षा या पृष्ठभूमिवर्कर पर कूदना नहीं चाहता हूं। मुझे पता है कि मैं कहीं खो गया हूँ।सी # और कार्य - यूआई थ्रेड हैंग - प्री-असिंक/कीवर्ड का इंतजार

private void GoButtonClick(object sender, EventArgs e) 
    { 
     string baseUrl = "http://someserver/api"; 
     var startDateTime = this._startDateTimePicker.Value; 
     var endDateTime = this._endDateTimePicker.Value; 
     _getPlaylistsFunc = delegate() 
      { 
       var client = new PlaylistExportClient(baseUrl); 
       return client.GetPlaylistsByDateRange(startDateTime, endDateTime).ToList(); 
      }; 
     var task = new Task<List<Playlist>>(_getPlaylistsFunc); 
     task.ContinueWith((t) => DisplayPlaylists(t.Result)); 
     task.Start(); 
    } 

    private void DisplayPlaylists(List<Playlist> playlists) 
    { 
     _queueDataGridView.DataSource = playlists; 
    } 

अद्यतन मैं ये परिवर्तन किए, लेकिन अब आवेदन यूआई धागा लटका रहा है।

private void GoButtonClick(object sender, EventArgs e) 
    { 
     string baseUrl = "http://someserver/api"; 
     var startDateTime = this._startDateTimePicker.Value; 
     var endDateTime = this._endDateTimePicker.Value; 
     var token = Task.Factory.CancellationToken; 

     var context = TaskScheduler.FromCurrentSynchronizationContext(); 
     Task.Factory.StartNew(() => 
      { 
       var client = new PlaylistExportClient(baseUrl); 
       _queueDataGridView.DataSource = client.GetPlaylistsByDateRange(startDateTime, endDateTime).ToList(); 

      },token,TaskCreationOptions.None,context); 

    } 
+0

यदि आप 'GetPlaylistsByDateRange' में ब्रेकपॉइंट डालते हैं तो क्या आप देखते हैं कि इसे वास्तव में बुलाया जाता है? – user7116

+2

आपको निरंतरता के लिए एक सिंक संदर्भ पारित करने की आवश्यकता होगी ताकि यह किसी अन्य थ्रेड पूल थ्रेड के बजाय UI थ्रेड में चल सके। इसके अलावा, मुझे यहां कोई वास्तविक त्रुटियां नहीं दिखाई देती हैं। – Servy

+2

आपका अपडेट यूआई थ्रेड पर * सभी * कार्यों को चलाता है। केवल दूसरा भागना चाहिए। –

उत्तर

2

ऐसा लगता है कि आप पृष्ठभूमि थ्रेड में यूआई नियंत्रण की संपत्ति को असाइन कर रहे हैं। यह आमतौर पर बुरी खबर है। WPF आमतौर पर अपवाद फेंकता है जब आप ऐसा करते हैं, WinForms के बारे में निश्चित नहीं है।

पृष्ठभूमि थ्रेड में डेटा कैप्चर करें, लेकिन इसे UI UI नियंत्रण में निर्दिष्ट करने से पहले मुख्य UI थ्रेड पर वापस स्विच करें।

var uiSync = SynchronizationContext.Current; 
    Task.Factory.StartNew(() => 
     { 
      var client = new PlaylistExportClient(baseUrl); 
      var list = client.GetPlaylistsByDateRange(...).ToList(); 
      uiSync.Post(() => _queueDataGridView.DataSource = list, null); 
     },token,TaskCreationOptions.None,context); 
+0

हम्म। मैं समझता हूं - मुझे लगता है। .Post() हालांकि मेरे संदर्भ पर एक विधि नहीं है। – BuddyJoe

+0

वूप्स। ठीक है, आप एक संदर्भ चर बुला रहे हैं वास्तव में एक शेड्यूलर है। मैं सिंक्रनाइज़ेशन संदर्भ को पकड़ने के लिए कोड के साथ अपना उत्तर अपडेट करूंगा। – dthorpe

+0

ऐसा लगता है कि यह वास्तव में करीब है। धन्यवाद। मैं सिर्फ पोस्ट() लैम्बडा तर्क का काम कर रहा हूं। अभी आईडीई अज्ञात फ़ंक्शन पर अनुचित हस्ताक्षर की रिपोर्ट कर रहा है – BuddyJoe

3

की तरह कुछ का उपयोग कर यूआई धागा करने के लिए डेटा पोस्टिंग मैं तुम्हें टास्क आधारित अतुल्यकालिक पैटर्न का उपयोग करें की कोशिश करो। यह काफी सरल है:

private async void GoButtonClick(object sender, EventArgs e) 
{ 
    string baseUrl = "http://someserver/api"; 
    var startDateTime = this._startDateTimePicker.Value; 
    var endDateTime = this._endDateTimePicker.Value; 
    var playlists = await Task.Run(() => 
    { 
     var client = new PlaylistExportClient(baseUrl); 
     return client.GetPlaylistsByDateRange(startDateTime, endDateTime).ToList(); 
    }); 
    _queueDataGridView.DataSource = playlists; 
} 

ध्यान दें कि यह थ्रेडपूल थ्रेड को अवरुद्ध करेगा; यदि आप GetPlaylistsByDateRangeAsync विधि रखने के लिए लाइब्रेरी को संशोधित कर सकते हैं, तो आप इसे और अधिक कुशल बना सकते हैं।

संपादित करें: आप .NET 4.0 पर अटक कर रहे हैं, तो आप Microsoft.Bcl.Async स्थापित कर सकते हैं पूर्ण async/await क्षमताओं पाने के लिए। है - कुछ अकथनीय कारण के लिए - आप अभी भीasync/await उपयोग नहीं कर सकते, तो आप इसे इस तरह कर सकते हैं:

private void GoButtonClick(object sender, EventArgs e) 
{ 
    string baseUrl = "http://someserver/api"; 
    var startDateTime = this._startDateTimePicker.Value; 
    var endDateTime = this._endDateTimePicker.Value; 
    var context = TaskScheduler.FromCurrentSynchronizationContext(); 
    Task.Run(() => 
    { 
     var client = new PlaylistExportClient(baseUrl); 
     return client.GetPlaylistsByDateRange(startDateTime, endDateTime).ToList(); 
    }).ContinueWith(t => 
    { 
     _queueDataGridView.DataSource = t.Result; 
    }, context); 
} 

हालांकि, ध्यान दें कि आपके त्रुटि हैंडलिंग इस दृष्टिकोण के साथ और अधिक जटिल है।

+0

मैं निश्चित रूप से यह जानने की कोशिश कर रहा था कि यह प्री-एसिंक/इंतजार कैसे किया जाता है। लेकिन अच्छी जानकारी भी है। – BuddyJoe

+0

मैंने इस उत्तर को प्रश्न पर निर्दिष्ट 'async-await' टैग' के आधार पर दिया है। यदि आप प्री-थैसिंक 'उत्तर चाहते हैं, तो' टास्क। कंटिन्यू विथ '('टास्कशेड्यूलर.फॉमक्रोरेंट सिंक्रनाइज़ेशन कॉन्टेक्स्ट' के साथ) या' BackgroundWorker' पर्याप्त है। 'async' कोड उन विकल्पों में से किसी एक से अधिक क्लीनर है। –

+0

' जारी रखें 'दृष्टिकोण का उपयोग करके कोड के लिए अद्यतन उत्तर देखें। –

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