C# 在XAML中的布尔值到复选框状态转换器中返回null

C# 在XAML中的布尔值到复选框状态转换器中返回null,c#,xaml,checkbox,windows-store-apps,win-universal-app,C#,Xaml,Checkbox,Windows Store Apps,Win Universal App,我有一个TaskStatus到Boolean转换器,它在XAML中为Windows应用商店应用程序(通用应用程序)实现IValueConverter接口 我有三种任务状态,我使用IsThrestate=“true”在复选框中启用了不确定状态 现在,尽管IsChecked属性似乎是一个Boolean?,但转换器始终将System.Boolean作为目标类型。无论我返回什么(例如null),都会转换为false,因此我无法在复选框中获取第三个状态 有没有一种方法可以在我的转换器中指定TargetTy

我有一个TaskStatus到Boolean转换器,它在XAML中为Windows应用商店应用程序(通用应用程序)实现IValueConverter接口

我有三种任务状态,我使用IsThrestate=“true”在复选框中启用了不确定状态

现在,尽管IsChecked属性似乎是一个Boolean?,但转换器始终将System.Boolean作为目标类型。无论我返回什么(例如null),都会转换为false,因此我无法在复选框中获取第三个状态

有没有一种方法可以在我的转换器中指定TargetType,或者返回null,以便IsChecked得到null作为输入,从而显示第三种状态

以下是转换器:

public class TaskStatusToCheckBoxStateConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, string language)
    {
        var taskStatus = (TaskStatus) value;
        switch (taskStatus)
        {
            case TaskStatus.Open:
                return false;
            case TaskStatus.InProgress:
                return null;
            case TaskStatus.Done:
                return true;
            default:
                throw new ArgumentOutOfRangeException();
        }
    }

    public object ConvertBack(object value, Type targetType, object parameter, string language)
    {
        var checkBoxState = (Boolean?) value;
        if (checkBoxState == null)
            return TaskStatus.InProgress;
        if (checkBoxState.Value)
            return TaskStatus.Done;
        return TaskStatus.Open;
    }
}
复选框的XAML代码

<CheckBox x:Name="CheckBoxTaskState" 
    IsThreeState="True"
    IsChecked="{Binding Status, 
                Converter={StaticResource TaskStatusToCheckBoxStateConverter}, 
                Mode=TwoWay}">
</CheckBox>

根据[this][1]:目前不支持绑定到WinRT中的可空类型。这对于一个无文件记录的规则来说怎么样?现在你知道了

从这个开始

public sealed partial class MainPage : Page, INotifyPropertyChanged
{
    public MainPage()
    {
        this.InitializeComponent();
        this.DataContext = this;
    }

    private void NullButton_Click(object sender, RoutedEventArgs e)
    { this.State = null; }

    private void FalseButton_Click(object sender, RoutedEventArgs e)
    { this.State = false; }

    private void TrueButton_Click(object sender, RoutedEventArgs e)
    { this.State = true; }

    bool? _State = null;
    public bool? State { get { return _State; } set { SetProperty(ref _State, value); } }

    public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;
    void SetProperty<T>(ref T storage, T value, [System.Runtime.CompilerServices.CallerMemberName] String propertyName = null)
    {
        if (!object.Equals(storage, value))
        {
            storage = value;
            if (PropertyChanged != null)
                PropertyChanged(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName));
        }
    }
}
您的XAML将仅更改如下:

<CheckBox Content="Hello three-state"
          IsThreeState="True"
          local:NullableCheckbox.Enabled="true"
          local:NullableCheckbox.IsChecked="{Binding State, Mode=TwoWay}" />

常规IsChecked属性不重要,它将被附加属性覆盖。您的viewmodel可以保持不变。真的很神奇,是吗


祝你好运

尝试返回可为null的
而不是仅为null。(请注意,Nullable是一个结构,它将作为一个对象装箱。因此,返回null与返回Nullable并不相同。)也不起作用。不幸的是,同样的结果。也许我做错了。我现在已经
返回新的Nullable()。这就是你的意思吗?我刚刚选中了tri-state复选框和System.Windows.Data.IValueConverter(手头没有VS2013/WindowsStore项目),其Convert方法返回null或new Nullable。这两种变体都很有魅力。您是否尝试在Convert和ConvertBack方法中设置断点,以观察绑定和转换器正在处理哪些值?是的。我查过了。当值为TaskStatus.InProgress时,代码将正确进入相应的开关盒。目标类型始终为System.Boolean。ConvertBack很有魅力。Just Convert不会返回正确的空值。我也在WPF应用程序中尝试了同样的方法,就像在您这边一样,它可以按预期工作(null和null)。我不相信WindowsStore应用程序中的复选框或转换器绑定被破坏。如果您看到ConvertBack正常工作,而Convert似乎不工作,那么我只能想到以下可能导致您出现问题的场景:(1)在代码背后的某个地方,或者作为XAML中触发器定义的一部分,CheckBox属性的值IsChecked或IsThrestate在某些情况下发生更改。(2) 您的代码还有另一个双向数据绑定,IsChecked或IsThreeState属性作为其绑定源,从而更改属性。
public class NullableCheckbox : DependencyObject
{
    public static bool GetEnabled(DependencyObject obj)
    { return (bool)obj.GetValue(EnabledProperty); }
    public static void SetEnabled(DependencyObject obj, bool value)
    { obj.SetValue(EnabledProperty, value); }
    public static readonly DependencyProperty EnabledProperty =
        DependencyProperty.RegisterAttached("Enabled", typeof(bool), typeof(NullableCheckbox), new PropertyMetadata(false, EnabledChanged));
    private static void EnabledChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var checkbox = d as CheckBox;
        if ((bool)e.NewValue)
        {
            var binding = new Binding
            {
                Path = new PropertyPath("IsChecked"),
                Mode = BindingMode.TwoWay,
                Source = checkbox,
            };
            checkbox.SetBinding(NullableCheckbox.InternalStateProperty, binding);
        }
    }

    private static object GetInternalState(DependencyObject obj)
    { return (object)obj.GetValue(InternalStateProperty); }
    private static void SetInternalState(DependencyObject obj, object value)
    { obj.SetValue(InternalStateProperty, value); }
    private static readonly DependencyProperty InternalStateProperty =
        DependencyProperty.RegisterAttached("InternalState", typeof(object),
        typeof(NullableCheckbox), new PropertyMetadata(null, InternalStateChanged));
    private static void InternalStateChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    { SetIsChecked(d, (object)e.NewValue); }

    public static object GetIsChecked(DependencyObject obj)
    { return (object)obj.GetValue(IsCheckedProperty); }
    public static void SetIsChecked(DependencyObject obj, object value)
    { obj.SetValue(IsCheckedProperty, value); }
    public static readonly DependencyProperty IsCheckedProperty =
        DependencyProperty.RegisterAttached("IsChecked", typeof(object),
        typeof(NullableCheckbox), new PropertyMetadata(default(object), IsCheckedChanged));
    private static void IsCheckedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var checkbox = d as CheckBox;
        bool? newvalue = null;
        if (e.NewValue is bool?)
            newvalue = (bool?)e.NewValue;
        else if (e.NewValue != null)
        {
            bool newbool;
            if (!bool.TryParse(e.NewValue.ToString(), out newbool))
                return;
            newvalue = newbool;
        }
        if (!checkbox.IsChecked.Equals(newvalue))
            checkbox.IsChecked = newvalue;
    }
}
<CheckBox Content="Hello three-state"
          IsThreeState="True"
          local:NullableCheckbox.Enabled="true"
          local:NullableCheckbox.IsChecked="{Binding State, Mode=TwoWay}" />