Как выполнить выбор одного клика в WPF DataGrid? - PullRequest
126 голосов
/ 30 сентября 2010

У меня есть DataGrid с первым столбцом в виде текстового столбца и вторым столбцом в качестве столбца CheckBox.Что я хочу, если я нажму на флажок.Это должно быть проверено.Но для выбора требуется два щелчка, для первого щелчка выбирается ячейка, для второго щелчка устанавливается флажок.Как сделать так, чтобы флажок был отмечен / снят одним щелчком мыши.

Я использую WPF 4.0.Столбцы в DataGrid генерируются автоматически.

Ответы [ 11 ]

167 голосов
/ 01 сентября 2011

Для флажка DataGrid в один клик вы можете просто установить обычный флажок внутри DataGridTemplateColumn и установить UpdateSourceTrigger=PropertyChanged.

<DataGridTemplateColumn.CellTemplate>
    <DataTemplate>
        <CheckBox IsChecked="{Binding Path=IsSelected, UpdateSourceTrigger=PropertyChanged}" />
    </DataTemplate>
</DataGridTemplateColumn.CellTemplate>
55 голосов
/ 02 мая 2011

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

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

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

20 голосов
/ 01 ноября 2013

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

У меня была такая же проблема пару дней назад, и я нашел удивительно короткое решение дляэто (см. этот блог ).По сути, все, что вам нужно сделать, это заменить определение 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;).

16 голосов
/ 01 декабря 2011

Основано на блоге, указанном в ответе Гоблина, но изменено для работы в .NET 4.0 и в режиме выбора строк.

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

XAML:

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

Код-за:

    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;
    }
15 голосов
/ 29 июля 2012

Чтобы ответ Константина Салаватова работал с 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 доступными для редактирования одним щелчком мыши.

9 голосов
/ 28 января 2011

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

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

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

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

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

8 голосов
/ 21 сентября 2015

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

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

Если вы используете DataGridCheckBoxColumn для реализации, первый клик - для фокусировки, второй клик - для проверки.

Но использование *Для реализации 1007 * требуется только один клик.

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

7 голосов
/ 15 марта 2017

Я решил с помощью этого:

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

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

6 голосов
/ 23 апреля 2015

Основываясь на Джим Адорно ответ и комментарии на его пост, это решение с 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>
5 голосов
/ 18 апреля 2018

Еще одно простое решение - добавить этот стиль в DataGridColumn. Тело вашего стиля может быть пустым.

<DataGridCheckBoxColumn>
     <DataGridCheckBoxColumn.ElementStyle>
          <Style TargetType="CheckBox">
           </Style>
     </DataGridCheckBoxColumn.ElementStyle>
</DataGridCheckBoxColumn>
...