【问题标题】:C# - Dynamic properties and RaisePropertyChangedC# - 动态属性和 RaisePropertyChanged
【发布时间】:2011-08-30 01:40:50
【问题描述】:

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

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]

我不断收到以下错误:

因此,如果有任何更改,我可以在我的视图中相应地处理它。请不要给我解决单选按钮列表等的解决方案。

【问题讨论】:

  • ViewModelBase 定义在哪里?
  • ViewModelBase 扩展 GalaSoft.MvvMLight ViewModelBase。它实现了INotifyPropertyChangedRaisePropertyChanged 几乎只是打电话给if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs(property));
  • 嗯,那么错误来自哪里?你能发布完整的堆栈跟踪吗?
  • @KirkWoll 添加了错误的屏幕截图。我假设正在发生错误,因为我没有使用正确的参数调用 RaisePropertyChanged()。 RadioButton 绑定到 [radio1],我尝试使用它作为属性名称,但它也不起作用。

标签: c# binding dynamic-properties


【解决方案1】:

问题在于您正在实施索引器,而不是普通的属性。虽然绑定子系统支持索引器,但 MVVMLightINotifyPropertyChanged 不支持。

如果您想使用索引器,您需要:

  • 使用集合基类,例如ObservableCollection&lt;T&gt;
  • 实现 INotifiyCollectionChanged 并引发 that 事件

第一个选项不现实,因为您已经从 ViewModelBase 派生并且必须继续这样做。由于实现INotifiyCollectionChanged 需要一点工作,最简单的方法是:

  • RadioButtonSwitch 添加一个属性,该属性是一个可观察的布尔值集合 (ObservableCollection&lt;bool&gt;)

然后更改您的绑定以添加一个路径元素,然后您就完成了。

编辑:

根据您的评论和重新阅读您的问题,我认为实现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;
        }
    }
}

【讨论】:

  • 第二个选项听起来不错。但是我不知道如何绑定到 ObservableCollection 的特定行。你有例子吗?
  • 太好了,这正是我所追求的!
【解决方案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[]")

【讨论】:

  • 我不想从头开始实现所有东西,也不想改变其他地方使用的现有方法。
猜你喜欢
  • 2014-10-07
  • 2016-08-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-01-29
  • 1970-01-01
  • 1970-01-01
  • 2010-10-07
相关资源
最近更新 更多