C# - 动态属性和RaisePropertyChanged

时间:2011-05-21 02:27:51

标签: c# binding dynamic-properties

我有以下用于单选按钮绑定的课程

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" />

视图模型

RadioSwitch = new RadioButtonSwitch(
                new Dictionary<string, bool> {{"radio1", true},{"radio2", false}}
                );

我的班级中遇到RaisePropertyChanged()问题。我不确定我应该采取什么价值来提高变化。

我尝试过:

  • 项[]
  • 一个
  • 并[a]

我一直收到以下错误:

Error

如果发生任何变化,我可以在相应的视图中处理。请不要给我列表的单选按钮等解决方案。

2 个答案:

答案 0 :(得分: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;
        }
    }
}

答案 1 :(得分:2)

GalaSoft.MvvmLight在提升PropertyChanged事件之前有以下代码来检查属性名称。

public void VerifyPropertyName(string propertyName)
{
    if (GetType().GetProperty(propertyName) == null)
        throw new ArgumentException("Property not found", propertyName);
}

GetType().GetProperty("Item[]")显然会返回null 这就是它失败的原因。

我认为,对您而言最快的解决方法是不使用此库中的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[]")