2012-05-09 23 views
6

मैं multithreading और WPF के लिए नया हूँ।अवलोकन करने योग्य चयन वस्तुओं के लिए असीमित अद्यतन

मेरे पास ObservableCollection<RSSFeed> है, ऐप स्टार्टअप आइटम UI संग्रह से इस संग्रह में जोड़े गए हैं। आरएसएसएफआईडी की संपत्तियां डब्ल्यूपीएफ लिस्ट व्यू से जुड़ी हैं। बाद में, मैं प्रत्येक आरएसएसफ़ीड को असीमित रूप से अपडेट करना चाहता हूं। तो मैं RSSFeed.FetchAsync() जैसे कुछ को लागू करने और इसके अद्यतन गुणों पर PropertyChanged को बढ़ाने के बारे में सोच रहा हूं।

मुझे पता है कि ObservableCollection UI थ्रेड के अलावा थ्रेड से अपडेट का समर्थन नहीं करता है, यह NotSupportedException फेंकता है। लेकिन चूंकि मैं ऑब्जर्जेबल कोलेक्शन में खुद को जोड़ नहीं रहा हूं बल्कि इसकी वस्तुओं पर गुणों को अपडेट कर रहा हूं, क्या मैं इसे काम करने की उम्मीद कर सकता हूं और ListView आइटम अपडेट कर सकता हूं? या संपत्ति के कारण किसी भी तरह से अपवाद फेंक दिया जाएगा?

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

RSSFeed.cs

public class RSSFeed 
{ 
    public String Title { get; set; } 
    public String Summary { get; set; } 
    public String Uri { get; set; }   
    public String Encoding { get; set; } 
    public List<FeedItem> Posts { get; set; } 
    public bool FetchedSuccessfully { get; protected set; }   

    public RSSFeed() 
    { 
     Posts = new List<FeedItem>(); 
    } 

    public RSSFeed(String uri) 
    { 
     Posts = new List<FeedItem>(); 
     Uri = uri; 
     Fetch(); 
    } 

    public void FetchAsync() 
    { 
     // call Fetch asynchronously 
    } 

    public void Fetch() 
    { 
     if (Uri != "") 
     { 
      try 
      { 
       MyWebClient client = new MyWebClient(); 
       String str = client.DownloadString(Uri); 

       str = Regex.Replace(str, "<!--.*?-->", String.Empty, RegexOptions.Singleline); 
       FeedXmlReader reader = new FeedXmlReader(); 
       RSSFeed feed = reader.Load(str, new Uri(Uri)); 

       if (feed.Title != null) 
        Title = feed.Title; 
       if (feed.Encoding != null) 
        Encoding = feed.Encoding; 
       if (feed.Summary != null) 
        Summary = feed.Summary; 
       if (feed.Posts != null) 
        Posts = feed.Posts; 

       FetchedSuccessfully = true; 
      } 
      catch 
      { 
       FetchedSuccessfully = false; 
      } 

     } 
    } 

UserProfile.cs

public class UserProfile : INotifyPropertyChanged 
{ 
    public event PropertyChangedEventHandler PropertyChanged; 
    public event CollectionChangeEventHandler CollectionChanged; 

    private ObservableCollection<RSSFeed> feeds; 
    public ObservableCollection<RSSFeed> Feeds 
    { 
     get { return feeds; } 
     set { feeds = value; OnPropertyChanged("Feeds"); } 
    } 

    public UserProfile() 
    { 
     feeds = new ObservableCollection<RSSFeed>(); 
    } 

    protected void OnPropertyChanged(string name) 
    { 
     PropertyChangedEventHandler handler = PropertyChanged; 
     if (handler != null) 
     { 
      handler(this, new PropertyChangedEventArgs(name)); 
     } 
    } 

    protected void OnCollectionChanged(RSSFeed feed) 
    { 
     CollectionChangeEventHandler handler = CollectionChanged; 
     if (handler != null) 
     { 
      handler(this, new CollectionChangeEventArgs(CollectionChangeAction.Add, feed)); 
     } 
    } 
} 

MainWindow.xaml.cs

public partial class MainWindow : Window, INotifyPropertyChanged 
{ 
    // My ListView is bound to this 
    // ItemsSource="{Binding Posts} 
    public List<FeedItem> Posts 
    { 
     get 
     { 
      if (listBoxChannels.SelectedItem != null) 
       return ((RSSFeed)listBoxChannels.SelectedItem).Posts; 
      else 
       return null; 
     } 
    } 

    private void Window_Loaded(object sender, RoutedEventArgs e) 
    { 
     // here I load cached feeds 
     // called from UI thread 

     // now I want to update the feeds 
     // since network operations are involved, 
     // I need to do this asynchronously to prevent blocking the UI thread 
    } 

} 

धन्यवाद।

उत्तर

3

आवेदन के इस प्रकार के लिए, मैं आमतौर पर एक BackgroundWorker का उपयोग ReportsProgress सही पर सेट होने के साथ। फिर आप ReportProgress विधि में userState पैरामीटर के रूप में प्रत्येक कॉल के लिए एक ऑब्जेक्ट पास कर सकते हैं। प्रोग्रेस चेंजेड ईवेंट यूआई थ्रेड पर चलाएगा, ताकि आप ईवेंट हैंडलर में ऑब्जेर्जेबल कोलेक्शन में ऑब्जेक्ट जोड़ सकें।

अन्यथा, पृष्ठभूमि थ्रेड से गुणों को अपडेट करना काम करेगा, लेकिन यदि आप ऑब्जर्जेबल कोलेक्शन को फ़िल्टर या सॉर्ट कर रहे हैं, तो फ़िल्टर को तब तक लागू नहीं किया जाएगा जब तक कुछ संग्रह परिवर्तन अधिसूचना ईवेंट नहीं उठाया जाता है।

आप संग्रह में आइटम की अनुक्रमणिका (उदाहरण के लिए इसे प्रगतिशीलता के रूप में रिपोर्ट करके) और सूची.इटेम (i) = e.userstate को सेट करके फ़िल्टर और प्रकार का पुन: उपयोग कर सकते हैं, यानी आइटम को प्रतिस्थापित करना प्रोग्रेस चेंजेड इवेंट में स्वयं की सूची।इस तरह, संग्रह से जुड़े किसी भी नियंत्रण के चयनित इटिम को संरक्षित किया जाएगा, जबकि फ़िल्टर और सॉर्टिंग आइटम में किसी भी बदले गए मानों का सम्मान करेगी।

3

यदि आप WPF का उपयोग कर रहे हैं तो आपको अलग-अलग बाध्य वस्तुओं पर गुण अपडेट करने और पृष्ठभूमि थ्रेड से PropertyChanged बढ़ाने की अनुमति है। डब्ल्यूपीएफ डेटा बाध्यकारी तंत्र (WinForms समकक्ष के विपरीत) यह पता लगाने के लिए और यूआई धागा के लिए मार्शल का पता लगाएं। इस कोर्स के लिए एक लागत है- स्वचालित तंत्र का उपयोग करके, प्रत्येक व्यक्तिगत संपत्ति अपडेट एक मार्शलिंग घटना का कारण बनता है, इसलिए यदि आप बहुत सारे गुणों को बदल रहे हैं तो प्रदर्शन का सामना करना पड़ सकता है, और आपको यूआई को एक बैच ऑपरेशन के रूप में खुद को मारने पर विचार करना चाहिए ।

आपको संग्रहों में हेरफेर करने की अनुमति नहीं है हालांकि (आइटम जोड़ें/हटाएं), इसलिए यदि आपके आरएसएस फ़ीड में नेस्टेड संग्रह शामिल हैं जिन्हें आप बाध्य करना चाहते हैं तो पूरे अपडेट को यूआई थ्रेड में समय से पहले उठाना होगा।

+0

धन्यवाद का उल्लेख कर सकते हैं। मेरे आरएसएसफ़ीड कक्षा में मेरा घोंसला संग्रह है। अगर यह आरएसएसएफआईडी.फेटाएसिंक() ने अपना पूरा होने पर एक कार्यक्रम उठाया और इवेंटअर्ज़ के माध्यम से नया (अपडेटेड) आरएसएसफाइड उदाहरण वापस कर दिया तो क्या यह एक अच्छा आत्मविश्वास होगा? बाद में मैं UI थ्रेड से संग्रह में संबंधित आइटम अपडेट कर दूंगा। – Martin

+0

यह एक संभावित समाधान है। अगर हम कुछ कोड देख सकते हैं तो मैं आपको एक और ठोस जवाब दे सकता हूं। –

+0

@malymato आमतौर पर Async विधियां पूर्ण होने पर कॉलबैक प्रदान करती हैं। आप किस प्रकार के कार्यान्वयन का उपयोग कर रहे हैं? –

5

.NET 4.5 के साथ, आप बैंडिंगऑपरेशंस का उपयोग करके एक ऑब्जर्जेबल कोलेक्शन में पृष्ठभूमि थ्रेड अपडेट के लिए समर्थन जोड़ सकते हैं। सक्षम कोलेक्शन सिंक्रनाइज़ेशन। यह एमवीवीएम के साथ बढ़िया काम करता है।

देखें: BindingOperations.EnableCollectionSynchronization() equivalent for .net 4.0

0

मैं एक ऐसी ही परिदृश्य था और इस "ObservableCollection यूआई धागा अलावा अन्य धागे से अद्यतन का समर्थन नहीं करता", अंत में यह थॉमस लेवेस्क के ब्लॉग में इस AsyncObservableCollection implement चर्चा करते हुए द्वारा हल किया गया मुलाकात की , मुझे लगता है कि यह आपके लिए सहायक हो सकता है।

अपने अद्यतन संस्करण में, इस समस्या को हल करने के लिए सिंक्रनाइज़ेशन कॉन्टेक्स्ट का उपयोग किया जाता है। आप MSDN page of SynchronizationContext

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