更改选项卡时,RadioButton IsChecked属性会被覆盖

时间:2012-07-18 14:13:41

标签: wpf radio-button tabcontrol

我确定这种行为是已知的,但我无法谷歌。我有以下代码:

<Window x:Class="ContentControlListDataTemplateKacke.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <DockPanel>
        <TabControl ItemsSource="{Binding Items}">
            <TabControl.ContentTemplate>
                <DataTemplate>
                    <StackPanel>
                        <Label Content="{Binding Name}" />
                        <RadioButton Content="Option1" IsChecked="{Binding Option1}" />
                        <RadioButton Content="Option2" IsChecked="{Binding Option2}" />
                    </StackPanel>
                </DataTemplate>
            </TabControl.ContentTemplate>
        </TabControl>
    </DockPanel>
</Window>

代码隐藏很简单:

public partial class MainWindow
{
    public MainWindow()
    {
        InitializeComponent();
        DataContext = new ViewModel();
    }
}

ViewModel如下所示:

public class ViewModel : NotificationObject
{
    public ViewModel()
    {
        Items = new ObservableCollection<Item>
        {
            new Item {Name = "1", Option1 = true},
            new Item {Name = "2", Option2 = true}
        };
    }

    public ObservableCollection<Item> Items { get; set; }
}

这样的项目:

public class Item : NotificationObject
{
    public string Name { get; set; }

    private bool _option1;
    public bool Option1
    {
        get { return _option1; }
        set
        {
            _option1 = value;
            RaisePropertyChanged(() => Option1);
        }
    }

    private bool _option2;
    public bool Option2
    {
        get { return _option2; }
        set
        {
            _option2 = value;
            RaisePropertyChanged(() => Option2);
        }
    }
}

我正在使用Prism,因此RaisePropertyChanged会引发一个PropertyChanged事件。选择第二个选项卡,然后选择第一个选项卡,再选择第二个选项卡,然后取消选择第二个选项卡上的RadioButtons。

为什么?

除Rachels

之外的另一种解决方案

我的同事只是想将RadioButtons的GroupName属性绑定到每个项目的唯一字符串。只需将RadioButtons的声明更改为:

<RadioButton GroupName="{Binding Name}" Content="Option1" IsChecked="{Binding Option1}" />
<RadioButton GroupName="{Binding Name}" Content="Option2" IsChecked="{Binding Option2}" />

如果Name-property对所有项都是唯一的(就我的问题而言),它就有效。

2 个答案:

答案 0 :(得分:1)

WPF正在将所有RadioButton作为同一组的一部分阅读,而在单选按钮组中,一次只能选择一个项目。

加载顺序为:

  • 加载Tab1
  • 加载Tab1.Radio1。 IsChecked = True
  • 加载Tab1.Radio2。 IsChecked = True,因此设置Tab1.Radio2.IsChecked = False

  • 点击标签2

  • 加载Tab2
  • 加载Tab2.Radio1。 IsChecked = True,因此设置Tab1.Radio2.IsChecked = False
  • 加载Tab2.Radio2。 IsChecked = True,因此设置Tab2.Radio1.IsChecked = False

  • 到目前为止,Tab2.Radio2是唯一一个已检查,并且所有其他无线电已加载和未选中,因此其DataBound值已更新为false。

  • 点击标签1

  • 加载Tab1.Radio1。 IsChecked = False
  • 加载Tab1.Radio2。 IsChecked = False

如果单选按钮不相关且可以同时检查,我建议切换到CheckBoxes

如果要将它们分组并且一次只能选择一个项目,我建议切换为使用ListBox绘制的RadioButtons,并仅存储SelectedOptionViewModel

这是我通常使用的风格:

<Style x:Key="RadioButtonListBoxStyle" TargetType="{x:Type ListBox}">
    <Setter Property="BorderBrush" Value="Transparent"/>
    <Setter Property="KeyboardNavigation.DirectionalNavigation" Value="Cycle" />
    <Setter Property="ItemContainerStyle">
        <Setter.Value>
            <Style TargetType="{x:Type ListBoxItem}" >
                <Setter Property="Margin" Value="2, 2, 2, 0" />
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate>
                            <Border Background="Transparent">
                                <RadioButton
                                    Content="{TemplateBinding ContentPresenter.Content}" VerticalAlignment="Center"
                                    IsChecked="{Binding Path=IsSelected,RelativeSource={RelativeSource TemplatedParent},Mode=TwoWay}"/>

                            </Border>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Style>
        </Setter.Value>
    </Setter>
</Style>

它的使用方式如下:

<ListBox ItemsSource="{Binding Options}"
         SelectedValue="{Binding SelectedValue}"
         Style="{StaticResource RadioButtonListBoxStyle}" />

答案 1 :(得分:0)

我曾经遇到过与此问题非常类似的问题,当我在视图之间切换时,文本被清除了。如果我没记错的话,以下解决方案是有效的。

  • OneWay绑定到属性,并使用属性标记这些绑定属性。
  • 每次加载视图(以及视图模型)时,请使用上述属性的反射来查找绑定属性。
  • 为每个属性触发PropertyChanged事件以正确更新视图。

我认为这是由于视图加载默认设置而不是在加载时查询属性,因为没有任何事情引发PropertyChanged事件。

此外,它不是您的问题的一部分,但您可以直接在XAML中设置数据上下文(通过Window中的DataContext属性),以便Visual Studio不必具有显式的代码隐藏文件。