2012-11-29 19 views
6

हेई,डब्ल्यूपीएफ डाटाग्रिड अतिरिक्त "भूत" पंक्ति जोड़ रहा है

मेरे आवेदन में मैं कुछ डेटा दिखाने के लिए डेटाग्रिड का उपयोग कर रहा हूं। थ्रेडिंग के साथ काम करने के लिए सब कुछ पाने के लिए मैं AsyncObservableCollection डेटाग्रिड के डेटाकॉन्टेक्स्ट के रूप में उपयोग कर रहा हूं। जब मेरा एप्लिकेशन शुरू होता है तो यह कुछ फ़ोल्डर्स में फ़ाइलों की तलाश करता है और AsyncObservableCollection अपडेट करता है। फ़ाइलें ढूँढना एक अलग थ्रेड पर किया जाता है:

Task.Factory.StartNew(() => _cardType.InitAllOrdersCollection()) 
    .ContinueWith((t) => ThrowEvent(), TaskContinuationOptions.None); 

कहाँ सभी लदान तर्क InitAllOrdersCollection() विधि में है।

अब यहां जहां चीजें खराब होती हैं, जब मैं किसी कारण से एप्लिकेशन शुरू करता हूं तो मुझे डेटाग्रिड में एक ही डेटा के साथ 2 पंक्तियां मिलती हैं, भले ही संग्रह में एक आइटम और फ़ोल्डर में केवल एक फ़ाइल हो। यदि मैं फ़ाइलों को लोड करने से पहले देरी (Thread.Sleep() 50ms न्यूनतम) जोड़ता हूं तो डेटाग्रिड सबकुछ सही ढंग से दिखाता है (कोई अतिरिक्त पंक्ति नहीं)। फ़ाइलों को लोड करने वाले थ्रेड में देरी को जोड़ा जाना चाहिए (जिसे Task.Factory.StartNew() के साथ बनाया गया है)।

क्या किसी ने कुछ ऐसा ही सामना किया है या क्या मुझे कुछ और कोशिश करनी चाहिए? अग्रिम धन्यवाद!

संपादित करें: अनुरोध के रूप में कुछ कोड जोड़ना:

public AsyncObservableCollection<IGridItem> OrdersCollection = new AsyncObservableCollection<IGridItem>(); 

public void InitAllOrdersCollection() 
{ 
    // Thread.Sleep(50); <-- this sleep here fixes the problem! 
    foreach (var convention in FileNameConventions) 
    { 
     var namePatterns = convention.NameConvention.Split(','); 
     foreach (var pattern in namePatterns) 
     { 
      var validFiles = CardTypeExtensions.GetFiles(this.InputFolder, pattern, convention); 
      if (validFiles.Any()) 
      { 
       this.FilesToOrders(validFiles, convention); 
      } 
     } 
    } 
} 

public static List<string> GetFiles(string inputFolder, string pattern, FileNameConvention convention) 
{ 
    var files = Directory.GetFiles(inputFolder, pattern); 
    return files.Where(file => IsCorrect(file, convention)).AsParallel().ToList(); 
} 

// Adds new order to OrdersCollection if its not there already! 
private void FilesToOrders(List<string> dirFiles, FileNameConvention convention) 
{ 
    foreach (var dirFile in dirFiles.AsParallel()) 
    { 
     var order = new Order(dirFile, this, convention); 

     if (!this.OrdersCollection.ContainsOrder(order)) 
     { 
       this.OrdersCollection.Add(order); 
     } 
    } 
} 

public static bool ContainsOrder(this ObservableCollection<IGridItem> collection, Order order) 
{ 
    return collection.Cast<Order>().Any(c=>c.Filepath == order.Filepath); 
} 

FilesToOrders() विधि एक क्या AsyncObservableCollection को नए आदेश जोड़ता है। उम्मीद है कि यह मदद करता है।

+0

करने के लिए CanUserAddRows="False" जोड़ें आप कृपया InitAllOrdersCollection पद्धति पर कुछ विस्तार से जोड़ने सकते हैं? मैंने एक साधारण परीक्षण कार्यक्रम बनाया है और मुझे कोई डुप्लिकेट नहीं मिल रहा है। शायद आपके पास कोड में कुछ ऐसा है जो मैं इस तरह के व्यवहार को दोहराने के लिए नहीं कर रहा हूं। –

+0

मुझे संदेह है कि डेटा ग्रिड नियंत्रण के साथ समस्या को करना है। जांच करें कि 'ऑर्डर्स कोलेक्शन' में क्या है - आपका तर्क संग्रह में कुछ "रिक्त मॉडल" डाल सकता है। इसके अलावा, आप 'dirFiles 'के बजाय' dirFiles.AsParallel() 'के माध्यम से क्यों पुन: प्रयास करते हैं? क्या उस लूप में कोई समय लेने वाला ऑपरेशन है? –

+0

ऑर्डरकोलेक्शन में केवल सही मात्रा में आइटम हैं, मैंने कई बार जांच की है, लेकिन फिर भी उन्हें डेटाग्रिड में डबल दिखाया गया है। [AsParallel()] (http://www.albahari.com/threading/part5.aspx#_PLINQ) के बारे में कुछ और जानकारी यहां दी गई है। ठीक है, हो सकता है कि उन स्थानों में AsParallel() को कॉल करना कुछ भी नहीं कर रहा है, लेकिन यह समस्या नहीं है .. – hs2d

उत्तर

2

शायद मुझे कुछ स्पष्ट याद आ रहा है, लेकिन आपके द्वारा पोस्ट किए गए लिंक में AsyncObservableCollection कार्यान्वयन मेरे लिए थ्रेड-सुरक्षित नहीं दिखता है।

मैं देख सकता हूं कि इसमें संग्रहकर्ता (उपभोक्ता) थ्रेड पर संग्रहChanged/PropertyChanged ईवेंट को आग लगाने के लिए कोड शामिल है, लेकिन मुझे संग्रह थ्रेड-सुरक्षित में आइटम तक पहुंच बनाने के लिए कोई सिंक्रनाइज़ेशन नहीं दिख रहा है।

अद्यतन

जहां तक ​​मेरा, देख सकते हैं किसी भी तुल्यकालन के बिना आप निम्नलिखित समवर्ती हो रहा हो सकता है:

  • कार्यकर्ता (निर्माता) धागा डालने है मद (ओं)

  • यूआई (उपभोक्ता) धागा आइटम

उपभोक्ता धागे पर आइटम डालने के लिए SynchronizationContext.Send पर कॉल करने के लिए AsyncObservableCollection.InsertItem को संशोधित करने की संभावना हो सकती है, हालांकि यह निश्चित रूप से प्रदर्शन पर प्रभाव डालता है (निर्माता जारी रखने से पहले सम्मिलन पूर्ण करने के लिए उपभोक्ता थ्रेड के लिए प्रतीक्षा करता है)।

एक वैकल्पिक दृष्टिकोण मानक ObservableCollection का उपयोग करना होगा जो कि उपभोक्ता थ्रेड पर कभी भी पहुंचा जा सकता है, और निर्माता धागे से सम्मिलित करने के लिए आइटम पोस्ट करने के लिए SynchronizationContext.Post का उपयोग करें। कुछ ऐसा:

foreach (var dirFile in dirFiles.AsParallel()) 
{ 
    var order = new Order(dirFile, this, convention); 

    _synchronizationContext.Post(AddItem, order); 

} 

...

void AddItem(object item) 
{ 
    // this is executed on the consumer thread 
    // All access to OrderCollection on this thread so no need for synchnonization 
    Order order = (Order) item; 
    if (!OrdersCollection.ContainsOrder(order)) 
    { 
     OrdersCollection.Add(order); 
    } 
} 
+0

उस ब्लॉग पोस्ट के नीचे अद्यतन समाधान देखें। प्रॉपर्टी चेंजेड ईवेंट को संग्रह थ्रेड में पोस्ट करने के लिए इसका उपयोग 'सिंक्रनाइज़ेशन कॉन्टेक्स्ट' का उपयोग करना है। – hs2d

+0

@ hs2d - हाँ मैंने इसे देखा। मुझे घटना फायरिंग में कोई समस्या नहीं दिख रही है, लेकिन मुझे संग्रह में वस्तुओं तक पहुंचने में संभावित समस्या दिखाई देती है। – Joe

+0

हम्म, यह दिलचस्प लग रहा है और जब मैंने कोशिश की तो यह वास्तव में काम किया। कुछ और परीक्षण करने की आवश्यकता है, लेकिन मुझे लगता है कि हमारे पास समाधान है। – hs2d

4

अपने XAML फाइल

<DataGrid CanUserAddRows="False"../> 
+1

इस तरह की Lana

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