如何在 WPF 中设置/重置三态复选框值

发布于 2024-10-14 01:22:09 字数 3274 浏览 2 评论 0原文

我有一个数据网格,其标题列之一是三态复选框。该列的单元格模板包含两个状态复选框 + 所有项目复选框 - 项目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(对象发送者, 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 计数不起作用。

注意:上面的代码更像是一个示例,直接复制它可能不起作用。我可以根据要求提供完整的代码和示例。

I have a datagrid whose one of the header column is Three-state checkbox. The celltemplate for that column contains two state checkbox
+ AllItems CheckBox
- Item1
- Item2
- Item3
..
I wanted to use AllItems checkbox to select/unselect all items (item1,item2) which works fine. Next I wanted to set AllItems checkbox to intermediate state when not all items are selected/unselected. Similarly I wanted to set AllItems checkbox as checked/unchecked when all items get manually selected.

Here is the code that I tried...

<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" method looks for all three state (all-checked, none-checked, intermediate) and sets "IsAllItemChecked" property which is INotifyproperty. It does not work. Other alternative I may try is to find the "AllItems" element and set it from the code. Could not locate anything like that on web. There is few examples but is for TreeView and not the way I am trying. Any help?

PS>>

Updated with fix to close this post.

  • First thing I wanted was to allow "AllItemSelectionCheckBox" to have only two states (True, False) when manually selected.

    private void AllItemSelectionCheckBox_Click(object sender, RoutedEventArgs e)
    {
        var cb = e.Source as CheckBox;
        if (!cb.IsChecked.HasValue)
            cb.IsChecked = false;  
    }
    
  • I wanted "AllItemSelectionCheckBox" checkbox to show three-state thru code.
  • All check-box checked will cause its value to TRUE
  • All check-box unchecked will cause its value to FALSE
  • Any few selected will cause its value to NULL.

Code Example following:

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

Updating NumberOfItemsChecked count globally did not work due to race condition corrupting the value outside.

Note: Above code is more like an example and may not work copying it directly. I can provide complete code with sample on request.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

酒中人 2024-10-21 01:22:10

这对我有用。我创建了一个新的 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;
    }            
}

This is what worked for me. I created a new FTThreeStateCheckBox (subclassed from CheckBox), overrode the IsCheckedProperty metadata so I could watch for changes in the value, then if it was null, I set IsThreeState and IsChecked to 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;
    }            
}
捎一片雪花 2024-10-21 01:22:10

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

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

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

            cbAllFeatures.IsChecked = false;
        }

我希望你喜欢它。

I found a simple way:

Adjust the event click of three state check box, and check if its value is null. If does change it to false. Like this:

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

            cbAllFeatures.IsChecked = false;
        }

I hope you enjoy it.

活泼老夫 2024-10-21 01:22:10

对于想要实现此目的的人,

  • 用户可以将视图中的复选框仅切换为 true 或 false。不要未定义!
  • ViewModel 中的代码可以将复选框切换为 true 或 false 或未定义,

只需执行以下操作:

  • 将复选框添加到视图,但不要设置 IsThreeState=true
  • 绑定 IsChecked 到ViewModel 中的 bool?(可为 null bool)属性

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

for people who want to achieve this

  • user can switch checkbox in the view only to true or false. Not to undefined!
  • code in ViewModel can switch checkbox to true or false or undefined

just do this:

  • add checkbox to view but DONT set IsThreeState=true
  • bind IsChecked to a bool? (nullable bool) property in the ViewModel

You can now set it to null in the ViewModel while the user cannot do it in the View.

陌路黄昏 2024-10-21 01:22:09

事实上我还有一个更好的。

我发现,如果我为 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,该值在外部设置为 null。
如果该值为 true 或 false,用户将无法将其设置为 null。

Actually I got one better.

I found out that if I create a binding for IsThreeState, then change the value based on whether the value is set or not, then it works.

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");
    }
}

Now the checkbox will support threestate IFF the value is set to null externally.
If the value is true or false, the user won't be able to set it to null.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文