Как я могу симулировать эффекты наблюдаемой коллекции в этой ситуации? - PullRequest
2 голосов
/ 16 апреля 2010

Я делаю редактор конфигурации для другого приложения и использую отражение для извлечения редактируемых полей из класса конфигурации. Следующий класс является базовым классом для моих различных DataTypeViewModels и показывает, как я получаю и устанавливаю соответствующие свойства.

public abstract class DataTypeViewModel<T> : ViewModelBase
{
    Func<T> getFunction;

    Action<T> setAction;

    public const string ValuePropertyName = "Value";

    public string Label { get; set; }

    public T Value
    {
        get
        {
            return getFunction.Invoke();
        }

        set
        {
            if (getFunction.Invoke().Equals(value))
            {
                return;
            }

            setAction.Invoke(value);

            // Update bindings, no broadcast
            RaisePropertyChanged(ValuePropertyName);
        }
    }

     /// <summary>
    /// Initializes a new instance of the StringViewModel class.
    /// </summary>
    public DataTypeViewModel(string sectionName, string label)
    {
        if (IsInDesignMode)
        {
            // Code runs in Blend --> create design time data.
        }
        else
        {
            Label = label;

            getFunction = new Func<T>(() =>
                {
                    return (T)Settings.Instance.GetType().GetProperty(sectionName).PropertyType.
                        GetProperty(label).GetValue(Settings.Instance.GetType().GetProperty(sectionName).GetValue(Settings.Instance, null), null);
                });

            setAction = new Action<T>(value =>
                {
                    Settings.Instance.GetType().GetProperty(sectionName).PropertyType.GetProperty(label).
                        SetValue(Settings.Instance.GetType().GetProperty(sectionName).GetValue(Settings.Instance, null), value, null);
                });
        }
    }
}

Эта часть работает так, как я хочу, следующая часть представляет собой образец DataTypeViewModel в списке строк.

public class StringListViewModel : DataTypeViewModel<ICollection<string>>
{
    /// <summary>
    /// The <see cref="RemoveItemCommand" /> property's name.
    /// </summary>
    public const string RemoveItemCommandPropertyName = "RemoveItemCommand";

    private RelayCommand<string> _removeItemCommand = null;

    public ObservableCollection<string> ObservableValue { get; set; }

    /// <summary>
    /// Gets the RemoveItemCommand property.
    /// TODO Update documentation:
    /// Changes to that property's value raise the PropertyChanged event. 
    /// This property's value is broadcasted by the Messenger's default instance when it changes.
    /// </summary>
    public RelayCommand<string> RemoveItemCommand
    {
        get
        {
            return _removeItemCommand;
        }

        set
        {
            if (_removeItemCommand == value)
            {
                return;
            }

            var oldValue = _removeItemCommand;
            _removeItemCommand = value;

            // Update bindings, no broadcast
            RaisePropertyChanged(RemoveItemCommandPropertyName);
        }
    }

    /// <summary>
    /// The <see cref="AddItemCommand" /> property's name.
    /// </summary>
    public const string AddItemCommandPropertyName = "AddItemCommand";

    private RelayCommand<string> _addItemCommand = null;

    /// <summary>
    /// Gets the AddItemCommand property.
    /// TODO Update documentation:
    /// Changes to that property's value raise the PropertyChanged event. 
    /// This property's value is broadcasted by the Messenger's default instance when it changes.
    /// </summary>
    public RelayCommand<string> AddItemCommand
    {
        get
        {
            return _addItemCommand;
        }

        set
        {
            if (_addItemCommand == value)
            {
                return;
            }

            var oldValue = _addItemCommand;
            _addItemCommand = value;

            // Update bindings, no broadcast

            RaisePropertyChanged(AddItemCommandPropertyName);
        }
    }

    /// <summary>
    /// Initializes a new instance of the StringListViewModel class.
    /// </summary>
    public StringListViewModel(string sectionName, string label) : base(sectionName, label)
    {
        ObservableValue = new ObservableCollection<string>(Value);
        AddItemCommand = new RelayCommand<string>(param =>
            {
                if (param != string.Empty)
                {
                    Value.Add(param);
                    ObservableValue.Add(param);
                }
            });

        RemoveItemCommand = new RelayCommand<string>(param =>
            {
                if (param != null)
                {
                    Value.Remove(param);
                    ObservableValue.Remove(param);
                }
            });
    }
}

Как вы можете видеть в конструкторе, у меня в настоящее время есть «Значение», отраженное в новую коллекцию ObservableCollection под названием «ObservableValue», которая затем связывается с ListView в XAML. Это хорошо работает, но клонирование списка кажется таким хакерским способом сделать это. Несмотря на привязку к значению, я попытался добавить:

RaisePropertyChanged("Value");

для AddItemCommand и RemoveItemCommand, но это не работает, ListView не будет обновляться. Как правильно это сделать?

1 Ответ

2 голосов
/ 16 апреля 2010

Реализация INotifyCollectionChanged это похоже на NotifyPropertyChanged, но используется ObservableCollection для уведомления о вставках / удалениях / сбросах ...

  public class MyCustomCollection : INotifyCollectionChanged
    {
        public event NotifyCollectionChangedEventHandler CollectionChanged;

        protected virtual void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
        {
            if (CollectionChanged != null)
            {
                CollectionChanged(this, e);
            }
        }

        public void Add(Object o)
        {
            OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, o));
        }

        public void Remove(Object o)
        {
            OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, 0));
        }

        public void Clear()
        {
            OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
        }

        public void Move(Object o, Int32 newIndex)
        {
            Int32 oldIndex = 0; // can get the old index position using collection.IndexOf(o);
            OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Move,
                o, newIndex, oldIndex));
        }

        public Object this[Int32 index]
        {
            get
            {
                return null; // return collection[index];
            }
            set
            {
                Object oldValue = null;  // get old value using collection[index];
                OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace,
                    value, oldValue));
            }
        }
    }

... я скопировал это из здесь

...