2011-06-30 21 views
8

के साथ सही ढंग से अपडेट नहीं किया गया है मैं वर्तमान में एक सूची दृश्य के लिए अपनी डेटा ऑब्जेक्ट्स को स्टोर करने के लिए एक अवलोकन संग्रह का उपयोग कर रहा हूं। संग्रह में नई ऑब्जेक्ट्स जोड़ना ठीक काम करता है, और सूची ठीक से अद्यतन देखें। हालांकि जब मैं संग्रह में किसी ऑब्जेक्ट के गुणों में से किसी एक को बदलने का प्रयास करता हूं तो सूची दृश्य ठीक से अपडेट नहीं होगा। उदाहरण के लिए, मेरे पास एक अवलोकन संग्रह डेटाकोलेक्शन है। मैंListView ObservableCollection

_DataCollections.ElementAt(count).Status = "Active"; 

बटन बटन के कारण मैं लंबे ऑपरेशन से पहले इस बदलाव को निष्पादित करता हूं। सूची दृश्य परिवर्तन को प्रतिबिंबित नहीं करेगा। तो मैं myListView.Items.Refresh() जोड़ता हूं; यह काम करता है, हालांकि सूची दृश्य को बटन_क्लिक विधि पूर्ण होने तक रीफ्रेश नहीं किया जाता है, जो तब तक अच्छा नहीं है। उदाहरण के लिए:

button1_Click(...) 
    { 
     _DataCollections.ElementAt(count).Status = "Active"; 
     myListView.Items.Refresh(); 
     ExecuteLongOperation(); 
     _DataCollections.ElementAt(count).Status = "Finished"; 
     myListView.Items.Refresh(); 
    } 

स्थिति "सक्रिय" गोटो कभी नहीं होगा, यह सीधे जाना होगा "समाप्त" करने के बाद विधि पूरा करती है। मैं भी इस तरह एक डिस्पैचर उपयोग करने की कोशिश:

button1_Click(...) 
    { 
     this.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Background, 
      (NoArgDelegate)delegate { _DataCollection.ElementAt(count).Status = "Active"; myListView.Items.Refresh(); }); 

     ExecuteLongOperation(); 
    this.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Background, 
      (NoArgDelegate)delegate { _DataCollection.ElementAt(count).Status = "Finished"; myListView.Items.Refresh(); }); 

    } 

हालांकि, कि या तो सही ढंग से काम करने के लिए प्रतीत नहीं होता। किसी भी सुझाव या विचारों की सराहना की जाएगी।

उत्तर

3

इसे हल करने के लिए मैंने VeryObservableCollection नामक एक कक्षा बनाई। आपके द्वारा जोड़े जाने वाले प्रत्येक ऑब्जेक्ट के लिए, यह ऑब्जेक्ट की NotifyPropertyChanged ईवेंट को एक हैंडलर पर बनाता है जो संग्रह संग्रहित ईवेंट को ट्रिगर करता है। प्रत्येक वस्तु को हटाने के लिए, यह हैंडलर को हटा देता है। बहुत सरल और आपको वही देगा जो आप चाहते हैं। आंशिक कोड:

public class VeryObservableCollection<T> : ObservableCollection<T> 

/// <summary> 
/// Override for setting item 
/// </summary> 
/// <param name="index">Index</param> 
/// <param name="item">Item</param> 
protected override void SetItem(int index, T item) 
{ 
    try 
    { 
     INotifyPropertyChanged propOld = Items[index] as INotifyPropertyChanged; 
     if (propOld != null) 
      propOld.PropertyChanged -= new PropertyChangedEventHandler(Affecting_PropertyChanged); 
    } 
    catch (Exception ex) 
    { 
     Exception ex2 = ex.InnerException; 
    } 
    INotifyPropertyChanged propNew = item as INotifyPropertyChanged; 
    if (propNew != null) 
     propNew.PropertyChanged += new PropertyChangedEventHandler(Affecting_PropertyChanged); 

    base.SetItem(index, item); 
} 
+0

मुझे Effecting_PropertyChanged विधि के सही कार्यान्वयन को खोजने के लिए लंबे समय की आवश्यकता है .. आपको केवल एक पंक्ति की आवश्यकता है: 'MyBase.OnCollectionChanged (नया NotifyCollectionChangedEventArgs (NotifyCollectionChangedAction.Reset))' और मैं InsertItem को ओवरराइट करने और ObservableCollection के निकालने के लिए अनुशंसा करता हूं, क्योंकि SetItem didn मेरे लिए काम नहीं करता –

+0

@ फ़ेलिक्स, हाँ, इसके लिए और भी कुछ था। कक्षा कार्यान्वयन 800 से अधिक लाइनों है। मैंने कहा था कि मैंने आंशिक कोड पोस्ट किया था, मुख्य रूप से सामान्य विचार देने के लिए। –

+0

मैंने इसे अन्य लोगों के लिए लिखा है जो इस पोस्ट को ढूंढते हैं और यह नहीं जानते कि इस कोड लाइन को कैसे कार्यान्वित किया जाए। यह सुधार नहीं था, यह काम करने के लिए सिर्फ एक विस्तार है। :) लेकिन आपकी कक्षा की लंबाई 800 लाइनों क्यों है? मैं वास्तव में आपके पूर्ण वर्ग कार्यान्वयन को देखने का आनंद लेता हूं। –

2

आपने ऑब्जर्जेबल कोलेक्शन के साथ क्लासिक समस्या में भाग लिया है। यह केवल तभी सूचित करता है जब कोई आइटम जोड़ा या हटा दिया जाता है। जब संग्रह में किसी आइटम की कोई संपत्ति बदलती है तो यह सूचित नहीं होता है। यदि आप इस तरह के परिवर्तनों के बारे में अधिसूचित होना चाहते हैं तो आपको अपना खुद का कस्टम संग्रह बनाना होगा और संपत्ति को अलग-अलग ऑब्जेक्ट्स पर मैन्युअल रूप से बदलना होगा। माफ करना दोस्त।

3

आपको उचित डेटा बाइंडिंग तकनीकों का उपयोग करना होगा, और फिर यह स्वचालित रूप से काम करेगा।

आवश्यक ...

  1. ObservableCollection के अंदर अपने वर्ग पर INotifyPropertyChanged लागू (और सुनिश्चित करें कि आप घटना है जब आप उस वर्ग पर गुण सेट कर रहे हैं ट्रिगर कर रहे हैं बनाने के) अपने ListView के ItemTemplate पर
  2. , हो सुनिश्चित करें कि आप गुणों के लिए बाध्यकारी का उपयोग कर रहे हैं

यदि आप उन दो चीजों को करते हैं, तो "ताज़ा करें" कॉल या किसी अन्य चीज़ की आवश्यकता नहीं है। INotifyPropertyChanged को ट्रिगर करने वाली संपत्ति को सेट करने से आइटम टेम्पलेट को अपडेट करने का बाध्यकारी हो जाएगा।

कार्यान्वयन INotifyPropertyChanged ObservableCollection के अंदर अपने वर्ग पर ... (BindableBase वर्ग को देखने अगर आप इसके बारे में पहले से ही पता नहीं है)

public class ToDoItem : INotifyPropertyChanged 
{ 
    public event PropertyChangedEventHandler PropertyChanged; 

    private string _name; 
    public string Name 
    { 
     get { return _name; } 
     set { SetProperty(ref _name, value); } 
    } 

    private DateTime _date; 
    public DateTime Date 
    { 
     get { return _date; } 
     set { SetProperty(ref _date, value); } 
    } 

    protected bool SetProperty<T>(ref T storage, T value, [CallerMemberName]string propertyName = null) 
    { 
     if (object.Equals(storage, value)) return false; 

     storage = value; 
     this.OnPropertyChanged(propertyName); 
     return true; 
    } 

    protected void OnPropertyChanged(string propertyName) 
    { 
     var eventHandler = this.PropertyChanged; 
     if (eventHandler != null) 
     { 
      eventHandler(this, new PropertyChangedEventArgs(propertyName)); 
     } 
    } 
} 

आपका ListView

<ListView 
    x:Name="listView"> 

    <ListView.ItemTemplate> 
     <DataTemplate> 

      <StackPanel> 

       <TextBlock 
        Text="{Binding Name}"/> 

       <TextBlock 
        Text="{Binding Date}"/> 

      </StackPanel> 

     </DataTemplate> 
    </ListView.ItemTemplate> 

</ListView> 

आपका पर्यवेक्षण चयन ...

private ObservableCollection<ToDoItem> _toDoItems = new ObservableCollection<ToDoItem>(); 

// Assign the collection to the ListView 
listView.ItemsSource = _toDoItems; 

के संग्रह से काम करता है बातें जोड़ रहा है ...

_toDoItems.Add(new ToDoItem() 
{ 
    Name = "Item " + (_toDoItems.Count + 1), 
    Date = DateTime.Now 
}); 

और अद्यतन करने के लिए, आप के लिए, काम करता है क्या पूछ रहे थे ...

ToDoItem item = _toDoItems[randomIndex]; 

item.Name = "Updated " + item.Name; 
item.Date = DateTime.Now; 

कोई कॉल "ताज़ा करें" या किसी और चीज की आवश्यकता है। सूची बदलने के बिना आइटम स्वयं अपडेट होता है।

आइटम 4 को अद्यतन करने से पहले ...

Before updating Item 4

आइटम 4 अद्यतन करने के बाद ...

After updating Item 4

पूर्ण कोड नमूना यहाँ उपलब्ध है:CODE SAMPLE