【问题标题】:Single click edit in WPF DataGrid在 WPF DataGrid 中单击编辑
【发布时间】:2011-03-26 12:01:49
【问题描述】:

我希望用户能够将单元格置于编辑模式并通过单击突出显示单元格所在的行。默认情况下,这是双击。

我如何覆盖或实现它?

【问题讨论】:

  • 您在使用 WPF 工具包中的 DataGrid 吗?
  • 您是否可以向我们提供更多信息,说明您尝试过什么以及它是如何不起作用的?

标签: c# .net wpf events xaml


【解决方案1】:

其中几个答案以及this blog post 启发了我,但每个答案都留下了一些不足之处。我结合了它们中最好的部分,并提出了这个相当优雅的解决方案,它似乎可以完全正确地获得用户体验。

这使用了一些 C# 9 语法,尽管您可能需要在项目文件中进行设置,但它在任何地方都可以正常工作:

<LangVersion>9</LangVersion>

首先,我们将点击次数从 3 次减少到 2 次:

将此类添加到您的项目中:

public static class WpfHelpers
{
    internal static void DataGridPreviewMouseLeftButtonDownEvent(object sender, RoutedEventArgs e)
    {
        // The original source for this was inspired by https://softwaremechanik.wordpress.com/2013/10/02/how-to-make-all-wpf-datagrid-cells-have-a-single-click-to-edit/
        DataGridCell? cell = e is MouseButtonEventArgs { OriginalSource: UIElement clickTarget } ? FindVisualParent<DataGridCell>(clickTarget) : null;
        if (cell is { IsEditing: false, IsReadOnly: false })
        {
            if (!cell.IsFocused)
            {
                cell.Focus();
            }

            if (FindVisualParent<DataGrid>(cell) is DataGrid dataGrid)
            {
                if (dataGrid.SelectionUnit != DataGridSelectionUnit.FullRow)
                {
                    if (!cell.IsSelected)
                    {
                        cell.IsSelected = true;
                    }
                }
                else
                {
                    if (FindVisualParent<DataGridRow>(cell) is DataGridRow { IsSelected: false } row)
                    {
                        row.IsSelected = true;
                    }
                }
            }
        }
    }

    internal static T? GetFirstChildByType<T>(DependencyObject prop)
        where T : DependencyObject
    {
        int count = VisualTreeHelper.GetChildrenCount(prop);
        for (int i = 0; i < count; i++)
        {
            if (VisualTreeHelper.GetChild(prop, i) is DependencyObject child)
            {
                T? typedChild = child as T ?? GetFirstChildByType<T>(child);
                if (typedChild is object)
                {
                    return typedChild;
                }
            }
        }

        return null;
    }

    private static T? FindVisualParent<T>(UIElement element)
        where T : UIElement
    {
        UIElement? parent = element;
        while (parent is object)
        {
            if (parent is T correctlyTyped)
            {
                return correctlyTyped;
            }

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

        return null;
    }
}

将此添加到您的 App.xaml.cs 文件中:

protected override void OnStartup(StartupEventArgs e)
{
    base.OnStartup(e);

    EventManager.RegisterClassHandler(
        typeof(DataGrid),
        DataGrid.PreviewMouseLeftButtonDownEvent,
        new RoutedEventHandler(WpfHelpers.DataGridPreviewMouseLeftButtonDownEvent));
}

然后我们从 2 得到 1:

将此添加到包含DataGrid的页面后面的代码中:

private void TransactionDataGrid_PreparingCellForEdit(object sender, DataGridPreparingCellForEditEventArgs e)
{
    WpfHelpers.GetFirstChildByType<Control>(e.EditingElement)?.Focus();
}

并将其连接起来(在 XAML 中):PreparingCellForEdit="TransactionDataGrid_PreparingCellForEdit"

【讨论】:

  • 这种方法在遇到模板列之前效果很好。它的行为将被打破。在关注另一行之前,它不会删除其他行上的突出显示。不幸的是,我还不足以理解为什么。但我认为我已经将其范围缩小到一个结论,即这种方法会以某种方式干扰 DataGrid 处理焦点的方式。因为如果我不让它专注于模板列,那么它就可以正常工作。
  • 我几乎只使用模板列,没有遇到您所描述的问题。
  • 这很奇怪。我希望那时我做错了什么。因为这个解决方案非常优雅。我创建了一个小项目来重新创建问题。我希望你能告诉我我做错了什么。这是一个带有 2 列的简单 DataGrid。一个文本列和一个包含 3 个按钮的模板列。程序启动时,尝试关注第二行的文本列,然后单击第一行的按钮。您会看到它突出显示了两行。 drive.google.com/file/d/1YLdK_Rq5hRrd-hv00AQivf2gyuysIOMH/…
  • 嗯...我从未在模板列中使用 buttons 进行过测试。我下载了您的代码,您似乎已经正确完成了我的所有步骤,并且我看到您的网格的行为与第一列的预期相同。这只是导致它行为不端的按钮。 :(
【解决方案2】:

我稍微修改了 Dušan Knežević 的解决方案

<DataGrid.Resources>
   <Style x:Key="ddlStyle" TargetType="DataGridCell">
      <Style.Triggers>
         <Trigger Property="IsMouseOver" Value="True">
            <Setter Property="IsEditing" Value="True" />
         </Trigger>
      </Style.Triggers>
    </Style>
</DataGrid.Resources>

并将样式应用到我的愿望列

<DataGridComboBoxColumn CellStyle="{StaticResource ddlStyle}">

【讨论】:

    【解决方案3】:

    更新

    如果您对单元格保持文本框感到满意,这是一个简单的解决方案(不区分编辑模式和非编辑模式)。这种方式单击编辑可以开箱即用。这也适用于组合框和按钮等其他元素。否则使用更新下方的解决方案。

    <DataGridTemplateColumn Header="My Column header">
       <DataGridTemplateColumn.CellTemplate>
          <DataTemplate>
             <TextBox Text="{Binding MyProperty } />
          </DataTemplate>
       </DataGridTemplateColumn.CellTemplate>
    </DataGridTemplateColumn>
    

    更新结束

    咆哮

    我尝试了在这里和谷歌上找到的所有内容,甚至尝试创建自己的版本。但是每个答案/解决方案主要适用于文本框列,但不适用于所有其他元素(复选框、组合框、按钮列),甚至破坏了其他元素列或有一些其他副作用。感谢微软让 datagrid 表现得如此丑陋,并迫使我们创建这些黑客。因此,我决定制作一个可以直接将样式应用于文本框列而不影响其他列的版本。

    特点

    • 后面没有代码。 MVVM 友好。
    • 它在单击相同或不同行中的不同文本框单元格时有效。
    • TAB 和 ENTER 键有效。
    • 不影响其他列。

    来源

    我使用了这个解决方案和@m-y 的答案并将它们修改为附加行为。 http://wpf-tutorial-net.blogspot.com/2016/05/wpf-datagrid-edit-cell-on-single-click.html

    如何使用

    添加此样式。 当您将一些 fancy styles 用于您的数据网格并且您不想丢失它们时,BasedOn 很重要。

    <Window.Resources>
        <Style x:Key="SingleClickEditStyle" TargetType="{x:Type DataGridCell}" BasedOn="{StaticResource {x:Type DataGridCell}}">
            <Setter Property="local:DataGridTextBoxSingleClickEditBehavior.Enable" Value="True" />
        </Style>
    </Window.Resources>
    

    将带有CellStyle 的样式应用于您的每个DataGridTextColumns,如下所示:

    <DataGrid ItemsSource="{Binding MyData}" AutoGenerateColumns="False">
        <DataGrid.Columns>
            <DataGridTextColumn Header="My Header" Binding="{Binding Comment}" CellStyle="{StaticResource SingleClickEditStyle}" />         
        </DataGrid.Columns>
    </DataGrid>
    

    现在将这个类添加到与您的 MainViewModel 相同的命名空间(或不同的命名空间。但是您将需要使用除 local 之外的其他命名空间前缀)。欢迎来到附加行为的丑陋样板代码世界。

    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Media;
    
    namespace YourMainViewModelNameSpace
    {
        public static class DataGridTextBoxSingleClickEditBehavior
        {
            public static readonly DependencyProperty EnableProperty = DependencyProperty.RegisterAttached(
                "Enable",
                typeof(bool),
                typeof(DataGridTextBoxSingleClickEditBehavior),
                new FrameworkPropertyMetadata(false, OnEnableChanged));
    
    
            public static bool GetEnable(FrameworkElement frameworkElement)
            {
                return (bool) frameworkElement.GetValue(EnableProperty);
            }
    
    
            public static void SetEnable(FrameworkElement frameworkElement, bool value)
            {
                frameworkElement.SetValue(EnableProperty, value);
            }
    
    
            private static void OnEnableChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
            {
                if (d is DataGridCell dataGridCell)
                    dataGridCell.PreviewMouseLeftButtonDown += DataGridCell_PreviewMouseLeftButtonDown;
            }
    
    
            private static void DataGridCell_PreviewMouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
            {
                EditCell(sender as DataGridCell, e);
            }
    
            private static void EditCell(DataGridCell dataGridCell, RoutedEventArgs e)
            {
                if (dataGridCell == null || dataGridCell.IsEditing || dataGridCell.IsReadOnly)
                    return;
    
                if (dataGridCell.IsFocused == false)
                    dataGridCell.Focus();
    
                var dataGrid = FindVisualParent<DataGrid>(dataGridCell);
                dataGrid?.BeginEdit(e);
            }
    
    
            private static T FindVisualParent<T>(UIElement element) where T : UIElement
            {
                var parent = VisualTreeHelper.GetParent(element) as UIElement;
    
                while (parent != null)
                {
                    if (parent is T parentWithCorrectType)
                        return parentWithCorrectType;
    
                    parent = VisualTreeHelper.GetParent(parent) as UIElement;
                }
    
                return null;
            }
        }
    }
    

    【讨论】:

      【解决方案4】:

      我是这样解决这个问题的:

      <DataGrid DataGridCell.Selected="DataGridCell_Selected" 
                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="DataGridCell_Selected"

      我只是简单地挂钩 DataGrid 单元格的 Selected 事件,然后在 DataGrid 上调用 BeginEdit()。

      这是事件处理程序的代码:

      private void DataGridCell_Selected(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);
          }
      }
      

      【讨论】:

      • 您可以通过将 DataGrid 上的 SelectionUnit 属性设置为 Cell 来解决已经选择的行问题。
      • 假设我的 DataGridCell 中有一个 TextBox。在我调用grd.BeginEdit(e) 之后,我希望该单元格中的 TextBox 具有焦点。我怎样才能做到这一点?我尝试在 DataGridCell 和 DataGrid 上调用 FindName("txtBox"),但它为我返回 null。
      • GotFocus="DataGrid_GotFocus" 好像不见了?
      • 这很好用,但我不建议这样做。我在我的项目中使用了它,并决定回滚到标准的 DG 行为。将来,当您的 DG 增长并变得复杂时,您会遇到验证、添加新行和其他奇怪行为的问题。
      • @white.zaz 在您回滚到标准 DG 行为后是否满意?因为问这个问题的主要原因是标准 DG 功能中的编辑对用户不友好,因为在 DG 进入编辑模式之前需要点击太多次。
      【解决方案5】:

      http://wpf.codeplex.com/wikipage?title=Single-Click%20Editing 的解决方案对我来说效果很好,但我使用 ResourceDictionary 中定义的样式为每个 DataGrid 启用了它。要在资源字典中使用处理程序,您需要向其中添加代码隐藏文件。以下是你的做法:

      这是一个 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.
      }
      

      【讨论】:

      • 链接失效(15 个字符限制)
      【解决方案6】:

      我知道我参加聚会有点晚了,但我遇到了同样的问题并想出了一个不同的解决方案:

           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 方法并在此处返回一个文本框控件,永远不会调用用于生成编辑元素的方法。 在另一个项目中,我使用它来实现 Datepicker 列,因此这也适用于复选框和组合框。

      这似乎不会影响数据网格的其他行为。至少到目前为止我没有注意到任何副作用,也没有收到任何负面反馈。

      【讨论】:

        【解决方案7】:

        我在 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);
              }
          }
          

        瞧!

        【讨论】:

        • 这对我的用例来说是一个很好的解决方案,但我确实修改了OnGotFocus,否则,单击单元格上的 Enter 将再次触发此方法并且不提交编辑:var row = sender as Row; if (!row.IsEditing) this.AssociatedObject.BeginEdit(e);
        【解决方案8】:

        根据 Dušan Knežević 的建议,我更喜欢这种方式。你点击就可以了))

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

        【讨论】:

        • 如果将组合框用作编辑模板,这将不起作用,我会假设其他像捕获鼠标事件的复选框也会中断
        • 对我来说,这适用于组合框列,但“新项目行”(最后一行)的文本框有一个奇怪的行为:首先单击我获得输入焦点并可以输入内容。当我将鼠标移出单元格,文本框的值消失了。进一步键入时,新输入的文本会正确保存(它会根据需要创建一个新条目)。即使使用 ComboboxColumn 也会发生这种情况。
        • 最初看起来工作正常,但完全搞砸了我的数据网格,当我尝试排序时,所有这些值都消失了,没有这段代码,一切都可以正常进行排序。
        • 也不再触发行验证
        【解决方案9】:
         <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;
        
         }
        

        【讨论】:

          【解决方案10】:

          我通过添加一个触发器解决了这个问题,当鼠标悬停在 DataGridCell 上时,它将 IsEditing 属性设置为 True。它解决了我的大部分问题。它也适用于组合框。

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

          【讨论】:

          • 不起作用...一旦鼠标离开单元格,它就会失去编辑。所以你 1) 左键单击要编辑的单元格。 2) 将鼠标移开 3) 开始打字。您的输入无效,因为单元格不再处于编辑模式。
          • 对我也不起作用。阻止为我编辑文本框
          • 但是这种方法有一个问题,我已经锁定了第一列进行编辑,使用这种方法,这使得第一列也可以编辑!
          【解决方案11】:

          user2134678 的回答有两个问题。一种是非常轻微的,没有功能作用。另一个相当重要。

          第一个问题是 GotFocus 实际上是针对 DataGrid 调用的,而不是实际中的 DataGridCell。 XAML 中的 DataGridCell 限定符是多余的。

          我发现答案的主要问题是 Enter 键的行为被破坏了。 Enter 应该将您移动到正常 DataGrid 行为中当前单元格下方的下一个单元格。然而,在幕后实际发生的是 GotFocus 事件将被调用两次。一次是当前单元格失去焦点,一次是新单元格获得焦点。但只要在第一个单元格上调用 BeginEdit,就永远不会激活下一个单元格。结果是您可以一键编辑,但任何不按字面单击网格的人都会感到不便,并且用户界面设计人员不应假设所有用户都在使用鼠标。 (键盘用户可以通过使用 Tab 来绕过它,但这仍然意味着他们正在跳过他们不应该这样做的障碍。)

          那么这个问题的解决方案呢?处理单元格的 KeyDown 事件,如果 Key 是 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。

          【讨论】:

            【解决方案12】:

            Micael Bergeron 的回答是我找到适合我的解决方案的良好开端。为了允许对已经处于编辑模式的同一行中的单元格进行单击编辑,我不得不对其进行一些调整。使用 SelectionUnit 单元格对我来说是没有选择的。

            我使用 DataGridCell.GotFocus 事件,而不是使用仅在第一次单击行的单元格时触发的 DataGridCell.Selected 事件。

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

            【讨论】:

            • 复选框似乎对我不起作用?我仍然需要双击它们
            【解决方案13】:

            发件人: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;
            }
            

            【讨论】:

            • 这在某些情况下不起作用,而且它比 Micael Bergerons 解决方案更复杂。
            • 对我来说,这几乎就是解决方案。我需要添加一个“PreviewMouseLeftButtonUp”事件处理程序并放在那里完全相同的代码。
            • 一旦你有一个组合框,这也不起作用。预览点击看到组合框的弹出点击,然后 cell.focus 调用搞砸了一切。最简单的解决方法是添加一个查看鼠标事件原始源的部分,在该部分上使用 FindVisualParent 来查看它是否在数据网格内。如果没有,不要做任何其他工作。
            猜你喜欢
            • 1970-01-01
            • 2016-05-11
            • 2012-12-04
            • 1970-01-01
            • 2014-04-24
            • 2021-02-22
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多