Как установить / сбросить значение флажка с тремя состояниями в WPF - PullRequest
6 голосов
/ 24 января 2011

У меня есть сетка данных, чей один из столбцов заголовка имеет флажок «Три состояния». Celltemplate для этого столбца содержит два флажка состояния + AllItems CheckBox - Item1 - Item2 - Item3 .. Я хотел использовать флажок 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
  • Если флажок не установлен, его значение будет равно ЛОЖЬ
  • Любые несколько выбранных будут иметь значение 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 не работало из-за состояния гонки, повреждающего значение снаружи.

Примечание: Вышеприведенный код больше похож на пример и может не работать при его прямом копировании. Я могу предоставить полный код с образцом по запросу.

Ответы [ 3 ]

13 голосов
/ 11 апреля 2013

На самом деле я получил один лучше.

Я обнаружил, что если я создаю привязку для 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.

1 голос
/ 15 октября 2016

Я нашел простой способ:

Настройте флажок события из трех состояний и убедитесь, что его значение равно нулю.Если действительно, измените его на false.Вот так:

private void cbAllFeatures_Click(object sender, RoutedEventArgs e)
    {
        CheckBox checkbox = sender as CheckBox;
        if (checkbox.IsChecked == null)
            checkbox.IsChecked = false;
    }

Надеюсь, вам понравится.

0 голосов
/ 24 октября 2016

Вот что у меня сработало. Я создал новый FTThreeStateCheckBox (подкласс из CheckBox), переопределил метаданные IsCheckedProperty, чтобы я мог наблюдать за изменениями значения, а затем, если оно было нулевым, я устанавливаю 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;
    }            
}
...