将两个复选框绑定到MVVM中的可空bool属性

时间:2015-04-15 09:27:32

标签: c# wpf mvvm

我尝试将两个复选框连接到我的ViewModel。他们的行为就像一个radiobutton(独家)和TheeState。所以都没有检查或其中一个检查

目前我正在做这样的工作:

                            <dxlc:LayoutGroup>
                                <dxlc:LayoutItem Label="with errors">
                                    <CheckBox IsChecked="{Binding OnlyMusicWithErrorsChecked}"></CheckBox>
                                </dxlc:LayoutItem>
                                <dxlc:LayoutItem Label="without errors">
                                    <CheckBox IsChecked="{Binding OnlyMusicWithoutErrorsChecked}"></CheckBox>
                                </dxlc:LayoutItem>
                            </dxlc:LayoutGroup>

和ViewModel:

    private bool _onlyMusicWithErrorsChecked;

    public bool OnlyMusicWithErrorsChecked
    {
        get { return _onlyMusicWithErrorsChecked; }
        set
        {
            SetProperty(ref _onlyMusicWithErrorsChecked, value, () => OnlyMusicWithErrorsChecked);
            if (OnlyMusicWithErrorsChecked)
                OnlyMusicWithoutErrorsChecked = false;
            RaisePropertyChanged("AdditionalCriteriaHeader");
            if (!_filteringData) 
                SelectData();
        }
    }

    private bool _onlyMusicWithoutErrorsChecked;

    public bool OnlyMusicWithoutErrorsChecked
    {
        get { return _onlyMusicWithoutErrorsChecked; }
        set
        {
            SetProperty(ref _onlyMusicWithoutErrorsChecked, value, () => OnlyMusicWithoutErrorsChecked);
            if (OnlyMusicWithoutErrorsChecked)
                OnlyMusicWithErrorsChecked = false;
            RaisePropertyChanged("AdditionalCriteriaHeader");
            if (!_filteringData) 
                SelectData();
        }
    }

问题是:我可以只使用一个属性可空的bool来完成这项工作吗?

3 个答案:

答案 0 :(得分:3)

您可以将两个CheckBox绑定到同一个属性OnlyMusicWithErrorsChecked,并在第二个CheckBox中添加一个反转属性值的转换器:

<CheckBox IsChecked="{Binding OnlyMusicWithErrorsChecked, Converter={StaticResource Inverter}}"></CheckBox>

这个转换器看起来有点像:

public class Inverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        if (value is bool)
            return !((bool)value);
        else // Fallback
            return false;
    }
}

编辑:如果你想构建一个只有一个可绑定属性的三态解决方案,你需要两个转换器(或者一个可以参数化的转换器):

public class MyConverter : DependencyObject, IValueConverter
{
    public static readonly DependencyProperty InvertProperty = DependencyProperty.Register(
        "Invert", typeof (bool), typeof (MyConverter), new PropertyMetadata(default(bool)));

    public bool Invert
    {
        get { return (bool) GetValue(InvertProperty); }
        set { SetValue(InvertProperty, value); }
    }

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        var val = (bool?) value;
        switch (val)
        {
            case true:
                return Invert;
                break;
            case false:
                return !Invert;
                break;
            case null:
                return false; // None of the checkboxes shall be active
                break;
        }
        // Fallback
        return false;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        var val = (bool)value;
        switch (val)
        {
            case true:
                return Invert;
                break;
            case false:
                return null;
                break;
        }
        // Fallback
        return false;
    }
}

第一个复选框的Invert属性设置为false,第二个复选框设置为true

<Window.Resources>
    <local:MyConverter x:Key="Converter" Invert="False"/>
    <local:MyConverter x:Key="Inverter" Invert="True"/>
</Window.Resources>

现在,您可以使用这两个转换器实例将复选框绑定到同一属性:

<CheckBox IsChecked="{Binding MyProperty, Converter={StaticResource Converter}}" />
<CheckBox IsChecked="{Binding MyProperty, Converter={StaticResource Inverter}}" />

如果选中第一个框,则属性为false,如果选中第二个框,则为true,如果未选中复选框,则为null。< / p>

但是,我同意ANewGuyInTown你最好使用Enum,因为bool类型在这里有点令人困惑(顺便说一下,大多数转换器都可以重新使用在使用三态枚举而不是可以为空的布尔值时使用。

答案 1 :(得分:2)

制作&#34; NotConverter&#34;在其中一个复选框上。这是我在Windows应用商店和手机应用中使用了一段时间的实现。 WPF很相似。

/// <summary>
/// Converts a bool to it's oppisite and back.
/// </summary>
public sealed class NotConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, string language)
    {
        return (!(value is bool)) || !(bool)value;
    }

    public object ConvertBack(object value, Type targetType, object parameter, string language)
    {
        return (value is bool) && (bool)value;
    }
}

在App.xaml(或您的视图)文件中注册您的转换器:

<Application.Resources>
    <ResourceDictionary>
        <converters:NotConverter x:Key="NotConverter"/>
    </ResourceDictionary>
</Application.Resources>

将它绑定在您的视图中:

<CheckBox IsChecked="{Binding OnlyMusicWithErrorsChecked,Converter={StaticResource NotConverter}}"></CheckBox>

您也可以为其他复选框命名并绑定到它的属性,如下所示:

<CheckBox x:Name="MyCheckBox" IsChecked="{Binding OnlyMusicWithErrorsChecked}"/>
<CheckBox IsChecked="{Binding ElementName=MyCheckBox,Path=IsChecked,Converter={StaticResource NotConverter}}"/>

答案 2 :(得分:1)

三个状态复选框。

 public bool CheckBox1
    {
        get { return _checkBox1; }
        set 
        { 
            _checkBox1 = value;
            if (value == true)
            {
                CheckBox2 = false;
            }
            OnPropertyChanged("CheckBox1");
        }
    }

    private bool _checkBox2 = false;

    public bool CheckBox2
    {
        get { return _checkBox2; }
        set 
        { 
            _checkBox2 = value;
            if (value == true)
            {
                CheckBox1 = false;
            }
            OnPropertyChanged("CheckBox2");
        }
    }

在Xaml Code中就像这样

<CheckBox Content="CheckBox1" IsChecked="{Binding CheckBox1, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" Height="30" Width="100" />
<CheckBox Content="CheckBox2" IsChecked="{Binding CheckBox2, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" Height="30" Width="100" />