2010-08-06 168 views
70

我希望用户能够将单元格置于编辑模式,并通过单击高亮显示单元格所在的行。默认情况下,这是双击。我如何重写或实现这个?我在谷歌搜索,Codeplex的答案不适合我。在WPF DataGrid中单击编辑

我对WPF和一般编码都很陌生,所以一个简单的答案会更好。

+0

您是否使用WPF工具包中找到的DataGrid? – 2010-08-06 19:06:58

+4

您能否给我们提供一些关于您尝试过的以及它不起作用的更多信息? – 2010-08-06 19:19:53

回答

7

来源: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; 
} 
+1

这在某些情况下不起作用,而Micael Bergerons解决方案则更为复杂。 – SwissCoder 2010-09-22 09:47:51

+0

对我来说,这几乎就是解决方案。我需要添加一个“PreviewMouseLeftButtonUp”事件处理程序,并在那里完全相同的代码。 – 2011-03-16 01:39:44

+0

一旦你有组合框,这也不起作用。预览点击会在组合框的弹出框中看到点击,然后cell.focus调用将所有内容都拧紧。最简单的修复方法是添加一个查看鼠标事件原始来源的部分,使用FindVisualParent来查看它是否在数据网格中。如果没有,不要做其他的工作。 – 2011-05-09 23:36:35

59

这是我如何解决这个问题:

<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单元格的选定事件,并在DataGrid上调用BeginEdit()。

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

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

{享受}

+4

您可以通过将DataGrid上的'SelectionUnit'属性设置为'Cell'来解决已经选择的行问题。 – 2012-07-25 21:45:54

+2

好东西!但它似乎没有在复选框上工作... – Jan 2012-12-26 13:24:51

+0

假设我在我的DataGridCell中有一个TextBox。在我调用'grd.BeginEdit(e)'后,我希望该单元格中的TextBox具有焦点。我怎样才能做到这一点?我试图在DataGridCell和DataGrid上调用FindName(“txtBox”)',但它对我而言返回null。 – user1214135 2013-01-10 19:17:00

6

http://wpf.codeplex.com/wikipage?title=Single-Click%20Editing该解决方案为我工作不错,但我用在限定的风格,使得它为每一个数据网格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:在根元素类属性。 创建一个类文件。在这个例子中,它将是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. 
} 
32

从米卡埃尔伯杰龙答案是一个良好的开端,我找到一个解决方案这就是我的工作。要允许单击也编辑同一行中已经处于编辑模式的单元格,我必须稍微调整一下。使用SelectionUnit Cell对我来说不是一种选择。

而不是使用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; 
} 
+3

复选框似乎不适合我?我仍然需要双击它们 – 2015-12-02 08:46:22

+0

事实上,不适用于复选框 – 2017-01-23 12:54:26

1

有两个问题用user2134678的答案。一个是非常小的,没有功能效果。另一个是相当重要的。

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

我在答案中发现的主要问题是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单单击编辑。

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

} 
1

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

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

不起作用......只要鼠标离开单元格,它就会失去编辑。所以你1)点击你想编辑的单元格。 2)将鼠标移开3)开始输入。您的输入不起作用,因为单元格不再处于编辑模式。 – Skarsnik 2017-02-13 00:26:29

2

我更喜欢这种方式根据DušanKnež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> 
+0

如果组合框被用作编辑模板,这不起作用,我会假设其他人喜欢复选框捕获鼠标事件也会中断 – Steve 2016-11-18 02:48:23