C# - Dynamic properties and RaisePropertyChanged
I have following class which I use for radio button binding
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)
{
开发者_Go百科 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}}
);
I'm having problem with RaisePropertyChanged() in my Class. I'm not sure what value I should be putting in order to raise the change.
I tried putting:
- Item[]
- a
- [a]
I keep getting following error:
This is so in case of any change I can handle it in my view accordingly. Please do not give me solutions for List for radio buttons etc.
The problem is that you are implementing an indexer, not an ordinary property. Although the binding subsystem supports indexers, MVVMLight and INotifyPropertyChanged
do not.
If you want to use an indexer you need to:
- Use a collection base class such as
ObservableCollection<T>
- Implement
INotifiyCollectionChanged
and raise that event instead
The first option isn't realistic because you are already deriving from ViewModelBase
and have to continue to do that. Since implementing INotifiyCollectionChanged
is a little bit of work, the easiest approach is to:
- add a property to
RadioButtonSwitch
that is an observable collection of boolean values (ObservableCollection<bool>
)
Then change you binding to add one more path element and you are done.
Edit:
Based on your comment and rereading your question, I think implementing INotifyCollectionChanged
is the easiest. Here is the rewrite of your RadioButtonSwitch
class which actually no longer needs to derive from the MVVMLight base class, although you still could if you wanted to.
The careful reader will notice that we use a sledgehammer and "reset" the whole collection when any element of the collection is modified. This is not just laziness; it is because the indexer uses a string index instead of an integer index and INotifyCollectionChanged
doesn't support that. As a result, when anything changes we just throw up our hands and say the whole collection has changed.
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 has the following code to check property name before raising PropertyChanged
event.
public void VerifyPropertyName(string propertyName)
{
if (GetType().GetProperty(propertyName) == null)
throw new ArgumentException("Property not found", propertyName);
}
GetType().GetProperty("Item[]")
obviously returns null.
This is why it is failing.
I think, the quickest workaround for you would be not to use ViewModelBase
from this library, but implement your own version, that doesn't do this check:
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));
}
}
If you implement this class you will be able to run RaisePropertyChanged("Item[]")
.
精彩评论