C# - динамические свойства и RaisePropertyChanged
У меня есть следующий класс, который я использую для привязки переключателя
public class RadioButtonSwitch : ViewModelBase
{
IDictionary<string, bool> _options;
public RadioButtonSwitch(IDictionary<string, bool> options)
{
this._options = options;
}
public bool this[string a]
{
get
{
return _options[a];
}
set
{
if (value)
{
var other = _options.Where(p => p.Key != a).Select(p => p.Key).ToArray();
foreach (string key in other)
_options[key] = false;
_options[a] = true;
RaisePropertyChanged("XXXX");
else
_options[a] = false;
}
}
}
XAML
<RadioButton Content="Day" IsChecked="{Binding RadioSwitch[radio1], Mode=TwoWay}" GroupName="Monthly" HorizontalAlignment="Left" VerticalAlignment="Center" />
ViewModel
RadioSwitch = new RadioButtonSwitch(
new Dictionary<string, bool> {{"radio1", true},{"radio2", false}}
);
У меня проблема с RaisePropertyChanged() в моем классе. Я не уверен, какую ценность я должен поставить, чтобы вызвать изменение.
Я попытался положить:
- Вещь[]
- [А]
Я продолжаю получать следующую ошибку:
Это так в случае каких-либо изменений, я могу справиться с этим, на мой взгляд, соответственно. Пожалуйста, не дайте мне решения для списка для переключателей и т. Д.
2 ответа
Проблема в том, что вы используете индексатор, а не обычное свойство. Хотя подсистема привязки поддерживает индексаторы, MVVMLight и INotifyPropertyChanged
не делайте.
Если вы хотите использовать индексатор, вам необходимо:
- Используйте базовый класс коллекции, такой как
ObservableCollection<T>
- Воплощать в жизнь
INotifiyCollectionChanged
и поднять это событие вместо
Первый вариант нереалистичен, потому что вы уже производите от ViewModelBase
и должен продолжать делать это. С момента внедрения INotifiyCollectionChanged
Это немного работы, самый простой подход заключается в:
- добавить свойство к
RadioButtonSwitch
это наблюдаемая коллекция булевых значений (ObservableCollection<bool>
)
Затем измените привязку, чтобы добавить еще один элемент пути, и все готово.
Редактировать:
Основываясь на вашем комментарии и перечитывая ваш вопрос, я думаю, что реализация INotifyCollectionChanged
самый простой. Вот переписать ваш RadioButtonSwitch
класс, который на самом деле больше не должен быть производным от базового класса MVVMLight, хотя вы все равно можете, если хотите.
Внимательный читатель заметит, что мы используем кувалду и "сбрасываем" всю коллекцию при изменении любого элемента коллекции. Это не просто лень; это потому, что индексатор использует строковый индекс вместо целочисленного индекса и INotifyCollectionChanged
не поддерживает это. В результате, когда что-то меняется, мы просто поднимаем руки и говорим, что вся коллекция изменилась.
public class RadioButtonSwitch : INotifyCollectionChanged
{
public event NotifyCollectionChangedEventHandler CollectionChanged;
protected void RaiseCollectionChanged()
{
if (CollectionChanged != null)
CollectionChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
}
IDictionary<string, bool> _options;
public RadioButtonSwitch(IDictionary<string, bool> options)
{
this._options = options;
}
public bool this[string a]
{
get
{
return _options[a];
}
set
{
if (value)
{
var other = _options.Where(p => p.Key != a).Select(p => p.Key).ToArray();
foreach (string key in other)
_options[key] = false;
_options[a] = true;
RaiseCollectionChanged();
}
else
_options[a] = false;
}
}
}
GalaSoft.MvvmLight имеет следующий код для проверки имени свойства перед поднятием PropertyChanged
событие.
public void VerifyPropertyName(string propertyName)
{
if (GetType().GetProperty(propertyName) == null)
throw new ArgumentException("Property not found", propertyName);
}
GetType().GetProperty("Item[]")
очевидно возвращает ноль.
Вот почему это терпит неудачу.
Я думаю, что самый быстрый обходной путь для вас будет не использовать ViewModelBase
из этой библиотеки, но реализуйте свою собственную версию, которая не выполняет эту проверку:
public class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void RaisePropertyChanged(string propertyName)
{
var handler = PropertyChanged;
if (handler != null)
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
Если вы реализуете этот класс, вы сможете запустить RaisePropertyChanged("Item[]")
,