2

ラジオボタンのバインディングに使用する次のクラスがあります

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
  • [a]

次のエラーが発生し続けます:

エラー

これは、何らかの変更があった場合に、それに応じて私の見解でそれを処理できるようにするためです。ラジオボタンなどのリストの解決策を教えてください。

4

2 に答える 2

2

問題は、通常のプロパティではなく、インデクサーを実装していることです。バインディング サブシステムはインデクサーをサポートしていますが、MVVMLightはサポートしていません。INotifyPropertyChanged

インデクサーを使用する場合は、次のことを行う必要があります。

  • 次のようなコレクション基本クラスを使用しますObservableCollection<T>
  • 代わりにそのイベントを実装INotifiyCollectionChangedして発生させます

最初のオプションは現実的ではありません。なぜなら、あなたはすでに派生しViewModelBaseており、それを続けなければならないからです。実装INotifiyCollectionChangedは少し手間がかかるため、最も簡単な方法は次のとおりです。

  • RadioButtonSwitchブール値の監視可能なコレクションであるプロパティを追加します ( ObservableCollection<bool>)

次に、バインディングを変更してもう 1 つのパス要素を追加すると、完了です。

編集:

INotifyCollectionChangedあなたのコメントとあなたの質問を読み直すことに基づいて、実装が最も簡単だと思います。これは、実際にはMVVMLightRadioButtonSwitch基本クラスから派生する必要がなくなったクラスの書き直しですが、必要に応じて派生させることもできます。

注意深い読者は、コレクションのいずれかの要素が変更されると、大ハンマーを使用してコレクション全体を「リセット」することに気付くでしょう。これは単なる怠惰ではありません。これは、インデクサーが整数インデックスではなく文字列インデックス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;
        }
    }
}
于 2011-05-21T03:30:33.353 に答える
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[]")

于 2011-05-21T03:40:00.563 に答える