Редактирование одним кликом в WPF DataGrid - PullRequest
86 голосов
/ 06 августа 2010

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

Как мне переопределить или реализовать это?

Ответы [ 10 ]

72 голосов
/ 13 августа 2010

Вот как я решил эту проблему:

<DataGrid DataGridCell.Selected="DataGrid_GotFocus" 
          ItemsSource="{Binding Source={StaticResource itemView}}">
    <DataGrid.Columns>
        <DataGridTextColumn Header="Nom" Binding="{Binding Path=Name}"/>
        <DataGridTextColumn Header="Age" Binding="{Binding Path=Age}"/>
    </DataGrid.Columns>
</DataGrid>

Эта DataGrid привязана к CollectionViewSource (содержит фиктивные Person объекты).

Там происходит волшебство: DataGridCell.Selected = "DataGrid_GotFocus" .

Я просто подключаю Выбранное событие ячейки DataGrid и вызываю BeginEdit () для DataGrid.

Вот код для обработчика событий:

private void DataGrid_GotFocus(object sender, RoutedEventArgs e)
{
    // Lookup for the source to be DataGridCell
    if (e.OriginalSource.GetType() == typeof(DataGridCell))
    {
        // Starts the Edit on the row;
        DataGrid grd = (DataGrid)sender;
        grd.BeginEdit(e);
    }
}
38 голосов
/ 05 марта 2013

Ответ от Микаэля Бержерона был для меня хорошим началом, чтобы найти решение, которое работает для меня.Чтобы разрешить редактирование одним щелчком также для ячеек в той же строке, которая уже находится в режиме редактирования, мне пришлось немного ее настроить.Использование ячейки SelectionUnit для меня было невозможным.

Вместо использования события DataGridCell.Selected, которое запускается только при первом нажатии ячейки строки, я использовал событие DataGridCell.GotFocus.

<DataGrid DataGridCell.GotFocus="DataGrid_CellGotFocus" />

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

private void DataGrid_CellGotFocus(object sender, RoutedEventArgs e)
{
    // Lookup for the source to be DataGridCell
    if (e.OriginalSource.GetType() == typeof(DataGridCell))
    {
        // Starts the Edit on the row;
        DataGrid grd = (DataGrid)sender;
        grd.BeginEdit(e);

        Control control = GetFirstChildByType<Control>(e.OriginalSource as DataGridCell);
        if (control != null)
        {
            control.Focus();
        }
    }
}

private T GetFirstChildByType<T>(DependencyObject prop) where T : DependencyObject
{
    for (int i = 0; i < VisualTreeHelper.GetChildrenCount(prop); i++)
    {
        DependencyObject child = VisualTreeHelper.GetChild((prop), i) as DependencyObject;
        if (child == null)
            continue;

        T castedProp = child as T;
        if (castedProp != null)
            return castedProp;

        castedProp = GetFirstChildByType<T>(child);

        if (castedProp != null)
            return castedProp;
    }
    return null;
}
8 голосов
/ 06 августа 2010

От: http://wpf.codeplex.com/wikipage?title=Single-Click%20Editing

XAML:

<!-- SINGLE CLICK EDITING -->
<Style TargetType="{x:Type dg:DataGridCell}">
    <EventSetter Event="PreviewMouseLeftButtonDown" Handler="DataGridCell_PreviewMouseLeftButtonDown"></EventSetter>
</Style>

КОД:

//
// SINGLE CLICK EDITING
//
private void DataGridCell_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
    DataGridCell cell = sender as DataGridCell;
    if (cell != null && !cell.IsEditing && !cell.IsReadOnly)
    {
        if (!cell.IsFocused)
        {
            cell.Focus();
        }
        DataGrid dataGrid = FindVisualParent<DataGrid>(cell);
        if (dataGrid != null)
        {
            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;
                }
            }
        }
    }
}

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;
}
6 голосов
/ 11 марта 2011

Решение из http://wpf.codeplex.com/wikipage?title=Single-Click%20Editing отлично работает для меня, но я включил его для каждой DataGrid, используя стиль, определенный в ResourceDictionary. Чтобы использовать обработчики в словарях ресурсов, вам нужно добавить в него файл с выделенным кодом. Вот как вы это делаете:

Это DataGridStyles.xaml Словарь ресурсов:

<ResourceDictionary x:Class="YourNamespace.DataGridStyles"
            x:ClassModifier="public"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Style TargetType="DataGrid">
        <!-- Your DataGrid style definition goes here -->

        <!-- Cell style -->
        <Setter Property="CellStyle">
            <Setter.Value>
                <Style TargetType="DataGridCell">                    
                    <!-- Your DataGrid Cell style definition goes here -->
                    <!-- Single Click Editing -->
                    <EventSetter Event="PreviewMouseLeftButtonDown"
                             Handler="DataGridCell_PreviewMouseLeftButtonDown" />
                </Style>
            </Setter.Value>
        </Setter>
    </Style>
</ResourceDictionary>

Обратите внимание на атрибут x: Class в корневом элементе. Создайте файл класса. В этом примере это будет DataGridStyles.xaml.cs . Поместите этот код внутри:

using System.Windows.Controls;
using System.Windows;
using System.Windows.Input;

namespace YourNamespace
{
    partial class DataGridStyles : ResourceDictionary
    {

        public DataGridStyles()
        {
          InitializeComponent();
        }

     // The code from the myermian's answer goes here.
}
2 голосов
/ 25 сентября 2016

Я предпочитаю этот путь, основываясь на предложении Душана Кнежевича.нажимаешь вот и все))

<DataGrid.Resources>

    <Style TargetType="DataGridCell" BasedOn="{StaticResource {x:Type DataGridCell}}">
        <Style.Triggers>
                <MultiTrigger>
                    <MultiTrigger.Conditions>
                        <Condition Property="IsMouseOver"
                                   Value="True" />
                        <Condition Property="IsReadOnly"
                                   Value="False" />
                    </MultiTrigger.Conditions>
                    <MultiTrigger.Setters>
                        <Setter Property="IsEditing"
                                Value="True" />
                    </MultiTrigger.Setters>
                </MultiTrigger>
        </Style.Triggers>
    </Style>

</DataGrid.Resources>
1 голос
/ 08 октября 2018

Я ищу редактирование ячейки одним щелчком мыши в MVVM, и это другой способ сделать это.

  1. Добавление поведения в xaml

    <UserControl xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
                 xmlns:myBehavior="clr-namespace:My.Namespace.To.Behavior">
    
        <DataGrid>
            <i:Interaction.Behaviors>
                <myBehavior:EditCellOnSingleClickBehavior/>
            </i:Interaction.Behaviors>
        </DataGrid>
    </UserControl>
    
  2. Класс EditCellOnSingleClickBehavior расширяет System.Windows.Interactivity.Behavior;

    public class EditCellOnSingleClick : Behavior<DataGrid>
    {
        protected override void OnAttached()
        {
            base.OnAttached();
            this.AssociatedObject.LoadingRow += this.OnLoadingRow;
            this.AssociatedObject.UnloadingRow += this.OnUnloading;
        }
    
        protected override void OnDetaching()
        {
            base.OnDetaching();
            this.AssociatedObject.LoadingRow -= this.OnLoadingRow;
            this.AssociatedObject.UnloadingRow -= this.OnUnloading;
        }
    
        private void OnLoadingRow(object sender, DataGridRowEventArgs e)
        {
            e.Row.GotFocus += this.OnGotFocus;
        }
    
        private void OnUnloading(object sender, DataGridRowEventArgs e)
        {
            e.Row.GotFocus -= this.OnGotFocus;
        }
    
        private void OnGotFocus(object sender, RoutedEventArgs e)
        {
            this.AssociatedObject.BeginEdit(e);
        }
    }
    

Вуаля!

1 голос
/ 23 сентября 2016

Я решил это, добавив триггер, который устанавливает для свойства IsEditing объекта DataGridCell значение True, когда мышь находится над ним.Это решило большинство моих проблем.Работает и с комбобоксами.

<Style TargetType="DataGridCell">
     <Style.Triggers>
         <Trigger Property="IsMouseOver" Value="True">
             <Setter Property="IsEditing" Value="True" />
         </Trigger>
     </Style.Triggers>
 </Style>
1 голос
/ 16 сентября 2014

Есть две проблемы с ответом пользователя 2134678.Один очень незначительный и не имеет функционального эффекта.Другое довольно значимое.

Первая проблема заключается в том, что GotFocus фактически вызывается против DataGrid, а не DataGridCell на практике.Спецификатор DataGridCell в XAML является избыточным.

Основная проблема, с которой я нашел ответ, состоит в том, что поведение клавиши Enter нарушено.Ввод должен переместить вас в следующую ячейку ниже текущей ячейки в нормальном поведении DataGrid.Однако то, что на самом деле происходит за кулисами, - событие GotFocus будет вызвано дважды.Однажды текущая ячейка теряет фокус, а однажды новая ячейка приобретает фокус.Но пока BeginEdit вызывается в этой первой ячейке, следующая ячейка никогда не будет активирована.В результате у вас есть редактирование в один клик, но любой, кто буквально не щелкает по сетке, окажется в неудобном положении, и дизайнер пользовательского интерфейса не должен предполагать, что все пользователи используют мыши.(Пользователи клавиатуры могут как-то обойти это, используя Tab, но это все еще означает, что они прыгают через обручи, в которых они не нуждаются.)

Итак, решение этой проблемы?Обработайте событие KeyDown для ячейки, и, если ключ является клавишей Enter, установите флаг, который не позволяет BeginEdit запускать первую ячейку.Теперь клавиша Enter ведет себя так, как и должна.

Для начала добавьте в DataGrid следующий стиль:

<DataGrid.Resources>
    <Style TargetType="{x:Type DataGridCell}" x:Key="SingleClickEditingCellStyle">
        <EventSetter Event="KeyDown" Handler="DataGridCell_KeyDown" />
    </Style>
</DataGrid.Resources>

Примените этот стиль к свойству "CellStyle" столбцов, для которых вы хотитечтобы включить один щелчок.

Затем в коде у вас есть следующее в вашем обработчике GotFocus (обратите внимание, что здесь я использую VB, потому что это то, что наш клиент «запросил сетку данных одним щелчком» хотел в качествеязык разработки):

Private _endEditing As Boolean = False

Private Sub DataGrid_GotFocus(ByVal sender As Object, ByVal e As RoutedEventArgs)
    If Me._endEditing Then
        Me._endEditing = False
        Return
    End If

    Dim cell = TryCast(e.OriginalSource, DataGridCell)

    If cell Is Nothing Then
        Return
    End If

    If cell.IsReadOnly Then
        Return
    End If

    DirectCast(sender, DataGrid).BeginEdit(e)
    .
    .
    .

Затем вы добавляете свой обработчик для события KeyDown:

Private Sub DataGridCell_KeyDown(ByVal sender As Object, ByVal e As KeyEventArgs)
    If e.Key = Key.Enter Then
        Me._endEditing = True
    End If
End Sub

Теперь у вас есть DataGrid, который не изменил какое-либо фундаментальное поведение вне- встроенная реализация и поддерживает редактирование в один клик.

0 голосов
/ 13 марта 2019

Я знаю, что немного опоздал на вечеринку, но у меня возникла та же проблема, и я нашел другое решение:

     public class DataGridTextBoxColumn : DataGridBoundColumn
 {
  public DataGridTextBoxColumn():base()
  {
  }

  protected override FrameworkElement GenerateEditingElement(DataGridCell cell, object dataItem)
  {
   throw new NotImplementedException("Should not be used.");
  }

  protected override FrameworkElement GenerateElement(DataGridCell cell, object dataItem)
  {
   var control = new TextBox();
   control.Style = (Style)Application.Current.TryFindResource("textBoxStyle");
   control.FontSize = 14;
   control.VerticalContentAlignment = VerticalAlignment.Center;
   BindingOperations.SetBinding(control, TextBox.TextProperty, Binding);
    control.IsReadOnly = IsReadOnly;
   return control;
  }
 }

        <DataGrid Grid.Row="1" x:Name="exportData" Margin="15" VerticalAlignment="Stretch" ItemsSource="{Binding CSVExportData}" Style="{StaticResource dataGridStyle}">
        <DataGrid.Columns >
            <local:DataGridTextBoxColumn Header="Sample ID" Binding="{Binding SampleID}" IsReadOnly="True"></local:DataGridTextBoxColumn>
            <local:DataGridTextBoxColumn Header="Analysis Date" Binding="{Binding Date}" IsReadOnly="True"></local:DataGridTextBoxColumn>
            <local:DataGridTextBoxColumn Header="Test" Binding="{Binding Test}" IsReadOnly="True"></local:DataGridTextBoxColumn>
            <local:DataGridTextBoxColumn Header="Comment" Binding="{Binding Comment}"></local:DataGridTextBoxColumn>
        </DataGrid.Columns>
    </DataGrid>

Как видите, я написал свой собственный DataGridTextColumn, унаследовавший все отDataGridBoundColumn.Переопределяя метод GenerateElement и возвращая элемент управления Textbox, метод генерирования редактирующего элемента никогда не вызывается.В другом проекте я использовал это для реализации столбца Datepicker, так что это должно работать и для флажков, и для комбинированных списков.

Это, похоже, не влияет на остальную часть поведения datagrids. По крайней мере, у меня нетне заметил никаких побочных эффектов и не получил никаких отрицательных отзывов.

0 голосов
/ 10 октября 2014
 <DataGridComboBoxColumn.CellStyle>
                        <Style TargetType="DataGridCell">
                            <Setter Property="cal:Message.Attach" 
                            Value="[Event MouseLeftButtonUp] = [Action ReachThisMethod($source)]"/>
                        </Style>
                    </DataGridComboBoxColumn.CellStyle>
 public void ReachThisMethod(object sender)
 {
     ((System.Windows.Controls.DataGridCell)(sender)).IsEditing = true;

 }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...