MVVM单选按钮

41

有人可以帮忙吗?我遇到了一个有趣的问题。我正在尝试实现一个MVVM应用程序,并且想要在我的视图中绑定单选按钮。

这是我的视图:

<StackPanel Orientation="Horizontal" Grid.ColumnSpan="2"  >
    <RadioButton GroupName="1" IsChecked="{Binding Path=NoteGeneral, Mode=TwoWay}">General</RadioButton>
    <RadioButton GroupName="1" IsChecked="{Binding Path=NoteContact, Mode=TwoWay}" >Contact</RadioButton>
    <RadioButton GroupName="1" IsChecked="{Binding Path=NoteAddress, Mode=TwoWay}" >Address</RadioButton>
    <RadioButton GroupName="1" IsChecked="{Binding Path=NotePhone, Mode=TwoWay}" >Phone</RadioButton>
</StackPanel>

这是我的 ViewModel:

    bool _NoteGeneral;
    public bool NoteGeneral
    {
        get { return _NoteGeneral; }
        set
        {
            _NoteGeneral = value;
            OnPropertyChanged("NoteGeneral");
        }
    }

    bool _NoteContact;
    public bool NoteContact
    {
        get { return _NoteContact; }
        set
        {
            _NoteContact = value;
            OnPropertyChanged("NoteContact");
        }
    }

    bool _NoteAddress;
    public bool NoteAddress
    {
        get { return _NoteAddress; }
        set
        {
            _NoteAddress = value;
            OnPropertyChanged("NoteAddress");
        }
    }

    bool _NotePhone;
    public bool NotePhone
    {
        get { return _NotePhone; }
        set
        {
            _NotePhone = value;
            OnPropertyChanged("NotePhone");
        }
    }
问题在于,当我点击不同的单选按钮时,属性设置器只会在第一次调用(在我通过调试运行时)。例如,当我点击NoteGeneral、NoteContact,然后再次点击NoteGeneral时,只有前两次点击会更新我的视图模型。我认为我可能在绑定方面出了问题,或者我完全错误地处理了这个问题。
有人能帮忙吗?
我应该如何在我的视图模型中实现单选按钮选择?
.NET 4及更高版本
在.NET 4发布时,Microsoft解决了RadioButton绑定的问题。现在单选按钮的绑定可以像你期望的那样工作,无需使用下面列出的任何解决方法。
4个回答

18

点击这里查看。

我还没有实现提供的解决方案,但它很有道理。当进行单击操作时,底层框架控件会中断您的绑定。解决方案是覆盖执行此操作的方法并仅依赖于绑定。


1
请参考https://dev59.com/iXE95IYBdhLWcg3wf-AF,了解其他解决方案,特别是涉及列表框的相当简单的解决方案。 - David Veeneman
2
链接已经失效,因此您不应该将链接作为答案发布。 - Boendal

16

Jaime Rodriguez 在微软WPF团队工作,发布了一篇详尽的WPF问答,在最新的问题中讨论了RadioButtons和MVVM!

这篇文章可以在http://blogs.msdn.com/jaimer/archive/2009/09/22/wpf-discussion-090922.aspx 找到,您需要查看该文章中的最后一项。我测试了这个解决方案,并对其满意。

以下是该文章的引用:

我已经在.NET 3.5 SP1中解决了这个问题。以下是如何将一组单选按钮数据绑定到一个枚举值属性的方法:

<StackPanel>
    <RadioButton Content="New folder"
        IsChecked="{Binding Path=PublishTarget,
                    Converter={StaticResource equalityConverter},
                    ConverterParameter={x:Static local:PublishTarget.NewServerFolder}, Mode=TwoWay}"
        GroupName="1" />

    <RadioButton Content="Existing folder"
        IsChecked="{Binding Path=PublishTarget,
                    Converter={StaticResource equalityConverter},
                    ConverterParameter={x:Static local:PublishTarget.ExistingServerFolder},
                    Mode=TwoWay}"
        GroupName="2" />

    <RadioButton Content="Local folder"
        IsChecked="{Binding Path=PublishTarget,
                    Converter={StaticResource equalityConverter},
                    ConverterParameter={x:Static local:PublishTarget.LocalFolder},
                    Mode=TwoWay}"
        GroupName="3" />
</StackPanel>
设置每个单选按钮的 GroupName 为唯一值,可以防止用户点击单选按钮时绑定被覆盖。在这里,我依赖于数据源实现 INotifyPropertyChanged,这将告诉其他单选按钮进行更新。对于 ItemsControl 中的单选按钮,类似的方法也应该有效。

8

我在我的博客上为这个问题写了一个简单的技巧

在这种情况下,您应该将View和ViewModel编写如下:

<StackPanel Orientation="Horizontal" Grid.ColumnSpan="2">
    <RadioButton IsChecked="{Binding IsGeneralNote}">General</RadioButton>
    <RadioButton IsChecked="{Binding IsContactNote}">Contact</RadioButton>
    <RadioButton IsChecked="{Binding IsAddressNote}">Address</RadioButton>
    <RadioButton IsChecked="{Binding IsPhoneNote}">Phone</RadioButton>
</StackPanel>


public enum Note
{
    General,
    Contact,
    Address,
    Phone,
}

...

    Note note = Note.General;

    public Note Note
    {
        get { return this.note; }
        set
        {
            if (this.note == value)
                return;

            this.note = value;
            OnPropertyChanged("Note");
            OnPropertyChanged("IsGeneralNote");
            OnPropertyChanged("IsContactNote");
            OnPropertyChanged("IsAddressNote");
            OnPropertyChanged("IsPhoneNote");
        }
    }

    public bool IsGeneralNote
    {
        get { return Note == Note.General; }
        set { Note = value ? Note.General : Note; }
    }

    public bool IsContactNote
    {
        get { return Note == Note.Contact; }
        set { Note = value ? Note.Contact : Note; }
    }

    public bool IsAddressNote
    {
        get { return Note == Note.Address; }
        set { Note = value ? Note.Address : Note; }
    }

    public bool IsPhoneNote
    {
        get { return Note == Note.Phone; }
        set { Note = value ? Note.Phone : Note; }
    }
...

2
这个解决方案没有解决RadioButton绑定在按钮被选中时被覆盖的问题,是吗? - David Veeneman

2
您需要在XAML绑定中设置UpdateSourceTrigger="PropertyChanged",例如:

<StackPanel Grid.Column="1" Grid.Row="0" Orientation="Horizontal" HorizontalAlignment="Left" VerticalAlignment="Center">
    <RadioButton Name="rdbTimeFormat12" GroupName="TimeFormat" Content="12 Hrs" IsChecked="{Binding Radio1IsCheck,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"/>
    <RadioButton Name="rdbTimeFormat24" GroupName="TimeFormat" Margin="40,0,0,0" Content="24 Hrs" IsChecked="{Binding Radio2IsCheck,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"/>
</StackPanel>

只是一点小提醒,尽管问题已经被修复,但代码仍然需要这个建议的修复。我正在使用.NET 6,直到我实施了Vijay的修复方法,绑定才能正常工作。 - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接