C# - 动态属性和 RaisePropertyChanged

发布于 2024-11-09 04:13:28 字数 1544 浏览 0 评论 0原文

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

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() 问题。我不确定应该输入什么值才能进行更改。

我尝试输入:

  • Item[]
  • a
  • [a]

我不断收到以下错误:

Error

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

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)
                {
                    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:

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

拒绝两难 2024-11-16 04:13:28

问题在于您正在实现一个索引器,而不是一个普通的属性。尽管绑定子系统支持索引器,但 MVVMLightINotifyPropertyChanged 不支持。

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

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

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

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

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

编辑:

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

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;
        }
    }
}
满栀 2024-11-16 04:13:28

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[]")

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[]").

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文