Подтвердить что ты не робот

Как выполнить выбор флажка "Однократный щелчок" в WPF DataGrid?

У меня есть DataGrid с первым столбцом в виде текстового столбца и вторым столбцом в качестве столбца CheckBox. Я хочу, если я поставлю флажок. Он должен быть проверен.

Но для его выбора требуется два щелчка, для первого щелчка ячейки выбирается, а для вторых кликов устанавливается флажок. Как сделать флажок для проверки или снятия флажка одним щелчком.

Примечание. Я использую WPF 4.0

Edit: Столбцы в DataGrid автоматически генерируются.

4b9b3361

Ответ 1

Это для 3.5sp1, я знаю - но он должен работать под 4.0: Vinsibal.

Ответ 2

Чтобы установить флажок одиночного щелчка по datagrid, вы можете просто установить регулярный флажок внутри DataGridTemplateColumn и установить UpdateSourceTrigger = PropertyChanged Все это. Очень просто.:)

<DataGridTemplateColumn.CellTemplate>
    <DataTemplate>
        <CheckBox IsChecked="{Binding Path=IsSelected, UpdateSourceTrigger=PropertyChanged}" />
    </DataTemplate>
</DataGridTemplateColumn.CellTemplate>

Ответ 3

Я решил это со следующим стилем:

<Style TargetType="DataGridCell">
     <Style.Triggers>
         <Trigger Property="IsMouseOver" Value="True">
             <Setter Property="IsEditing" Value="True" />
         </Trigger>
     </Style.Triggers>
 </Style>

Конечно, можно адаптировать это для конкретных столбцов...

Ответ 4

На основе блога, на который ссылается ответ Goblin, но изменен для работы в .NET 4.0 и в режиме выбора строк.

Обратите внимание, что это также ускоряет редактирование DataGridComboBoxColumn - путем входа в режим редактирования и отображения выпадающего меню одним нажатием или текстовым вводом.

XAML:

        <Style TargetType="{x:Type DataGridCell}">
            <EventSetter Event="PreviewMouseLeftButtonDown" Handler="DataGridCell_PreviewMouseLeftButtonDown" />
            <EventSetter Event="PreviewTextInput" Handler="DataGridCell_PreviewTextInput" />
        </Style>

Code-за:

    private void DataGridCell_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
    {
        DataGridCell cell = sender as DataGridCell;
        GridColumnFastEdit(cell, e);
    }

    private void DataGridCell_PreviewTextInput(object sender, TextCompositionEventArgs e)
    {
        DataGridCell cell = sender as DataGridCell;
        GridColumnFastEdit(cell, e);
    }

    private static void GridColumnFastEdit(DataGridCell cell, RoutedEventArgs e)
    {
        if (cell == null || cell.IsEditing || cell.IsReadOnly)
            return;

        DataGrid dataGrid = FindVisualParent<DataGrid>(cell);
        if (dataGrid == null)
            return;

        if (!cell.IsFocused)
        {
            cell.Focus();
        }

        if (cell.Content is CheckBox)
        {
            if (dataGrid.SelectionUnit != DataGridSelectionUnit.FullRow)
            {
                if (!cell.IsSelected)
                    cell.IsSelected = true;
            }
            else
            {
                DataGridRow row = FindVisualParent<DataGridRow>(cell);
                if (row != null && !row.IsSelected)
                {
                    row.IsSelected = true;
                }
            }
        }
        else
        {
            ComboBox cb = cell.Content as ComboBox;
            if (cb != null)
            {
                //DataGrid dataGrid = FindVisualParent<DataGrid>(cell);
                dataGrid.BeginEdit(e);
                cell.Dispatcher.Invoke(
                 DispatcherPriority.Background,
                 new Action(delegate { }));
                cb.IsDropDownOpen = true;
            }
        }
    }


    private static T FindVisualParent<T>(UIElement element) where T : UIElement
    {
        UIElement parent = element;
        while (parent != null)
        {
            T correctlyTyped = parent as T;
            if (correctlyTyped != null)
            {
                return correctlyTyped;
            }

            parent = VisualTreeHelper.GetParent(parent) as UIElement;
        }
        return null;
    }

Ответ 5

Сначала я знаю, что это довольно старый вопрос, но я все же думал, что попробую ответить на него.

У меня была такая же проблема несколько дней назад, и на нее набросилось удивительно короткое решение (см. этот блог). В основном, все, что вам нужно сделать, это заменить определение DataGridCheckBoxColumn в вашем XAML следующим образом:

<DataGridTemplateColumn Header="MyCheckBoxColumnHeader">
    <DataGridTemplateColumn.CellTemplate>
        <DataTemplate>
            <CheckBox HorizontalAlignment="Center" VerticalAlignment="Center" IsChecked="{Binding Path=MyViewModelProperty, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
        </DataTemplate>
    </DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>

Потенциал этого решения очевиден - он только XAML; таким образом, он эффективно воздерживает вас от отягощения вашего кода обратно дополнительной логикой пользовательского интерфейса и помогает поддерживать ваш статус в глазах фанатиков MVVM;).

Ответ 6

Чтобы Константин Салаватов ответил, работайте с AutoGenerateColumns, добавьте обработчик события в DataGrid AutoGeneratingColumn со следующим кодом:

if (e.Column is DataGridCheckBoxColumn && !e.Column.IsReadOnly)
{
    var checkboxFactory = new FrameworkElementFactory(typeof(CheckBox));
    checkboxFactory.SetValue(FrameworkElement.HorizontalAlignmentProperty, HorizontalAlignment.Center);
    checkboxFactory.SetValue(FrameworkElement.VerticalAlignmentProperty, VerticalAlignment.Center);
    checkboxFactory.SetBinding(ToggleButton.IsCheckedProperty, new Binding(e.PropertyName) { UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged });

    e.Column = new DataGridTemplateColumn
        {
            Header = e.Column.Header,
            CellTemplate = new DataTemplate { VisualTree = checkboxFactory },
            SortMemberPath = e.Column.SortMemberPath
        };
}

Это приведет к тому, что все столбцы флажков DataGrid автоматически сгенерированы "одним кликом".

Ответ 7

Я пробовал эти предложения и много других, которых я нашел на других сайтах, но ни один из них не работал у меня. В итоге я создал следующее решение.

Я создал свой собственный унаследованный DataGrid элемент управления и просто добавил к нему этот код:

public class DataGridWithNavigation : Microsoft.Windows.Controls.DataGrid
{
    public DataGridWithNavigation()
    {
        EventManager.RegisterClassHandler(typeof(DataGridCell), 
            DataGridCell.PreviewMouseLeftButtonDownEvent,
            new RoutedEventHandler(this.OnPreviewMouseLeftButtonDown));
    }


    private void OnPreviewMouseLeftButtonDown(object sender, RoutedEventArgs e)
    {
        DataGridCell cell = sender as DataGridCell;
        if (cell != null && !cell.IsEditing && !cell.IsReadOnly)
        {
          DependencyObject obj = FindFirstControlInChildren(cell, "CheckBox");
            if (obj != null)
            {
                System.Windows.Controls.CheckBox cb = (System.Windows.Controls.CheckBox)obj;
                cb.Focus();
                cb.IsChecked = !cb.IsChecked;
            }
        }
    }

    public DependencyObject FindFirstControlInChildren(DependencyObject obj, string controlType)
    {
        if (obj == null)
            return null;

        // Get a list of all occurrences of a particular type of control (eg "CheckBox") 
        IEnumerable<DependencyObject> ctrls = FindInVisualTreeDown(obj, controlType);
        if (ctrls.Count() == 0)
            return null;

        return ctrls.First();
    }

    public IEnumerable<DependencyObject> FindInVisualTreeDown(DependencyObject obj, string type)
    {
        if (obj != null)
        {
            if (obj.GetType().ToString().EndsWith(type))
            {
                yield return obj;
            }

            for (var i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++)
            {
                foreach (var child in FindInVisualTreeDown(VisualTreeHelper.GetChild(obj, i), type))
                {
                    if (child != null)
                    {
                        yield return child;
                    }
                }
            }
        }
        yield break;
    }
}

Что все это делает?

Хорошо, каждый раз, когда мы нажимаем на любую ячейку в нашем DataGrid, мы видим, содержит ли ячейка элемент управления CheckBox внутри него. Если да, то мы установим фокус на этот CheckBox и переключим его.

Это, похоже, работает для меня и является хорошим, легкореализуемым решением.

Неутешительно, что нам нужно писать код, чтобы сделать это. Объяснение того, что первый щелчок мыши (в DataGrid CheckBox) "игнорируется", поскольку WPF использует его для перевода строки в режим редактирования, может звучать логично, но в реальном мире это противоречит тому, как работает любое реальное приложение.

Если пользователь видит флажок на своем экране, они должны иметь возможность щелкнуть по нему один раз, чтобы пометить/отключить его. Конец истории.

Ответ 8

Здесь гораздо более простое решение.

          <DataGridTemplateColumn MinWidth="20" >
                <DataGridTemplateColumn.CellTemplate>
                    <DataTemplate>
                        <Grid>
                            <CheckBox VerticalAlignment="Center" HorizontalAlignment="Center"/>
                        </Grid>
                    </DataTemplate>
                </DataGridTemplateColumn.CellTemplate>
            </DataGridTemplateColumn>

Если вы используете DataGridCheckBoxColumn для реализации, сначала нажмите для фокусировки, второй щелчок должен быть проверен.

Но используя DataGridTemplateColumn для реализации нужно только один клик.

Разница в использовании DataGridComboboxBoxColumn и реализации DataGridTemplateColumn также аналогична.

Ответ 9

Я решил с этим:

<DataGridTemplateColumn>
    <DataGridTemplateColumn.CellTemplate>
        <DataTemplate>
            <Viewbox Height="25">
                <CheckBox IsChecked="{Binding TheProperty, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"/>
            </Viewbox>
        </DataTemplate>
    </DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>

Флажок активен одним кликом!

Ответ 10

Основание на комментарии Джима Адорно и комментарии к его сообщению, это решение с MultiTrigger:

<Style TargetType="DataGridCell">
  <Style.Triggers>
    <MultiTrigger>
      <MultiTrigger.Conditions>
    <Condition Property="IsReadOnly" Value="False" />
    <Condition Property="IsMouseOver" Value="True" />
      </MultiTrigger.Conditions>
      <Setter Property="IsEditing" Value="True" />
    </MultiTrigger>
  </Style.Triggers>
</Style>

Ответ 11

<Style x:Key="StilCelula" TargetType="DataGridCell"> 
<Style.Triggers>
 <Trigger Property="IsMouseOver" Value="True">
   <Setter Property="IsEditing" 
     Value="{Binding RelativeSource={x:Static RelativeSource.Self}, 
     Converter={StaticResource CheckBoxColumnToEditingConvertor}}" />
 </Trigger>
</Style.Triggers>
<Style>
Imports System.Globalization
Public Class CheckBoxColumnToEditingConvertor
    Implements IValueConverter
    Public Function Convert(ByVal value As Object, ByVal targetType As Type, ByVal parameter As Object, ByVal culture As CultureInfo) As Object Implements IValueConverter.Convert
        Try

            Return TypeOf TryCast(value, DataGridCell).Column Is DataGridCheckBoxColumn
        Catch ex As Exception
            Return Visibility.Collapsed
        End Try
    End Function

    Public Function ConvertBack(ByVal value As Object, ByVal targetType As Type, ByVal parameter As Object, ByVal culture As CultureInfo) As Object Implements IValueConverter.ConvertBack
        Throw New NotImplementedException()
    End Function
End Class