2010-07-14 15 views

Respuesta

5

Ok, no he encontrado una solución sencilla y nadie me señaló a uno. El siguiente código se puede usar para agregar una propiedad adjunta IsInEditMode a un DataGrid. Espero que ayude a alguien:

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

Para usarlo, situado en la cuadrícula de datos de la propiedad ProcessIsInEditMode- true:

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

de Afer que va a tener el IsInEditMode-propiedad en sincronía con el modo de la Cuadrícula de datos. Si también desea la celda de edición, cambie el código en BeginningEdit de manera acorde.

+0

Genial, gracias, por mi opinión, debe publicar esto en una conexión a Microsoft y publicar aquí un enlace para que los usuarios puedan votar para implementarlo en la próxima versión. – Shimmy

+0

Sugeriría reemplazar los parámetros obj DependendencyProperty con DataGrid dg, por lo que la propiedad adjunta solo se puede aplicar a objetos del tipo DataGrid. – Shimmy

+0

Tienes razón: lo he cambiado. – HCL

3

He encontrado una solución más corto (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

A veces GetContainerFromIndex no devuelve un valor. No estoy seguro si tiene algo que ver con elementos virtuales/no creados. Por lo tanto, item.IsEditing en GetEditingRow causa una NullReferenceException. Pero de todos modos; esto es algo menor y resolvió mi problema: +1 – Markus

+0

@Markus, si alguna vez encuentra un sln, por favor, póngase en contacto con – Shimmy

7

Parece también se puede obtener esta información de la vista de elementos, es decir, esto funciona:

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

No he confirmado esto, pero lo más probable es que pueda obtener estas banderas en un modelo de vista si su colección encuadernada proporciona un IEditableCollectionView.

0

Todas las respuestas anteriores utilizando IsEditing en el datagridrow o IsEdititngItem en el IEditableCollectionView son respuestas parciales a mí:

Si el usuario introduzca edición, a continuación, clics en cualquier otra célula, se dispara el evento EndEdit pero el DataGridRow tiene todavía la propiedad IsEditing to True !!! Y si intentas encontrar responsable a DataGridCell, su propiedad IsEditingProperty siempre es falsa ... Creo que es un error. Y para tener el comportamiento deseado, que tenía que escribir esta solución feo

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 

Esto básicamente forzar a la red para establecer IsEditing = false en el datagridrow, cuando cualquier célula deja de edición.

Cuestiones relacionadas