दिलचस्प पोस्ट
क्या कोई जावा रिच टेक्स्ट एडिटर सुझा सकता है? प्रतिक्रिया घटक प्रदान नहीं कर रहा है: जेएस प्रतिक्रिया टीडी के अंदर एक डीआईवी एक बुरा विचार है? आदेश में कई क्षेत्रों में कोणीय आईई 7 में getElementsByName कैसे व्यक्तिगत टुकड़ा मैन्युअल रूप से वापस बटन दबाने पर पिछले टुकड़े पर वापस जाने के लिए? .NET अनुप्रयोग XamlParseException को प्रारंभ और प्राप्त नहीं कर सकता AppSettings बनाम ऐप्लिकेशन सैटिंग्स के पेशेवरों और विपक्ष (.NET app.config / Web.config) एंड्रॉइड विडियोविव्ही ब्लैक स्क्रीन कैसे सी कार्यक्रम में तारीख और समय मूल्य प्राप्त करने के लिए एक्स अक्ष में उच्च चार्ज की तारीखें कैसे प्राप्त करें? सी # में दिनांकटाइम मान्य करें Php का उपयोग करके स्ट्रिंग में सिंगल-कोट (एपॉस्ट्रॉफ़ी) कैसे बचें मैं अपने जीवीएम के लिए डिफ़ॉल्ट लोकेल कैसे सेट करूं? सी # में प्रतिबिंब प्रवेश सुरक्षित / निजी सदस्य वर्ग क्यों हो सकता है?

अवलोकन के समय को सूचित करें जब आइटम में परिवर्तन होता है

मुझे इस लिंक पर मिला

अवलोकन जब उसमें आइटम बदलता है तब उसे नहीं देखा जा सकता (यहां तक ​​कि INotifyPropertyChanged के साथ)

कुछ तकनीकों को अवलोकन के लिए सूचित किया जाता है कि एक आइटम बदल गया है। सचमुच ओब्सवॉवेबल इस लिंक में चयन मैं क्या देख रहा हूँ लगता है।

public class TrulyObservableCollection<T> : ObservableCollection<T> where T : INotifyPropertyChanged { public TrulyObservableCollection() : base() { CollectionChanged += new NotifyCollectionChangedEventHandler(TrulyObservableCollection_CollectionChanged); } void TrulyObservableCollection_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) { if (e.NewItems != null) { foreach (Object item in e.NewItems) { (item as INotifyPropertyChanged).PropertyChanged += new PropertyChangedEventHandler(item_PropertyChanged); } } if (e.OldItems != null) { foreach (Object item in e.OldItems) { (item as INotifyPropertyChanged).PropertyChanged -= new PropertyChangedEventHandler(item_PropertyChanged); } } } void item_PropertyChanged(object sender, PropertyChangedEventArgs e) { NotifyCollectionChangedEventArgs a = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset); OnCollectionChanged(a); } 

}

लेकिन जब मैं इसका इस्तेमाल करने की कोशिश करता हूं, तो मुझे संग्रह पर नोटिफिकेशन नहीं मिल रहा है। मुझे यकीन नहीं है कि यह मेरे सी # कोड में सही ढंग से कैसे लागू करें:

एक्सएएमएल:

  <DataGrid AutoGenerateColumns="False" ItemsSource="{Binding MyItemsSource, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"> <DataGrid.Columns> <DataGridCheckBoxColumn Binding="{Binding MyProperty, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/> </DataGrid.Columns> </DataGrid> 

देखेंमोडेल:

 public class MyViewModel : ViewModelBase { private TrulyObservableCollection<MyType> myItemsSource; public TrulyObservableCollection<MyType> MyItemsSource { get { return myItemsSource; } set { myItemsSource = value; // Code to trig on item change... RaisePropertyChangedEvent("MyItemsSource"); } } public MyViewModel() { MyItemsSource = new TrulyObservableCollection<MyType>() { new MyType() { MyProperty = false }, new MyType() { MyProperty = true }, new MyType() { MyProperty = false } }; } } public class MyType : ViewModelBase { private bool myProperty; public bool MyProperty { get { return myProperty; } set { myProperty = value; RaisePropertyChangedEvent("MyProperty"); } } } public class ViewModelBase : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; protected void RaisePropertyChangedEvent(string propertyName) { if (PropertyChanged != null) { PropertyChangedEventArgs e = new PropertyChangedEventArgs(propertyName); PropertyChanged(this, e); } } } 

जब मैं प्रोग्राम चलाता हूं, तो मेरे पास 3 चेकबॉक्स झूठे, सच्चे, झूठे हैं जैसे कि संपत्ति प्रारंभिक रूप में। लेकिन जब मैं किसी एक कोकेकबॉक्स की स्थिति को बदलता हूं, तो प्रोग्राम item_PropertyChanged के माध्यम से जाना जाता है लेकिन कभी भी MyItemsSource Property Code में नहीं।

वेब के समाधान से एकत्रित समाधान "अवलोकन के समय को सूचित करें जब आइटम में परिवर्तन होता है"

जिस स्थान पर आपने टिप्पणी की है, // Code to trig on item change... केवल तभी ट्रिगर होगा जब संग्रह ऑब्जेक्ट बदल जाता है, जैसे कि यह किसी नए ऑब्जेक्ट पर सेट हो जाता है या नल पर सेट हो जाता है।

TrulyObservableCollection के अपने वर्तमान कार्यान्वयन के साथ, अपने संग्रह की संपत्ति परिवर्तित घटनाओं को संभालने के लिए, MyItemsSource के संग्रह परिवर्तित ईवेंट में कुछ पंजीकृत करें

 public MyViewModel() { MyItemsSource = new TrulyObservableCollection<MyType>(); MyItemsSource.CollectionChanged += MyItemsSource_CollectionChanged; MyItemsSource.Add(new MyType() { MyProperty = false }); MyItemsSource.Add(new MyType() { MyProperty = true}); MyItemsSource.Add(new MyType() { MyProperty = false }); } void MyItemsSource_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) { // Handle here } 

व्यक्तिगत रूप से मैं वास्तव में इस क्रियान्वयन को पसंद नहीं करता। आप एक CollectionChanged परिवर्तित इवेंट को बढ़ा रहे हैं जो कहता है कि पूरे संग्रह को रीसेट कर दिया गया है, कभी भी कोई संपत्ति बदलता है। यकीन है कि यह यूआई अपडेट को किसी भी समय संग्रह में एक आइटम बना देगा, लेकिन मुझे लगता है कि प्रदर्शन पर बुरा है, और यह पता नहीं है कि संपत्ति किस प्रकार बदल गई है, जो जानकारी के महत्वपूर्ण टुकड़ों में से एक है मुझे आम तौर पर तब की आवश्यकता होती है जब कुछ PropertyChanged

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

 public MyViewModel() { MyItemsSource = new ObservableCollection<MyType>(); MyItemsSource.CollectionChanged += MyItemsSource_CollectionChanged; MyItemsSource.Add(new MyType() { MyProperty = false }); MyItemsSource.Add(new MyType() { MyProperty = true}); MyItemsSource.Add(new MyType() { MyProperty = false }); } void MyItemsSource_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) { if (e.NewItems != null) foreach(MyType item in e.NewItems) item.PropertyChanged += MyType_PropertyChanged; if (e.OldItems != null) foreach(MyType item in e.OldItems) item.PropertyChanged -= MyType_PropertyChanged; } void MyType_PropertyChanged(object sender, PropertyChangedEventArgs e) { if (e.PropertyName == "MyProperty") DoWork(); } 

मैंने इस मामले को स्थिर कार्रवाई का उपयोग करके हल किया


 public class CatalogoModel { private String _Id; private String _Descripcion; private Boolean _IsChecked; public String Id { get { return _Id; } set { _Id = value; } } public String Descripcion { get { return _Descripcion; } set { _Descripcion = value; } } public Boolean IsChecked { get { return _IsChecked; } set { _IsChecked = value; NotifyPropertyChanged("IsChecked"); OnItemChecked.Invoke(); } } public static Action OnItemChecked; } public class ReglaViewModel : ViewModelBase { private ObservableCollection<CatalogoModel> _origenes; CatalogoModel.OnItemChecked = () => { var x = Origenes.Count; //Entra cada vez que cambia algo en _origenes }; } 

ObservableCollection और इसके डेरिवेटिव्स ने अपनी संपत्ति में आंतरिक रूप से वृद्धि की है। आपके सेटर में कोड केवल तभी शुरू किया जाना चाहिए, जब आप एक नया TrulyObservableCollection<MyType> को MyItemsSource संपत्ति में MyItemsSource । यही है, केवल एक बार, कन्स्ट्रक्टर से ही होना चाहिए।

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

मुझे पता है कि यह देर हो चुकी है, लेकिन शायद यह दूसरों की मदद करता है मैंने एक क्लास NotifyObservableCollection बनाया है, जो आइटम की NotifyObservableCollection की समस्या को हल करता है, जब आइटम की कोई संपत्ति बदल जाती है। उपयोग ObservableCollection रूप में सरल है

 public class NotifyObservableCollection<T> : ObservableCollection<T> where T : INotifyPropertyChanged { private void Handle(object sender, PropertyChangedEventArgs args) { OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset, null)); } protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e) { if (e.NewItems != null) { foreach (object t in e.NewItems) { ((T) t).PropertyChanged += Handle; } } if (e.OldItems != null) { foreach (object t in e.OldItems) { ((T) t).PropertyChanged -= Handle; } } base.OnCollectionChanged(e); } 

आइटम आइटम को जोड़ा या निकाला जाता है, जबकि वस्तुओं के लिए बदल जाते हैं, घटनाओं को बदल दिया जाता है।

उपयोग:

 public abstract class ParameterBase : INotifyPropertyChanged { protected readonly CultureInfo Ci = new CultureInfo("en-US"); private string _value; public string Value { get { return _value; } set { if (value == _value) return; _value = value; OnPropertyChanged(); } } } public class AItem { public NotifyObservableCollection<ParameterBase> Parameters { get { return _parameters; } set { NotifyCollectionChangedEventHandler cceh = (sender, args) => OnPropertyChanged(); if (_parameters != null) _parameters.CollectionChanged -= cceh; _parameters = value; //needed for Binding to AItem at xaml directly _parameters.CollectionChanged += cceh; } } public NotifyObservableCollection<ParameterBase> DefaultParameters { get { return _defaultParameters; } set { NotifyCollectionChangedEventHandler cceh = (sender, args) => OnPropertyChanged(); if (_defaultParameters != null) _defaultParameters.CollectionChanged -= cceh; _defaultParameters = value; //needed for Binding to AItem at xaml directly _defaultParameters.CollectionChanged += cceh; } } public class MyViewModel { public NotifyObservableCollection<AItem> DataItems { get; set; } } 

यदि अब DataItems में किसी आइटम की संपत्तियां बदलती हैं, तो निम्नलिखित xaml को एक अधिसूचना मिल जाएगी, हालांकि यह Parameters[0] या वस्तु को बदलकर वस्तु के बदलते संपत्ति Value को छोड़कर (ट्रेंजर्स पर कन्वर्टर्स को विश्वसनीय मानता है परिवर्तन)।

 <DataGrid CanUserAddRows="False" AutoGenerateColumns="False" ItemsSource="{Binding DataItems}"> <DataGrid.Columns> <DataGridTextColumn Binding="{Binding Parameters[0].Value}" Header="P1"> <DataGridTextColumn.CellStyle> <Style TargetType="DataGridCell"> <Setter Property="Background" Value="Aqua" /> <Style.Triggers> <DataTrigger Value="False"> <!-- Bind to Items with changing properties --> <DataTrigger.Binding> <MultiBinding Converter="{StaticResource ParameterCompareConverter}"> <Binding Path="DefaultParameters[0]" /> <Binding Path="Parameters[0]" /> </MultiBinding> </DataTrigger.Binding> <Setter Property="Background" Value="DeepPink" /> </DataTrigger> <!-- Binds to AItem directly --> <DataTrigger Value="True" Binding="{Binding Converter={StaticResource CheckParametersConverter}}"> <Setter Property="FontWeight" Value="ExtraBold" /> </DataTrigger> </Style.Triggers> </Style> </DataGridTextColumn.CellStyle> </DataGridTextColumn> 

किसी सामान्य तरीके से किसी वस्तु की परिवर्तित संपत्ति के बारे में सूचित करने के लिए आप एक एक्सटेंशन विधि का उपयोग कर सकते हैं।

 public static class ObservableCollectionExtension { public static void NotifyPropertyChanged<T>(this ObservableCollection<T> observableCollection, Action<T, PropertyChangedEventArgs> callBackAction) where T : INotifyPropertyChanged { observableCollection.CollectionChanged += (sender, args) => { //Does not prevent garbage collection says: http://stackoverflow.com/questions/298261/do-event-handlers-stop-garbage-collection-from-occuring //publisher.SomeEvent += target.SomeHandler; //then "publisher" will keep "target" alive, but "target" will not keep "publisher" alive. if (args.NewItems == null) return; foreach (T item in args.NewItems) { item.PropertyChanged += (obj, eventArgs) => { callBackAction((T)obj, eventArgs); }; } }; } } public void ExampleUsage() { var myObservableCollection = new ObservableCollection<MyTypeWithNotifyPropertyChanged>(); myObservableCollection.NotifyPropertyChanged((obj, notifyPropertyChangedEventArgs) => { //DO here what you want when a property of an item in the collection has changed. }); } 

यहां सभी समाधान सही हैं, लेकिन वे एक महत्वपूर्ण परिदृश्य खो रहे हैं जिसमें विधि साफ़ () का उपयोग किया जाता है, जो NotifyCollectionChangedEventArgs ऑब्जेक्ट में OldItems प्रदान नहीं करता है।

यह एकदम सही ObservableCollection

 public class ObservableCollectionEX<T> : ObservableCollection<T> { #region Constructors public ObservableCollectionEX() : base() { CollectionChanged += ObservableCollection_CollectionChanged; } public ObservableCollectionEX(IEnumerable<T> c) : base(c) { CollectionChanged += ObservableCollection_CollectionChanged; } public ObservableCollectionEX(List<T> l) : base(l) { CollectionChanged += ObservableCollection_CollectionChanged; } #endregion public new void Clear() { foreach (var item in this) { if (item is INotifyPropertyChanged i) { if (i != null) i.PropertyChanged -= Element_PropertyChanged; } } base.Clear(); } private void ObservableCollection_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) { if (e.OldItems != null) foreach (var item in e.OldItems) { if (item != null && item is INotifyPropertyChanged i) { i.PropertyChanged -= Element_PropertyChanged; } } if (e.NewItems != null) foreach (var item in e.NewItems) { if (item != null && item is INotifyPropertyChanged i) { i.PropertyChanged -= Element_PropertyChanged; i.PropertyChanged += Element_PropertyChanged; } } } private void Element_PropertyChanged(object sender, PropertyChangedEventArgs e) { //raise the event ItemPropertyChanged?.Invoke(sender, e); } /// <summary> /// the sender is the Item /// </summary> public PropertyChangedEventHandler ItemPropertyChanged; } 

आप इस तरह से मालिक सूची प्रदान करने के लिए मदर्राफ्ट बदल सकते हैं

कुछ नाम स्थान में कक्षा के बाहर:
public delegate void ListedItemPropertyChangedEventHandler(IList SourceList, object Item, PropertyChangedEventArgs e);

कक्षा में इन परिवर्तन:

 private void Element_PropertyChanged(object sender, PropertyChangedEventArgs e) { //raise the event ItemPropertyChanged?.Invoke(this,sender, e); } public ListedItemPropertyChangedEventHandler ItemPropertyChanged;