【问题标题】:Boolean to Integer converter issue when set from ViewModel从 ViewModel 设置时的布尔到整数转换器问题
【发布时间】:2025-11-29 11:45:01
【问题描述】:

我有一个单选按钮布尔到整数转换器类:

public class RadioBoolToIntConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter,
                          CultureInfo culture)
    {
        int integer = (int)value;
        if (integer == int.Parse(parameter.ToString()))
            return true;
        else
            return false;
    }

    public object ConvertBack(object value, Type targetType, object parameter, 
                              CultureInfo culture)
    {            
        return parameter;
    }
}

我在绑定到属性“TestTypeRef”的堆栈面板中有两个单选按钮:

<StackPanel Orientation="Horizontal">
    <RadioButton 
        Content="Screening" 
        Margin="0 0 10 0" 
        IsChecked="{Binding Path=TestTypeRef, Mode=TwoWay, Converter={StaticResource RadioBoolToIntConverter}, ConverterParameter=0 }" />
    <RadioButton 
        Content="Full" 
        Margin="0 0 10 0" 
        IsChecked="{Binding Path=TestTypeRef, Mode=TwoWay, Converter={StaticResource RadioBoolToIntConverter}, ConverterParameter=1 }" />
</StackPanel>

当我尝试在关联的 ViewModel 中设置单选按钮绑定到的属性的值时,就会出现问题。

当我将值从 0 设置为 1 时 - 这很好。

当我将值从 1 设置为 0 - 属性值保持为 1:

ViewModel 内部:

// Set the default test type.
TestTypeRef = 0;
// ~~> TestTypeRef = 0
TestTypeRef = 1;  
// ~~> TestTypeRef = 1          
TestTypeRef = 0;
// ~~> TestTypeRef = 1 i.e. no change.

非常感谢您提供的任何帮助。

更新: 感谢@Rachel 和@Will 的反馈。 ConvertBack 例程出错。这修复了它:

    return value.Equals(false) ? DependencyProperty.UnsetValue : parameter;

【问题讨论】:

  • 在转换器的ConvertBack 方法中始终返回ConverterParameter 的值,因此它始终为0 或1,具体取决于您在UI 中设置的值。这似乎是错误的,并且闻起来像是与您正在观察的事物有关。您应该正确实现 ConvertBack 方法,或者在您往返 UI 时查看其中发生了什么。
  • 嗨@Will。是的 - ConvertBack 方法中的错误。感谢您的评论。

标签: c# wpf mvvm


【解决方案1】:

我认为您可能错误地使用了转换器,但我不确定我是否理解您的原始前提。

转换器用于将绑定值转换为不同的类型。因此,您的转换器在从 UI 中读取 IsChecked 的属性时所说的是

“将绑定值(TestTypeRef)与给定的参数进行比较。如果相同,请检查单选按钮”

也就是说在做反向转换的时候(把IsChecked值写回绑定值(TestTypeRef),就

"发回参数值"

所以要按逻辑...

当 UI 绑定值以读取 IsChecked 属性时

如果 TestTypeRef 等于 0 选中 Radio 0,因为该值等于参数 (0) 单选 1 未选中,因为该值不等于参数 (1) 如果 TestTypeRef 等于 1 单选 0 未选中,因为值不等于参数 (0) 选中 Radio 1,因为该值等于参数 (1)

现在问题出现在您的反向绑定上,当它将一个值写回数据源时

如果选中 Radio 0,则将 0 写入数据源 如果 Radio 0 未选中,则将 0 写入数据源 如果选中 Radio 1,则将 1 写入数据源 如果 Radio 1 未选中,则将 1 写入数据源

当您将数据源值设置为某个值时,它会触发对 IsChecked 值的更新,该值又会写回数据源

默认值:TestTypeRef = 0 无线电 0 已检查 收音机 1 未选中 设置 TestTypeRef = 1 更新 Radio 0 绑定(选中 > 未选中) 更新 Radio 1 绑定(未选中 > 选中) 因为 IsChecked 更新,所以它使用 ConvertBack 来更新数据源。 如果选中 Radio 1,则将 1 写入数据源

请注意,此时 Radio0 绑定的更改事件没有运行,可能是因为它现在看到没有任何更改 - 引发了更改事件,但值从 1 变为 1,因此它没有运行代码更新任何东西。

您可以通过在您的 ConvertBack 方法中放置一个断点来确认这一点,当您尝试将值设置为 0 时,您会注意到它的值为“1”。TestTypeRef 的设置器中的另一个断点还会显示它首先将值更改为 0,然后再次变回 1。

长话短说,修理你的转换器。或者更好的是,修复您的设计。

据我所知,您试图说“如果绑定值等于某个值,则 isChecked 为真”,但从该语句中您无法准确地得到相反的结果。如果用户选中单选按钮,那么您将绑定值设置为等于参数。如果用户取消选中单选按钮,它不知道将绑定值设置为什么。

所以要么

  1. 将绑定更改为 OneWay,这样它们就不会运行 ConvertBack 并更新数据源。如果您希望用户实际使用单选按钮,则不理想。
  2. 更改绑定值,使其格式正确 显示数据,例如两个布尔属性 IsFull 和 可以直接绑定的IsScreening
  3. 实施一套更好的 用于此的 UI 控件。我个人的偏好是ListBox bound to a single value and styled with RadioButtons,但这对于本质上是一个布尔值来说可能有点过分了。

我个人现在会为你推荐 2 个。

public bool IsScreening
{ 
    get { return TestTypeRef == 0; }
    set { if (value) TestTypeRef = 0; }
}

public bool IsFull
{ 
    get { return TestTypeRef == 1; }
    set { if (value) TestTypeRef = 1; }
}

【讨论】:

  • 感谢@Rachel 的精彩演练。 ConvertBack 例程出错。这修复了它: return value.Equals(false) ? DependencyProperty.UnsetValue : 参数;
【解决方案2】:

我们需要使用转换器参数来指定单选按钮对应的值。如果您的属性等于该值,则该按钮将被选中,而其他按钮则不被选中。无论您是否设置 GroupName 属性,此解决方案都有效,尽管您通常应该设置它。

you can see the solution

【讨论】: