2010-07-14 13 views

risposta

5

Ok, io ho mai trovato una soluzione semplice e nessuno mi ha indicato a uno. Il seguente codice può essere utilizzato per aggiungere una proprietà associata IsInEditMode a un DataGrid. Speranza che aiuta qualcuno:

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

Per usarlo, impostato sul datagrid proprietà ProcessIsInEditMode- true:

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

Afer che si avrà l'IsInEditMode-property in sincronia con la modalità del DataGrid. Se si desidera anche la cella di modifica, modificare il codice in BeginningEdit in modo accidentale.

+0

Grande, grazie, per la mia opinione dovresti postare questo in una connessione a Microsoft e postare qui un link in modo che l'utente possa votare perché possa essere implementato out-the-box nella prossima versione. – Shimmy

+0

Suggerirei di sostituire i parametri obj di DependendencyProperty con DataGrid dg, quindi la proprietà associata può essere applicata solo agli oggetti di tipo DataGrid. – Shimmy

+0

Hai ragione - L'ho cambiato. – HCL

3

ho trovato una soluzione più corta (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 volte, GetContainerFromIndex non restituisce un valore. Non sono sicuro che abbia qualcosa a che fare con oggetti virtuali/non creati. Pertanto item.IsEditing in GetEditingRow causa una eccezione NullReferenceException. Ma in ogni caso; questa è una cosa di poco conto e hai risolto il mio problema: +1 – Markus

+0

@Markus se dovessi mai trovare una sln per favore ronzio – Shimmy

7

Sembra è anche possibile ottenere queste informazioni dal articoli, cioè questo funziona:

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

Non l'ho confermato, ma molto probabilmente potresti ottenere questi flag in un viewmodel se la tua collezione associata fornisce un IEditableCollectionView.

0

Tutte le risposte di cui sopra utilizzando IsEditing sul DataGridRow o IsEdititngItem sul IEditableCollectionView sono risposte parziali a me:

Se l'utente entra edizione, quindi clics su qualsiasi altra cella, l'evento EndEdit viene licenziato, ma il DataGridRow ha ancora la proprietà IsEditing to True !!! E se si tenta di trovare il DataGridCell responsabile, IsEditingProperty è sempre falso ... Penso che sia un bug. E di avere il comportamento desiderato, ho dovuto scrivere questa soluzione Scarsa

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 

Questo fondamentalmente forzare la griglia per impostare IsEditing = false sul DataGridRow, quando una cella ferma editing.

Problemi correlati