【问题标题】:How to set/reset Three-state checkbox value in WPF如何在 WPF 中设置/重置三态复选框值
【发布时间】:2011-06-14 06:36:21
【问题描述】:

我有一个数据网格,其标题列之一是三态复选框。该列的单元格模板包含两个状态复选框 + 所有项目复选框 - 项目 1 - 项目2 - 项目 3 .. 我想使用 AllItems 复选框来选择/取消选择所有工作正常的项目(item1,item2)。接下来,当并非所有项目都被选中/取消选中时,我想将 AllItems 复选框设置为中间状态。同样,当手动选择所有项目时,我想将 AllItems 复选框设置为选中/未选中。

这是我尝试过的代码...

<dg:DataGridTemplateColumn.HeaderTemplate>
    <DataTemplate>
        <StackPanel x:Name="StackPanelForItemCheckbox" Orientation="Horizontal">
           <CheckBox x:Name="AllItemSelectionCheckBox" HorizontalAlignment="Left" Cursor="Hand"  
                     IsChecked="{Binding IsAllItemChecked, Mode=TwoWay}"                                              
                     IsThreeState="True"  Checked="ItemSelectionCheckBox_Checked" 
                     Unchecked="ItemSelectionCheckBox_Unchecked"
                     Click="AllItemSelectionCheckBox_Click">
           <TextBlock x:Name="ItemNameTextBlock" Text="Item" Margin="10,0,0,0">
           ......
<dg:DataGridTemplateColumn.CellTemplate>
       <DataTemplate x:Name="ItemCheckDataTemplate">                                
           <StackPanel x:Name="ItemCheckBoxStackPanel" Orientation="Horizontal">                                    
                  <CheckBox x:Name="itemCheckBox" Cursor="Hand" IsChecked="{Binding IsItemChecked, Mode=TwoWay}" Click="ItemSelectionCheckBox_Click"></CheckBox>
                   <TextBlock x:Name="ItemNameTextBlock" Text="{Binding Path=Item}"> </TextBlock>                                   
            </StackPanel>
         </DataTemplate>
...

“ItemSelectionCheckBox_Click”方法查找所有三种状态(全部选中、未选中、中间)并设置“IsAllItemChecked”属性,即 INotifyproperty。这是行不通的。我可能会尝试的其他替代方法是找到“AllItems”元素并从代码中设置它。在网上找不到类似的东西。例子很少,但适用于 TreeView 而不是我尝试的方式。有什么帮助吗?

PS>>

已更新修复以关闭此帖子。

  • 我想要的第一件事是允许“AllItemSelectionCheckBox”在手动选择时只有两种状态(True、False)。

    private void AllItemSelectionCheckBox_Click(object sender, RoutedEventArgs e)
    {
        var cb = e.Source as CheckBox;
        if (!cb.IsChecked.HasValue)
            cb.IsChecked = false;  
    }
    
  • 我希望“AllItemSelectionCheckBox”复选框显示三态直通代码。
  • 选中的所有复选框都会使其值为 TRUE
  • 所有未选中的复选框都将导致其值为 FALSE
  • 任何少数选择都会导致其值为 NULL。

代码示例如下:

private void itemCheckBox_Checked(object sender, RoutedEventArgs e)
{ 
    DataGridRowsPresenter DGRPresenter = FindVisualChild<DataGridRowsPresenter>(DataGName1);
    if (DGRP == null || DGRP.Children == null)
        return null;
    foreach (object obj in UIEC)
    {
        DGR = obj as Microsoft.Windows.Controls.DataGridRow;
        UIC = DGR.Item as <datagrid mapped data model>;
        if (DGR.IsSelected == true)
            UIC.IsItemChecked = true;
        if (UIC.IsItemChecked == true)
                NumberOfItemsChecked++;
    }
    if (NumberOfItemsChecked == myViewModelAllItems.Count)
    {
        allcheckbox.IsChecked = true;
    }
    else if (NumberOfItemsChecked < myViewModelAllItems.Count)
    {
        allcheckbox.IsChecked = null;   //intermittent state
    }
}

由于竞争条件破坏了外部值,全局更新 NumberOfItemsChecked 计数无效。

注意: 上面的代码更像是一个示例,直接复制可能无法正常工作。我可以根据要求提供完整的代码和示例。

【问题讨论】:

    标签: wpf wpf-controls checkbox wpfdatagrid


    【解决方案1】:

    对于想要实现这一目标的人

    • 用户只能将视图中的复选框切换为真或假。不要未定义!
    • ViewModel 中的代码可以将复选框切换为 true、false 或 undefined

    这样做:

    • 添加复选框以查看但不要设置IsThreeState=true
    • 在 ViewModel 中将 IsChecked 绑定到 bool?(可为空的布尔值)属性

    您现在可以在 ViewModel 中将其设置为 null,而用户无法在 View 中执行此操作。

    【讨论】:

    • 我很好奇为什么这不是最初的答案之一。你知道框架行为是否改变了吗?这似乎是很明显的尝试,它基本上是自动发生的。也许我不明白 OP 的问题,但是当我搜索时,这回答了我的问题。
    • @andrew 我不认为它改变了。微软十年没有更新wpf了。该解决方案有效,但我只是偶然发现了它。关闭三态并不直观,但它仍然具有三态行为。在我发现这个之前,我在这里投票并使用了其他解决方案之一,但遇到了一些问题。
    • 我的措辞很差,听起来很傲慢(“......真的很明显......”)。这对我来说当然不是很明显。我的意思是我很惊讶一个简单的解决方案不是早期已知的解决方案。在我实际尝试自己(预先计划)并在阅读您的答案时认为“整洁,这很简单”之前,我正在研究这个。然后我想知道写另一个答案时行为是否有所不同。有时我喜欢在做事之前先阅读 SO,以了解我正在做的事情——尤其是使用 WPF :) 谢谢!
    【解决方案2】:

    我找到了一个简单的方法:

    调整三态复选框的事件点击,检查其值是否为空。如果确实将其更改为假。像这样:

            private void cbAllFeatures_Click(object sender, RoutedEventArgs e)
            {
                if (cbAllFeatures.IsChecked != null) return;
    
                cbAllFeatures.IsChecked = false;
            }
    
    

    希望你喜欢。

    【讨论】:

      【解决方案3】:

      这对我有用。我创建了一个新的 FTThreeStateCheckBox(从 CheckBox 子类化),覆盖了 IsCheckedProperty 元数据,以便我可以观察值的变化,然后如果它为 null,我将 IsThreeState 和 IsChecked 设置为 false。

      static FTThreeStateCheckBox()
      {
          IsCheckedProperty.OverrideMetadata(typeof(FTThreeStateCheckBox), new FrameworkPropertyMetadata(null, IsCheckedChanged));          
      }
      
      
      public static void IsCheckedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
      {
          if ((d as FTThreeStateCheckBox).IsChecked == null)
          {
              (d as FTThreeStateCheckBox).IsThreeState = false;
              (d as FTThreeStateCheckBox).IsChecked = false;
          }            
      }
      

      【讨论】:

        【解决方案4】:

        实际上我得到了一个更好的。

        我发现如果我为 IsThreeState 创建一个绑定,然后根据值是否设置来更改值,那么它就可以工作了。

        bool? _Value;
        public bool? Value
        {
            get { return _Value; }
            set
            {
                if (value == null)
                {
                    IsThreeState = true;
                }
                else
                {
                    IsThreeState = false;
                }
                _Value = value;
        
                NotifyPropertyChanged("Value");
            }
        }
        
        bool _IsThreeState = true;
        public bool IsThreeState
        {
            get { return _IsThreeState; }
            private set
            {
                _IsThreeState = value;
                NotifyPropertyChanged("IsThreeState");
            }
        }
        

        现在复选框将支持三态 IFF 值在外部设置为空。 如果该值为 true 或 false,用户将无法将其设置为 null。

        【讨论】:

        • 轻微简化:IsThreeState = !value.HasValue
        • 这应该是答案!
        猜你喜欢
        • 2014-02-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-07-02
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多