【问题标题】:Code to check if a cell of a DataGrid is currently edited检查当前是否编辑了 DataGrid 的单元格的代码
【发布时间】:2011-03-15 22:48:45
【问题描述】:

是否有一种简单的方法可以检查 DataGrid 当前是否处于 EditMode(无需订阅BeginningEdit 和 CellEditEnding)

【问题讨论】:

    标签: wpf wpfdatagrid


    【解决方案1】:

    您似乎也可以从项目视图中获取此信息,即这有效:

    IEditableCollectionView itemsView = stateGrid.Items;
    if (itemsView.IsAddingNew || itemsView.IsEditingItem)
    {
        stateGrid.CommitEdit(DataGridEditingUnit.Row, true);
    }
    

    我尚未确认这一点,但如果您的绑定集合提供 IEditableCollectionView,您很可能可以在视图模型中获得这些标志。

    【讨论】:

    • 使用CollectionViewSource.GetDefaultView(stateGrid.Items)source获取itemsView更安全
    【解决方案2】:

    好的,我还没有找到一个简单的解决方案,也没有人向我指出一个。以下代码可用于将附加属性 IsInEditMode 添加到 DataGrid。希望它可以帮助某人:

    public class DataGridIsInEditModeTracker {
    
        public static bool GetIsInEditMode(DataGrid dataGrid) {
            return (bool)dataGrid.GetValue(IsInEditModeProperty);
        }
    
        private static void SetIsInEditMode(DataGrid dataGrid, bool value) {
            dataGrid.SetValue(IsInEditModePropertyKey, value);
        }
    
        private static readonly DependencyPropertyKey IsInEditModePropertyKey = DependencyProperty.RegisterAttachedReadOnly("IsInEditMode", typeof(bool), typeof(DataGridIsInEditModeTracker), new UIPropertyMetadata(false));
    
        public static readonly DependencyProperty IsInEditModeProperty = IsInEditModePropertyKey.DependencyProperty;
    
    
        public static bool GetProcessIsInEditMode(DataGrid dataGrid) {
            return (bool)dataGrid.GetValue(ProcessIsInEditModeProperty);
        }
    
        public static void SetProcessIsInEditMode(DataGrid dataGrid, bool value) {
            dataGrid.SetValue(ProcessIsInEditModeProperty, value);
        }
    
    
        public static readonly DependencyProperty ProcessIsInEditModeProperty =
            DependencyProperty.RegisterAttached("ProcessIsInEditMode", typeof(bool), typeof(DataGridIsInEditModeTracker), new FrameworkPropertyMetadata(false, delegate(DependencyObject d,DependencyPropertyChangedEventArgs e) {
    
                DataGrid dataGrid = d as DataGrid;
                if (null == dataGrid) {
                    throw new InvalidOperationException("ProcessIsInEditMode can only be used with instances of the DataGrid-class");
                }
                if ((bool)e.NewValue) {
                    dataGrid.BeginningEdit += new EventHandler<DataGridBeginningEditEventArgs>(dataGrid_BeginningEdit);
                    dataGrid.CellEditEnding += new EventHandler<DataGridCellEditEndingEventArgs>(dataGrid_CellEditEnding);
                } else {
                    dataGrid.BeginningEdit -= new EventHandler<DataGridBeginningEditEventArgs>(dataGrid_BeginningEdit);
                    dataGrid.CellEditEnding -= new EventHandler<DataGridCellEditEndingEventArgs>(dataGrid_CellEditEnding);
                }
            }));
    
        static void dataGrid_CellEditEnding(object sender, DataGridCellEditEndingEventArgs e) {            
            SetIsInEditMode((DataGrid)sender,false);
        }
    
        static void dataGrid_BeginningEdit(object sender, DataGridBeginningEditEventArgs e) {
            SetIsInEditMode((DataGrid)sender, true);
        }                  
    }
    

    要使用它,请将数据网格上的 ProcessIsInEditMode- 属性设置为 true:

    <DataGrid local:DataGridIsInEditModeTracker.ProcessIsInEditMode="True" ..  other properties ..>
    

    您将拥有与 DataGrid 的模式同步的 IsInEditMode 属性。 如果您还想要编辑单元格,请相应更改BeginningEdit中的代码。

    【讨论】:

    • 太好了,谢谢,我认为您应该在与 Microsoft 的连接中发布此内容,并在此处发布链接,以便用户投票支持它在即将推出的版本中开箱即用。跨度>
    • 我建议将 DependendencyProperty obj 参数替换为 DataGrid dg,因此附加属性只能应用于 DataGrid 类型的对象。
    • 如何确保在 XAML 等中声明的其他处理程序之前到达此行为的处理程序?
    • 我找到了,很简单,我用的是PreparingCellForEdit事件,它是在BeginningEdit事件之后引发的。
    【解决方案3】:

    我找到了一个更短的解决方法(VB.NET/C#):

    VB.NET

    <Extension>
    Public Function GetContainerFromIndex(Of TContainer As DependencyObject) _
        (ByVal itemsControl As ItemsControl, ByVal index As Integer) As TContainer
      Return DirectCast(
        itemsControl.ItemContainerGenerator.ContainerFromIndex(index), TContainer)
    End Function
    
    <Extension>
    Public Function IsEditing(ByVal dataGrid As DataGrid) As Boolean
      Return dataGrid.GetEditingRow IsNot Nothing
    End Function
    
    <Extension>
    Public Function GetEditingRow(ByVal dataGrid As DataGrid) As DataGridRow
      Dim sIndex = dataGrid.SelectedIndex
      If sIndex >= 0 Then
        Dim selected = dataGrid.GetContainerFromIndex(Of DataGridRow)(sIndex)
        If selected.IsEditing Then Return selected
      End If
    
      For i = 0 To dataGrid.Items.Count - 1
        If i = sIndex Then Continue For
        Dim item = dataGrid.GetContainerFromIndex(Of DataGridRow)(i)
        If item.IsEditing Then Return item
      Next
    
      Return Nothing
    End Function
    

    C#:

    public static TContainer GetContainerFromIndex<TContainer>
      (this ItemsControl itemsControl, int index)
        where TContainer : DependencyObject
    {
      return (TContainer)
        itemsControl.ItemContainerGenerator.ContainerFromIndex(index);
    }
    
    public static bool IsEditing(this DataGrid dataGrid)
    {
      return dataGrid.GetEditingRow() != null;
    }
    
    public static DataGridRow GetEditingRow(this DataGrid dataGrid)
    {
      var sIndex = dataGrid.SelectedIndex;
      if (sIndex >= 0)
      {
        var selected = dataGrid.GetContainerFromIndex<DataGridRow>(sIndex);
        if (selected.IsEditing) return selected;
      }
    
      for (int i = 0; i < dataGrid.Items.Count; i++)
      {
        if (i == sIndex) continue;
        var item = dataGrid.GetContainerFromIndex<DataGridRow>(i);
        if (item.IsEditing) return item;
      }
    
      return null;
    }
    

    【讨论】:

    • 有时 GetContainerFromIndex 不返回值。我不确定它是否与虚拟/未创建的项目有关。因此 GetEditingRow 中的 item.IsEditing 会导致 NullReferenceException。但无论如何;这是小事,你解决了我的问题:+1
    • @Markus 如果你能找到一个 sln 请在里面留言
    【解决方案4】:

    以上所有在 datagridrow 上使用 IsEditing 或在 IEditableCollectionView 上使用 IsEdititngItem 的答案都是对我的部分答案:

    如果用户输入版本,然后单击任何其他单元格,则会触发 EndEdit 事件,但 DataGridRow 仍然将属性 IsEditing 设置为 True !!!如果你试图找到负责的 DataGridCell,它的 IsEditingProperty 总是假的...... 我认为这是一个错误。为了获得理想的行为,我必须编写这个丑陋的解决方法

    Public Shared ReadOnly ForceEndEditProp As DependencyProperty =
            DependencyProperty.RegisterAttached("ForceEndEdit", GetType(Boolean),
            GetType(DataGridEditing), New PropertyMetadata(False, AddressOf ForceEndEditChanged))
    
    Protected Shared Sub ForceEndEditChanged(d As DependencyObject, e As DependencyPropertyChangedEventArgs)
        Dim g As DataGrid = TryCast(d, DataGrid)
        If g Is Nothing Then Return
        ''IsCommiting prevents a StackOverflow ...
        Dim IsCommiting As Boolean = False
        AddHandler g.CellEditEnding, Sub(s, e1)
                                         If IsCommiting Then Return
                                         IsCommiting = True
                                         g.CommitEdit(DataGridEditingUnit.Row, True)
                                         IsCommiting = False
                                     End Sub
    End Sub
    
    Public Shared Function GetForceEndEdit(o As DependencyObject) As Boolean
        Return o.GetValue(ForceEndEditProp)
    End Function
    
    Public Shared Sub SetForceEndEdit(ByVal o As DependencyObject, ByVal value As Boolean)
        o.SetValue(ForceEndEditProp, value)
    End Sub
    

    当任何单元格停止编辑时,这基本上会强制网格在 datagridrow 上设置 IsEditing = false。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-05-30
      • 1970-01-01
      • 2011-11-27
      • 1970-01-01
      • 1970-01-01
      • 2022-11-10
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多