2010-09-02 20 views
9

में पृष्ठभूमि कार्यकर्ता के साथ एक पर्यवेक्षण चयन अद्यतन करें ठीक है, मैंने हाल ही में डेटा की बचत और लोड करने के लिए पृष्ठभूमि कार्यकर्ता को लागू किया है।एमवीवीएम

हालांकि, इसे सहेजने के आदेश पर काम करने के लिए यह मुश्किल साबित हुआ है।

मूल रूप से, मेरे आदेश को बचाने कि एक आइटम जोड़ दिया गया है एक घटना है कि एक संग्रह को देखने के मॉडल को सूचित करता है उत्पन्न करता है, और आइटम अपनी ही ObservableCollection में जोड़ा जाना चाहिए कि।

इस बिंदु पर, मैं कह रहा मैं एक अलग धागे पर एक ICollection अद्यतन नहीं कर सकते हमेशा की तरह अपवाद मिलता है। मैंने एक नया सूची प्रकार बनाने का प्रयास किया है जो Dispatcher.Invoke पर कॉल करता है, हालांकि यह अभी भी एक ही अपवाद उत्पन्न करता है।

मैं सोच रहा था कि क्या किसी और को कैसे सबसे अच्छा यह से निपटने के लिए कोई सुझाव है?

public class ThreadSafeObservableCollection<T> : ObservableCollection<T> 
{ 
    public ThreadSafeObservableCollection(List<T> collection) 
     : base(collection) 
    { 
     dispatcher = Dispatcher.CurrentDispatcher; 
     rwLock = new ReaderWriterLock(); 
    } 

    protected override void InsertItem(int index, T item) 
    { 
     if (dispatcher.CheckAccess()) 
     { 
      if (index > this.Count) 
       return; 
      LockCookie c = rwLock.UpgradeToWriterLock(-1); 
      base.InsertItem(index, item); 
      rwLock.DowngradeFromWriterLock(ref c); 
     } 
     else 
     { 
      object[] obj = new object[] { index, item }; 
      dispatcher.Invoke(
       DispatcherPriority.Send, 
       (SendOrPostCallback)delegate { InsertItemImpl(obj); }, 
       obj); 
     } 
    } 

मैं तो एक दृश्य मॉडल वर्ग एक पृष्ठभूमि कार्यकर्ता किया जाता है जो बचाने है कि है:

तो वर्तमान में मैं एक वर्ग कि ObservableCollection से विरासत है।

एक बार बचाने पूरा हो गया है, एक घटना अपनी सूची को अद्यतन करने के एक और दृश्य मॉडल के लिए निकाल दिया गया है।

protected override void OnObjectAddedToRepository(object sender, ObjectEventArgs<cdAdministrators> e) 
    { 
     Dispatcher x = Dispatcher.CurrentDispatcher; 
     var viewModel = new AdministratorViewModel(e.EventObject, DataAccess); 
     viewModel.RecentlyAdded = true; 
     viewModel.ItemSelected += this.OnItemSelected; 
     this.AllViewModels.Add(viewModel); 
     RecentlyAddedViewModel = viewModel; 

     OnPropertyChanged(null); 
    } 

दोनों सूचियों एक अलग पृष्ठभूमि कार्यकर्ता धागा द्वारा बनाई गई हैं।

उत्तर

7

जहां आपके पास कोड है जो आइटम को अवलोकन संग्रह (संभावित रूप से दृश्य मॉडल में) में जोड़ता है, Add को Dispatcher.BeginInvoke कॉल में कॉल करें।

मान्य रूप से इसका मतलब है कि व्यू मॉडल को प्रेषक के बारे में जानना आवश्यक है, जो तब परीक्षण करने के लिए अजीब हो जाता है ... सौभाग्य से अपने IDispatcher इंटरफ़ेस को पेश करना और सामान्य तरीके से निर्भरता इंजेक्शन का उपयोग करना बहुत मुश्किल नहीं है।

+0

हाय जॉन, धन्यवाद आपके उत्तर के लिए, मैं पहले से ही एक संग्रह वस्तु है, जो InsertItem पर ObserveableCollection से विरासत इस करता है, तो गलत तो है Dispather.BeginInvoke, हालांकि यह अभी भी काम नहीं कर रहा Dispatcher.CheckAccess करता है ?? – jpgooner

+0

@jpgooner: क्या आप वाकई कोड का उपयोग कर रहे हैं? क्या आप एक संक्षिप्त लेकिन पूर्ण उदाहरण के साथ आ सकते हैं जो समस्या का प्रदर्शन करता है? –

+0

मैंने ऊपर और अधिक विवरण जोड़ा है, अगर आपको अब और चाहिए तो मुझे बताएं, मैं अभी भी स्टैक ओवरफ्लो – jpgooner

3

इस बारे में कैसे?

public class ThreadSafeObservableCollection<T> : ObservableCollection<T> 
{ 
    private SynchronizationContext SynchronizationContext; 

    public ThreadSafeObservableCollection() 
    { 
     SynchronizationContext = SynchronizationContext.Current; 

     // current synchronization context will be null if we're not in UI Thread 
     if (SynchronizationContext == null) 
      throw new InvalidOperationException("This collection must be instantiated from UI Thread, if not, you have to pass SynchronizationContext to con        structor."); 
    } 

    public ThreadSafeObservableCollection(SynchronizationContext synchronizationContext) 
    { 
     if (synchronizationContext == null) 
      throw new ArgumentNullException("synchronizationContext"); 

     this.SynchronizationContext = synchronizationContext; 
    } 

    protected override void ClearItems() 
    { 
     this.SynchronizationContext.Send(new SendOrPostCallback((param) => base.ClearItems()), null); 
    } 

    protected override void InsertItem(int index, T item) 
    { 
     this.SynchronizationContext.Send(new SendOrPostCallback((param) => base.InsertItem(index, item)), null); 
    } 

    protected override void RemoveItem(int index) 
    { 
     this.SynchronizationContext.Send(new SendOrPostCallback((param) => base.RemoveItem(index)), null); 
    } 

    protected override void SetItem(int index, T item) 
    { 
     this.SynchronizationContext.Send(new SendOrPostCallback((param) => base.SetItem(index, item)), null); 
    } 

    protected override void MoveItem(int oldIndex, int newIndex) 
    { 
     this.SynchronizationContext.Send(new SendOrPostCallback((param) => base.MoveItem(oldIndex, newIndex)), null); 
    } 
} 
2

मैं एक blog post ObeservableCollection के तरीकों के सभी प्रबंधित करने के लिए डिस्पैचर का उपयोग करता है पाया। यहां कोड का एक स्निप है, पूरे वर्ग के लिए post देखें।

public class DispatchingObservableCollection<T> : ObservableCollection<T> 
{ 
    /// <summary> 
    /// The default constructor of the ObservableCollection 
    /// </summary> 
    public DispatchingObservableCollection() 
    { 
     //Assign the current Dispatcher (owner of the collection) 
     _currentDispatcher = Dispatcher.CurrentDispatcher; 
    } 

    private readonly Dispatcher _currentDispatcher; 

    /// <summary> 
    /// Executes this action in the right thread 
    /// </summary> 
    ///<param name="action">The action which should be executed</param> 
    private void DoDispatchedAction(Action action) 
    { 
     if (_currentDispatcher.CheckAccess()) 
      action(); 
     else 
      _currentDispatcher.Invoke(DispatcherPriority.DataBind, action); 
    } 

    /// <summary> 
    /// Clears all items 
    /// </summary> 
    protected override void ClearItems() 
    { 
     DoDispatchedAction(() => base.ClearItems()); 
    } 

    /// <summary> 
    /// Inserts a item at the specified index 
    /// </summary> 
    ///<param name="index">The index where the item should be inserted</param> 
    ///<param name="item">The item which should be inserted</param> 
    protected override void InsertItem(int index, T item) 
    { 
     DoDispatchedAction(() => base.InsertItem(index, item)); 
    } 
+0

अच्छा उदाहरण! बस एक छोटा सुधार: संरक्षित ओवरराइड इंटर्ट इटिम (इंट इंडेक्स, टी आइटम) {DoDispatchedAction (() => बेसइन्सर्टआईटम (इंडेक्स, आइटम)); } वास्तव में संरक्षित ओवरराइड इंटर्ट इटिम (इंट इंडेक्स, टी आइटम) {DoDispatchedAction (() => base.InsertItem (अनुक्रमणिका, आइटम)) ओवरराइड है; } –

+0

धन्यवाद। मुझे यकीन नहीं है कि मैंने स्पष्ट रूप से एक विधि क्यों बनाई और दूसरे उदाहरण के लिए अनाम विधि का उपयोग किया। मैंने उन्हें साफ कर लिया है। – chilltemp