2010-03-24 15 views
15

में बाध्यकारी मैं एक नियंत्रण अपने डेटा एक मानक ObservableCollection करने के लिए बाध्य है, और मुझे लगता है कि और अधिक डेटा प्राप्त करने के लिए एक सेवा कॉल एक पृष्ठभूमि कार्य किया है।WPF अद्यतन एक पृष्ठभूमि धागा

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

मैं इस के आसपास मिल सकता है इतना है कि मेरी एनिमेशन और सामान मेरे पर चालू रखने के "कृपया प्रतीक्षा करें" संवाद?

या कम से कम उपयोगकर्ता को "उपस्थिति" दें जो इसे लॉक नहीं किया गया है?

उत्तर

17

अगर मैं सही ढंग से समझ, आप पहले से ही डेटा पुनः प्राप्त करने एक BackgroundWorker का उपयोग, और कहा कि बस बताए ObservableCollection के लिए इस डेटा यूआई अप ताला लगा है ।

एक तरह से यूआई अप ताला से बचने के लिए कई डिस्पैचर तरीकों कतार से छोटे मात्रा में ObservableCollection करने के लिए डेटा आवंटित करने के लिए है। प्रत्येक विधि कॉल के बीच, यूआई घटनाओं को संभाला जा सकता है।

निम्नलिखित एक समय में पर एक आइटम जोड़ना होगा, कि थोड़ा चरम है, लेकिन यह अवधारणा को दिखाता है।

void UpdateItems() 
{ 
    //retrievedItems is the data you received from the service 
    foreach(object item in retrievedItems) 
     Dispatcher.BeginInvoke(DispatcherPriority.Background, new ParameterizedThreadStart(AddItem), item);  
} 

void AddItem(object item) 
{ 
    observableCollection.Add(item); 
} 
+0

के रूप में सेट करें ताकि पृष्ठभूमि थ्रेड में आइटम संग्रह में उन्हें जोड़कर UI थ्रेड पर नियंत्रण अपडेट हो जाए? वह कैसे काम करता है? – Mark

+3

नहीं, आप उन्हें डिस्पैचर सूत्र में, लेकिन एक कम प्राथमिकता के साथ और छोटे chucnks में, एक बहुत मदद के लिए जोड़ने के लिए, तो यूआई उत्तरदायी रहता – Bubblewrap

+0

मैं देख रहा हूँ धन्यवाद मुझे लगता है कि एक कोशिश – Mark

0

इस कार्य को पूरा करने के लिए पृष्ठभूमिवर्कर का उपयोग करें।

+0

कैसे है कि अद्यतन यूआई धागा करता है? हो सकता है कि मैं इसे समझ नहीं पा रहा हूं, लेकिन मेरे सभी नियंत्रण और यूआई थ्रेड के अंदर उनके पीछे प्रतिपादन नहीं है, इसलिए पृष्ठभूमि थ्रेड में संग्रह को अद्यतन करने से यूआई थ्रेड सामान्य अपडेट कर सकता है? – Mark

-1

उपयोग DoWork विधि में obsrvablecollection अद्यतन इस:

 

Dispatcher.CurrentDispatcher.Invoke(DispatcherPriority.Render, new Action(UpdateData), value); 

private void UpdateData(int value) 
{ 
    BindingSourceProperty = value; 
} 

 
+1

यह क्या करता है? यह अच्छा क्यों है? यह मेरी मदद कैसे करेगा? – Mark

+0

कहते हैं कि तुम एक WPF यूआई के रूप में ProgressBar नियंत्रण रखने प्रपत्र प्राप्त हो जाता है जहां PercentValue अपने DataContext फार्म के साथ संलग्न में परिभाषित संपत्ति है। ऐसे परिदृश्य को मानते हुए जहां आप किसी अन्य थ्रेड पर कॉलबैक डेटा प्राप्त कर रहे हैं, ऑपरेशन की प्रगति का संकेत देते हैं और आप इसे यूआई पर प्रदर्शित करना चाहते हैं। यदि आप उस मान को सीधे अपनी निर्भरता स्रोत प्रॉपर्टी 'पर्सेंटवेल्यू' पर सेट करते हैं, तो आपको पृष्ठभूमि थ्रेड ऑपरेशन समाप्त होने पर केवल ui अपडेट किया जाएगा। तो प्रतिशत मूल्य की वास्तविक समय प्रगति प्राप्त करने के लिए, इस मान को – RockWorld

10

ObservableCollection CollectionChanged घटनाओं यूआई, डेटा, उपाय rebind व्यवस्था और पुनः बनाने के लिए विवश करेगा बढ़ा देंगे। यदि आपके पास कई अपडेट आ रहे हैं तो इसमें बहुत समय लग सकता है।

उपयोगकर्ता को यह सोचना संभव है कि छोटे पैकेज में नौकरी को विभाजित करके यूआई जीवित है। 10-100 आइटमों के साथ संग्रह अद्यतन क्रियाओं को निर्धारित करने के लिए यूआई थ्रेड (किसी भी नियंत्रण का संदर्भ है) से डिस्पैचर का उपयोग करें (प्रयोग द्वारा संख्या निर्धारित करें, ये केवल विचार का समर्थन करने के लिए)।

आपकी पृष्ठभूमि कोड हो सकता है इस तरह दिखता है:

void WorkInBackground() 
{ 
    var results = new List<object>(); 

    //get results... 

    // feed UI in packages no more than 100 items 
    while (results.Count > 0) 
    { 
     Application.Current.MainWindow.Dispatcher.BeginInvoke(
      new Action<List<object>>(FeedUI), 
      DispatcherPriority.Background, 
      results.GetRange(0, Math.Min(results.Count, 100))); 
     results.RemoveRange(0, Math.Min(results.Count, 100)); 
    } 
} 
void FeedUI(List<object> items) 
{ 
    // items.Count must be small enough to keep UI looks alive 
    foreach (var item in items) 
    { 
     MyCollection.Add(item); 
    } 
} 
0

मैं जो एक कार्यकर्ता धागा चलाता है और घटनाओं आवेदन करने के लिए वापस भेजता है एक DLL - पूरी तरह से खिड़कियों रूपों पर काम किया, WPF में स्विच करने और सब कुछ काम करना बंद कर। मैं काम करने के लिए 4 घंटों तक एक ईंट की दीवार के खिलाफ अपने सिर को तोड़ रहा हूं। लेकिन जिस समाधान के साथ मैं समाप्त हुआ, माइक्रोसॉफ्ट के यूआई थ्रेड सेफ मार्शलिंग को सक्षम करने के लिए धन्यवादकोलेक्शन सिंक्रनाइज़ेशन, इसे हल करने के लिए वास्तव में एक साफ कार्यान्वयन देता है।

यह संग्रह पर्यवेक्षण चयन को बढ़ाता है और सक्षम करता है EnableCollectionSynchronization इन ऑब्जेक्ट्स को WPF और पृष्ठभूमि कार्यकर्ताओं के बीच उपयोग करने योग्य बनाता है।

संपादित: Microsoft's docs निम्नलिखित कहते हैं, तो मैं ग्रहण करने के लिए उस वस्तु संदर्भ बंटवारे कोई फर्क नहीं पड़ता जा रहा हूँ।

संदर्भ पैरामीटर एक मनमानी वस्तु है जिसे आप संग्रह सिंक्रनाइज़ेशन सक्षम करते समय ज्ञात जानकारी के लिए उपयोग कर सकते हैं। संदर्भ शून्य हो सकता है।

ThreadSafeCollection.cs

using System.Collections.ObjectModel; 
using System.Windows.Data; 

namespace NSYourApplication 
{ 
    /// <summary> 
    /// This ObservableCollection is thread safe 
    /// You can update it from any thread and the changes will be safely 
    /// marshalled to the UI Thread WPF bindings 
    /// Thanks Microsoft! 
    /// </summary> 
    /// <typeparam name="T">Whatever type of collection you want!</typeparam> 
    public class ThreadSafeCollection<T> : ObservableCollection<T> 
    { 
     private static object __threadsafelock = new object(); 

     public ThreadSafeCollection() 
     { 
      BindingOperations.EnableCollectionSynchronization(this, __threadsafelock); 
     } 
    } 
} 

उदाहरण WindowViewModel WindowViewModel.cs

namespace NSYourApplication 
{ 
    /// <summary> 
    /// Example View 
    /// BaseModelView implements "PropertyChanged" to update WPF automagically 
    /// </summary> 
    class TestViewModel : BaseModelView 
    { 
     public ThreadSafeCollection<string> StringCollection { get; set; } 

     /// <summary> 
     /// background thread implemented elsewhere... 
     /// but it calls this method eventually ;) 
     /// Depending on the complexity you might want to implement 
     /// [MethodImpl(MethodImplOptions.Synchronized)] 
     /// to Synchronize multiple threads to prevent chase-conditions,deadlocks etc 
     /// </summary> 
     public void NonUIThreadMethod() 
     { 
      // No dispatchers or invokes required here! 
      StringCollection.Add("Some Text from a background worker"); 
     } 

     /// <summary> 
     /// Somewhere in the UIThread code it'll call this method 
     /// </summary> 
     public void UIThreadMethod() 
     { 
      StringCollection.Add("This text come from UI Thread"); 
     } 

     /// <summary> 
     /// Constructor, creates a thread-safe collection 
     /// </summary> 
     public TestViewModel() 
     { 
      StringCollection = new ThreadSafeCollection<string>(); 
     } 
    } 
} 

एक XAML खिड़की/नियंत्रण में एक लिस्टबॉक्स में प्रयोग MainWindow.xaml

<ListBox x:Name="wpfStringCollection" ItemsSource="{Binding StringCollection,Mode=OneWay}"> 

    </ListBox> 
+0

हम्म इसके बारे में सोच रहा है; यह एकल स्थैतिक __threadsafelock सभी संग्रहों द्वारा साझा किया जा रहा है; इससे समस्याएं हो सकती हैं;) मुझे इसे वापस आना होगा ... =] –

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