Code to check if a cell of a DataGrid is currently edited

后端 未结 4 562
孤街浪徒
孤街浪徒 2020-12-16 01:49

Is there a simple possibility to check if the DataGrid is currently in EditMode (Without to subscribe to BeginningEdit and CellEditEnding)

相关标签:
4条回答
  • 2020-12-16 02:26

    Ok, I havent found a simple solution and no one pointed me to one. The following code can be used to add an attached property IsInEditMode to a DataGrid. Hope it helps someone:

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

    To use it, set on the datagrid the ProcessIsInEditMode- property to true:

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

    Afer that you will have the IsInEditMode-property in sync with the mode of the DataGrid. If you want also the editing cell, change the code in BeginningEdit accoringly.

    0 讨论(0)
  • 2020-12-16 02:34

    I found a shorter workaround (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;
    }
    
    0 讨论(0)
  • 2020-12-16 02:37

    It seems you can also get this information from the items view, namely this works:

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

    I have not confirmed this but most likely you could get these flags in a viewmodel if your bound collection provides an IEditableCollectionView.

    0 讨论(0)
  • 2020-12-16 02:39

    All the answers above using IsEditing on the datagridrow or IsEdititngItem on the IEditableCollectionView are partial answers to me :

    If the user enter edition, then clics on any other cell, the EndEdit event is fired but the DataGridRow has still the property IsEditing to True !!! And if you try to find the DataGridCell responsible, its IsEditingProperty Is always false... I think it's a bug. And to have the desired behaviour, I had to write this Ugly workaround

    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
    

    This basicly force the grid to set IsEditing = false on the datagridrow, when any cell stops editing.

    0 讨论(0)
提交回复
热议问题