Xaml mvvm中的3状态复选框绑定,无法设置空状态

Xaml mvvm中的3状态复选框绑定,无法设置空状态,xaml,checkbox,mvvm,data-binding,uwp,Xaml,Checkbox,Mvvm,Data Binding,Uwp,我正在使用MVVM创建一个UWP应用程序。在我的xaml视图中,我有一个3状态复选框。我的复选框在一个列表视图中,这个列表视图也有一个子列表视图,有更多的复选框,所以本质上是嵌套的复选框列表。如果选中了内部listview中的任何复选框,我将尝试使外部listview中的复选框处于空状态。如果选择了所有内部复选框,我希望外部复选框处于true状态,如果未选择任何复选框,我希望它处于false状态。我正在使用委托命令来实现这些事件处理程序 我能够成功地使正确和错误案例工作,但是我无法使复选框在UI

我正在使用MVVM创建一个UWP应用程序。在我的xaml视图中,我有一个3状态复选框。我的复选框在一个列表视图中,这个列表视图也有一个子列表视图,有更多的复选框,所以本质上是嵌套的复选框列表。如果选中了内部listview中的任何复选框,我将尝试使外部listview中的复选框处于空状态。如果选择了所有内部复选框,我希望外部复选框处于true状态,如果未选择任何复选框,我希望它处于false状态。我正在使用委托命令来实现这些事件处理程序

我能够成功地使正确和错误案例工作,但是我无法使复选框在UI上显示状态null,因为它在我的ViewModel中的值成功地更改为null

<ListView ItemsSource="{Binding ObxList, Mode=TwoWay}">
    <ListView.ItemTemplate>
        <DataTemplate>
            <CheckBox IsChecked="{x:Bind IsSelected, Mode=TwoWay}" IsThreeState="True" Command="{Binding DataContext.ClickCommand, ElementName=Y}">
                <TextBlock Text="{x:Bind Value}"  />
            </CheckBox>
            <ListView ItemsSource="{Binding Children}" Visibility="{Binding visibility, Mode=TwoWay}">
                <ListView.ItemTemplate>
                    <DataTemplate>
                        <CheckBox IsChecked="{Binding IsSelected, Mode=TwoWay}"
                                  IsThreeState="False" Command="{Binding DataContext.ChildCommand, ElementName=Y}">
                            <TextBlock Text="{Binding Value}"/>
                        </CheckBox>
                    </DataTemplate>
                </ListView.ItemTemplate>
            </ListView>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView

{
返回t.Children.Count()==0;
}))
{
如果(item.IsSelected==true)
{
var parent=item.GetParent(AllObjectsList);
if(parent.IsSelected==null | | parent.IsSelected==false)
{
//检查是否选择了所有子项
//并将父项更改为true(如果是)
//如果仅选择了一些,则为null
bool allChildrenSelected=true;
foreach(parent.GetChildren中的var child(AllObjectsList))
{
if(child.IsSelected==false)
{
allChildrenSelected=false;
打破
}
}
如果(已选择所有儿童)
{
parent.IsSelected=true;
}
其他的
{
parent.IsSelected=new Nullable();
}
}
}
else if(item.IsSelected==false)
{
var parent=item.GetParent(AllObjectsList);
if(parent.IsSelected==null)
{
//检查是否所有子项都未选中
//如果是,则将父项设置为false
//如果不是,则将父项设置为null
bool noChildrenSelected=true;
foreach(parent.GetChildren中的var child(AllObjectsList))
{
if(child.IsSelected==true)
{
noChildrenSelected=false;
打破
}
}
如果(未选择儿童)
{
parent.IsSelected=false;
}
}
else if(parent.IsSelected==true)
{
parent.IsSelected=null;
}
}
}
}

这是因为WinRT不支持绑定到可空类型


@Jerry Nixon-MSFT有三种方法解决这个问题,他的博客中提供了一些示例。

这是因为WinRT不支持绑定到可空类型


@Jerry Nixon-MSFT有三种方法解决这个问题,他的博客中提供了一些示例。

这是因为WinRT不支持绑定到可空类型


@Jerry Nixon-MSFT有三种方法解决这个问题,他的博客中提供了一些示例。

这是因为WinRT不支持绑定到可空类型


@Jerry Nixon-MSFT有三种方法来解决这个问题,他的博客中提供了一些示例。

最终的问题是
依赖性属性的
实现
复选框。IsChecked
。WinRT中不隐式支持可空基元类型绑定,在WinRT中,基础类型是
IReference1
,这是一个内部定义,因此我们无法使用简单类型转换器来解决此问题

技术上是正确的,@Jerry Nixon在中提供了一些有用的背景信息,但它只表明存在解决方法,而不是具体如何实现它们

这篇文章中的建议在近10年的UWP中仍然有用:。最简单的解决方法是创建一个新的依赖项属性,该属性类型为
对象

这是许多第三方控件库中的常见解决方案,通常可以找到
对象
类型化的
属性和单独类型化的属性

这可以通过附加属性来实现,但是我更喜欢扩展
复选框
类:

//
///复选框控件,支持不确定状态的绑定
/// 
/// https://www.danrigby.com/2012/07/24/windows-8-dev-tip-nullable-dependency-properties-and-binding/
公共类BindableCheckBox:复选框
{
公共BindableCheckBox()
{
this.isthrestate=true;
//从可为空的状态开始!
this.IsChecked=null;
//连接UI事件以手动适当设置值
this.Checked+=BindableCheckBox\u Checked;
this.Unchecked+=BindableCheckBox\u Unchecked;
this.undeterminate+=BindableCheckBox\u undeterminate;
//连接属性已更改事件,以防某个笨蛋以其他方式设置ISCHECK
this.RegisterPropertyChangedCallback(CheckBox.IsCheckedProperty,(s,e)=>
{
如果(s是可绑定复选框cb)
{
如果(!cb.\U值正在更改)
{
public void ChildCheckboxHandler()
    {
        // gets all of the lowest level children
        foreach (Object item in AllObjectsList.Where(t =>
        {
            return t.Children.Count() == 0;
        }))
        {
            if (item.IsSelected == true)
            {
                var parent = item.GetParent(AllObjectsList);
                if (parent.IsSelected == null || parent.IsSelected == false)
                {
                    // checks if all children are selected
                    // and changes the parent to true if so
                    // null if only some are selected
                    bool allChildrenSelected = true;
                    foreach (var child in parent.GetChildren(AllObjectsList))
                    {
                        if (child.IsSelected == false)
                        {
                            allChildrenSelected = false;
                            break;
                        }
                    }
                    if (allChildrenSelected)
                    {
                        parent.IsSelected = true;
                    }
                    else
                    {
                        parent.IsSelected = new Nullable<Boolean>();

                    }
                }
            }
            else if (item.IsSelected == false)
            {
                var parent = item.GetParent(AllObjectsList);
                if (parent.IsSelected == null)
                {
                    // checks if all the children are unchecked
                    // if they are, then sets the parent to false
                    // if they are not, then sets the parent to null
                    bool noChildrenSelected = true;
                    foreach (var child in parent.GetChildren(AllObjectsList))
                    {
                        if (child.IsSelected == true)
                        {
                            noChildrenSelected = false;
                            break;
                        }
                    }
                    if (noChildrenSelected)
                    {
                        parent.IsSelected = false;
                    }
                }
                else if (parent.IsSelected == true)
                {
                    parent.IsSelected = null;
                }
            }
        }
    }