【问题标题】:RadioButton IsChecked property gets overridden when changing tabs更改选项卡时,RadioButton IsChecked 属性被覆盖
【发布时间】:2012-07-17 14:35:27
【问题描述】:

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

<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 对于所有项目都是唯一的(我的问题就是这种情况),那么它就可以工作。

【问题讨论】:

    标签: wpf radio-button tabcontrol


    【解决方案1】:

    WPF 正在读取同一组中的所有单选按钮,并且在单选按钮组中一次只能选择一项。

    加载顺序如下:

    • 加载 Tab1
    • 加载 Tab1.Radio1。 IsChecked = 真
    • 加载 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 是唯一选中的,其他所有 Radio 都已加载且未选中,因此它们的 DataBound 值已更新为 false。

    • 单击选项卡 1

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

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

    如果它们要被分组并且一次只能选择一个项目,我建议切换到使用RadioButtons 绘制的ListBox,并且只将SelectedOption 存储在您的ViewModel

    这是我通常使用的样式:

    <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}" />
    

    【讨论】:

      【解决方案2】:

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

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

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

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-06-16
        • 2019-12-16
        • 2014-10-14
        • 1970-01-01
        • 2013-01-19
        • 2020-06-22
        • 2014-02-25
        相关资源
        最近更新 更多