функция вызова при изменении списка? [Дубликат]

Нет. Вам нужен полноразмерный парсер для этого типа проблем.

7
задан Raphaël Althaus 8 October 2012 в 16:45
поделиться

5 ответов

Вы редко создаете новый экземпляр класса коллекции в классе. Создайте его один раз и очистите его, а не создайте новый список. (и использовать ObservableCollection, поскольку он уже унаследовал интерфейс INotifyCollectionChanged )

private readonly ObservableCollection<T> list;
public ctor() {
    list = new ObservableCollection<T>();
    list.CollectionChanged += listChanged;
}

public ObservableCollection<T> List { get { return list; } }

public void Clear() { list.Clear(); }

private void listChanged(object sender, NotifyCollectionChangedEventArgs args) {
   // list changed
}

Таким образом, вам нужно только один раз подключить события и выполнить «сброс», вызвав метод clear вместо того, чтобы проверять значение null или равенство первому списку в наборе доступа для свойства.

12
ответ дан Patrick 21 August 2018 в 05:18
поделиться
  • 1
    То, как я думал, сделав сеттера частным и использовать его как автопромышленность. public ObservableCollection<T> List { get; private set; } Я пойду с этим. – Martin 9 October 2012 в 10:10
  • 2
    @Martin: сделав его только для чтения и установив его только в конструкторе, добавит ограничение, поскольку вы не можете его установить нигде. Autoproperties прекрасны, но когда поле нужно устанавливать только один раз, я делаю его только для чтения и вместо этого использую поле поддержки. – Patrick 9 October 2012 в 10:19

У меня есть решение, когда кто-то вызывает метод Generic из объекта IList.add (object). Чтобы вы также получили уведомление.

using System;
using System.Collections;
using System.Collections.Generic;

namespace YourNamespace
{
    public class ObjectDoesNotMatchTargetBaseTypeException : Exception
    {
        public ObjectDoesNotMatchTargetBaseTypeException(Type targetType, object actualObject)
            : base(string.Format("Expected base type ({0}) does not match actual objects type ({1}).",
                targetType, actualObject.GetType()))
        {
        }
    }

    /// <summary>
    /// Allows you to react, when items were added or removed to a generic List.
    /// </summary>
    public abstract class NoisyList<TItemType> : List<TItemType>, IList
    {
        #region Public Methods
        /******************************************/
        int IList.Add(object item)
        {
            CheckTargetType(item);
            Add((TItemType)item);
            return Count - 1;
        }

        void IList.Remove(object item)
        {
            CheckTargetType(item);
            Remove((TItemType)item);
        }

        public new void Add(TItemType item)
        {
            base.Add(item);
            OnItemAdded(item);
        }

        public new bool Remove(TItemType item)
        {
            var result = base.Remove(item);
            OnItemRemoved(item);
            return result;
        }
        #endregion

        # region Private Methods
        /******************************************/
        private static void CheckTargetType(object item)
        {
            var targetType = typeof(TItemType);
            if (item.GetType().IsSubclassOf(targetType))
                throw new ObjectDoesNotMatchTargetBaseTypeException(targetType, item);
        }
        #endregion

        #region Abstract Methods
        /******************************************/
        protected abstract void OnItemAdded(TItemType addedItem);

        protected abstract void OnItemRemoved(TItemType removedItem);
        #endregion
    }
}
0
ответ дан Daniel 21 August 2018 в 05:18
поделиться

Если вы не хотите или не можете преобразовать в Observable Collection, попробуйте следующее:

public class EventList<T> : IList<T> /* NOTE: Changed your List<T> to IList<T> */
{
  private List<T> list; // initialize this in your constructor.
  public event ListChangedEventDelegate ListChanged;
  public delegate void ListChangedEventDelegate();

  private void notify()
  {
      if (ListChanged != null
          && ListChanged.GetInvocationList().Any())
      {
        ListChanged();
      }
  }

  public new void Add(T item)
  {
      list.Add(item);
      notify();
  }

  public List<T> Items {
    get { return list; } 
    set {
      list = value; 
      notify();
    }
  }
  ...
}

Теперь, для вашего свойства, вы сможете сократить свой код до этого:

public EventList List
{
  get { return m_List.Items; }
  set
  {
      //m_List.ListChanged -= List_ListChanged;

      m_List.Items = value;

      //m_List.ListChanged += List_ListChanged;
      //List_ListChanged();
  }
}

Почему? Установка чего-либо в EventList.Items вызовет вашу приватную notify().

5
ответ дан jp2code 21 August 2018 в 05:18
поделиться
  • 1
    ПРИМЕЧАНИЕ. Не забудьте реализовать остальную часть интерфейса IList<T>! – jp2code 8 October 2012 в 17:03
  • 2
    Определение Добавить как new приведет к тому, что ((IList)list).Add(item) не вызовет метод уведомления. – Patrick 8 October 2012 в 17:04
  • 3
    Это произойдет потому, что я добавил вызов notify() к этому добавлению свойства. – jp2code 8 October 2012 в 17:16
  • 4
    Кроме того, я не уверен, почему OP определил Add как new - я просто использовал то, что у него было. Я предполагаю, что у него есть причины. – jp2code 8 October 2012 в 17:19
  • 5
    Это не будет , если вы используете базовый класс , как показано на примере dotnetpad.net/ViewPaste/IYP6mJpXqUmpISCDe28YKA . Я не обвиняю вас, просто хотел бы отметить это, чтобы быть осторожным при использовании нового метода. Это вам даже не нужно, поскольку вы используете интерфейс IList вместо класса List, поэтому проблема сама по себе исчезает в вашем примере;) – Patrick 8 October 2012 в 19:37

Если ObservableCollection не является для вас решением, вы можете попробовать следующее:

A) Внедрить пользовательские EventArgs, которые будут содержать новый атрибут Count, когда событие будет запущено.

public class ChangeListCountEventArgs : EventArgs
{
    public int NewCount
    {
        get;
        set;
    }

    public ChangeListCountEventArgs(int newCount)
    {
        NewCount = newCount;
    }
}

B) Внедрите собственный список, который наследует от List и переопределяет атрибут Count и конструкторы в соответствии с вашими потребностями:

public class CustomList<T> : List<T>
{
    public event EventHandler<ChangeListCountEventArgs> ListCountChanged;

    public new int Count
    {
        get
        {
            ListCountChanged?.Invoke(this, new ChangeListCountEventArgs(base.Count));
            return base.Count;
        }
    }

    public CustomList()
    { }

    public CustomList(List<T> list) : base(list)
    { }

    public CustomList(CustomList<T> list) : base(list)
    { }
}

C) Наконец, подпишитесь на свое событие:

var myList = new CustomList<YourObject>();
myList.ListCountChanged += (obj, e) => 
{
    // get the count thanks to e.NewCount
};
1
ответ дан Nicolas Bodin-Ripert 21 August 2018 в 05:18
поделиться

ObservableCollection - это список с событием CollectionChanged

ObservableCollection.CollectionChanged Event

Как подключить обработчик событий, см. ответ от Patrick. +1

Не уверен, что вы ищете, но я использую это для коллекции с одним событием, которое срабатывает при добавлении, удалении и изменении.

public class ObservableCollection<T>: INotifyPropertyChanged
{
    private BindingList<T> ts = new BindingList<T>();

    public event PropertyChangedEventHandler PropertyChanged;

    // This method is called by the Set accessor of each property. 
    // The CallerMemberName attribute that is applied to the optional propertyName 
    // parameter causes the property name of the caller to be substituted as an argument. 
    private void NotifyPropertyChanged( String propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }

    public BindingList<T> Ts
    {
        get { return ts; }
        set
        {
            if (value != ts)
            {
                Ts = value;
                if (Ts != null)
                {
                    ts.ListChanged += delegate(object sender, ListChangedEventArgs args)
                    {
                        OnListChanged(this);
                    };
                }
                NotifyPropertyChanged("Ts");
            }
        }
    }

    private static void OnListChanged(ObservableCollection<T> vm)
    {
        // this will fire on add, remove, and change
        // if want to prevent an insert this in not the right spot for that 
        // the OPs use of word prevent is not clear 
        // -1 don't be a hater
        vm.NotifyPropertyChanged("Ts");
    }

    public ObservableCollection()
    {
        ts.ListChanged += delegate(object sender, ListChangedEventArgs args)
        {
            OnListChanged(this);
        };
    }
}
8
ответ дан Valamas 21 August 2018 в 05:18
поделиться
  • 1
    Это правда, но это не касается того, как он должен делать свои мероприятия. – Dan 8 October 2012 в 16:51
  • 2
    Узнал что-то новое. Goodbye EventList, Hello ObservableCollection! – Martin 9 October 2012 в 10:06
Другие вопросы по тегам:

Похожие вопросы: