从ViewModel设置时,布尔到整数转换器问题

时间:2017-04-06 15:14:29

标签: c# wpf mvvm

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

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;
    }
}

我在stackpanel中有两个单选按钮绑定到属性“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中设置绑定radiobuttons的属性的值时,会出现问题。

当我将值从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;

2 个答案:

答案 0 :(得分:1)

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

转换器用于将绑定值转换为其他类型。那么当转换器从UI中读取属性时,转换器所说的是

  

&#34;将约束值(TestTypeRef)与给定的参数进行比较。如果相同,请检查单选按钮&#34;

它还说在进行反向转换时(将IsChecked值写回绑定值(TestTypeRef),只需

  

&#34;发回参数值&#34;

所以做逻辑......

当UI绑定值以读取IsChecked属性

If TestTypeRef is equal to 0

    Radio 0 is checked because the value equals the parameter (0)
    Radio 1  is unchecked because the value does not equal the parameter (1)

If TestTypeRef is equal to 1

    Radio 0 is unchecked because the value does not equals the parameter (0)
    Radio 1  is checked because the value equals the parameter (1)

现在,当它将值写回数据源

时,反向绑定会出现问题
If Radio 0 is checked, write 0 to the datasource
If Radio 0 is unchecked, write 0 to the datasource
If Radio 1 is checked, write 1 to the datasource
If Radio 1 is unchecked, write 1 to the datasource

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

Default : TestTypeRef = 0
    Radio 0 is checked
    Radio 1 is unchecked

Set TestTypeRef = 1
    Update Radio 0 Binding (Checked > Unchecked)
    Update Radio 1 Binding (Unchecked > Checked)

Because the IsChecked updates, it uses ConvertBack to update the data source. 
    If Radio 1 is checked, write 1 to the datasource

请注意,此时,Radio0绑定的更改事件不会运行,可能是因为它现在看到没有任何更改 - 引发了更改事件,但值从1变为1,因此它不会#39 ; t运行代码来更新任何内容。

您可以通过在ConvertBack方法中添加断点来确认这一点,并且您会注意到它的值为&#34; 1&#34;当您尝试将值设置为0. TestTypeRef的设置器中的另一个断点也将显示它首先将值更改为0,然后再将其更改为1.

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

据我所知,你试图说&#34;如果绑定值等于某个值,则isChecked为真&#34;,但是从该语句中你无法准确地反过来。如果用户检查单选按钮,那么设置绑定值等于参数。如果用户取消选中单选按钮,则不知道将绑定值设置为。

所以要么

  1. 将绑定更改为OneWay,以便它们永远不会运行ConvertBack并更新数据源。如果您希望用户实际使用单选按钮,则不理想。
  2. 更改您的绑定值,使其以正确的方式格式化 显示数据,例如两个名为IsFull和的bool属性 IsScreening你可以直接绑定
  3. 实施更好的一套 UI控件。我的个人偏好是ListBox bound to a single value and styled with RadioButtons,但对于本质上是bool的价值而言可能有点过分。
  4. 就个人而言,我现在会为你提出建议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; }
    }
    

答案 1 :(得分:0)

我们需要使用converter参数来指定单选按钮对应的值。如果您的属性等于此值,则将选中此按钮并取消选中其他按钮。无论您是否设置了GroupName属性,此解决方案都可以使用,但您通常应该设置它。

you can see the solution