C# 将两个checbox绑定到MVVM中可为空的bool属性

C# 将两个checbox绑定到MVVM中可为空的bool属性,c#,wpf,mvvm,C#,Wpf,Mvvm,我尝试将两个复选框连接到我的ViewModel。他们的行为就像是一个单选按钮的排他性状态。所以两个都没有检查,或者其中一个没有检查 目前我正在做这样的工作: <dxlc:LayoutGroup> <dxlc:LayoutItem Label="with errors"> <Ch

我尝试将两个复选框连接到我的ViewModel。他们的行为就像是一个单选按钮的排他性状态。所以两个都没有检查,或者其中一个没有检查

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

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

问题是:我可以只使用一个属性nullable bool来执行此操作吗?

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

<CheckBox IsChecked="{Binding OnlyMusicWithErrorsChecked, Converter={StaticResource Inverter}}"></CheckBox>
编辑:如果要构建仅具有一个可绑定属性的三状态解决方案,则需要两个转换器或一个可参数化的转换器:

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;
    }
}
第一个复选框的“反转”属性设置为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


但是,我同意ANewGuyInTown的观点,即最好使用枚举,因为bool类型在这里有点混乱,顺便说一句,大多数转换器在使用三状态枚举时可以重复使用,而不是使用可为null的布尔值。

您可以仅将两个复选框绑定到同一属性musicWithErrorSchecked,在第二个复选框中,添加一个反转属性值的转换器:

<CheckBox IsChecked="{Binding OnlyMusicWithErrorsChecked, Converter={StaticResource Inverter}}"></CheckBox>
编辑:如果要构建仅具有一个可绑定属性的三状态解决方案,则需要两个转换器或一个可参数化的转换器:

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;
    }
}
第一个复选框的“反转”属性设置为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


但是,我同意ANewGuyInTown的观点,即最好使用枚举,因为bool类型在这里有点混乱,顺便说一下,大多数转换器在使用三状态枚举而不是可为null的布尔值时可以重复使用。

在其中一个复选框上创建NotConverter。这是我在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}}"/>

在其中一个复选框上创建NotConverter。这是我在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}}"/>
三状态复选框

 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代码中,类似这样的代码

<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" />
三状态复选框

 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代码中,类似这样的代码

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

如果想要单选按钮这样的行为,为什么要使用复选框?我认为与其尝试对复选框进行修改,不如重新考虑控件本身的选择。一个部件类似于radiobutton,但我希望两个复选框/radiobutton都不被选中。这就是为什么,我想将它们绑定到一个可为null的bool属性在这种情况下,使用可为null的属性不是一个好主意。Nullable bool是一个三态属性,第三个值是一个不确定状态null,您不希望将其用作满足需求的变通方法。我认为首先你必须弄清楚控制流程,即状态序列如何在复选框之间流动?换句话说,在什么样的场景中,两者都被取消选中,一个被取消选中,另一个被取消选中,依此类推。然后您可以决定什么数据类型适合该状态。可能是一个枚举可以完成此任务。但是你必须让我们知道你的全部要求。如果你想要像单选按钮一样的行为,为什么要使用复选框?我认为与其尝试对复选框进行修改,不如重新考虑控件本身的选择。一个部件类似于radiobutton,但我希望两个复选框/radiobutton都不被选中。这就是为什么,我想将它们绑定到一个可为null的bool属性在这种情况下,使用可为null的属性不是一个好主意。Nullable bool是一个三态属性,第三个值是一个不确定状态null,您不希望将其用作满足需求的变通方法。我认为首先你必须弄清楚控制流程,即状态序列如何在复选框之间流动?换句话说,在什么样的场景中,两者都被取消选中,一个被取消选中,另一个被取消选中,依此类推。然后您可以决定什么数据类型适合该状态。可能是一个枚举可以完成此任务。但是你必须让我们知道你的全部要求。我想知道你的要求。所以两个都没有检查,或者其中一个没有检查。您的解决方案不适用于三状态检查
框,不是吗?当然,你可以向转换器添加任何逻辑-我已经编辑了我的答案,以显示一个三态解决方案!我想把这个复选框放在州里。所以两个都没有检查,或者其中一个没有检查。您的解决方案不适用于三态复选框,不是吗?当然,您可以向转换器添加任何逻辑-我已经编辑了我的答案以显示三态解决方案!好的,我做到了。但您也使用两个属性。我想也许我可以这样做,只有一个可为null的属性复选框1在可为null的bool属性为true时选中,复选框2在可为null的bool属性为false时选中,而无复选框在可为null的bool属性为null时选中。如果你需要使用signle属性,你应该像其他人建议的那样使用转换器,并放置类似的逻辑。好的,我做到了。但您也使用两个属性。我想我可能只能在一个可为null的属性复选框1选中(当可为null的bool属性为true时)、复选框2选中(当可为null的bool属性为false时)和none复选框选中(当可为null的bool属性为null时)的情况下才能做到这一点。如果需要使用Single属性,您应该按照其他人的建议使用转换器,并放置类似的逻辑。