2010-07-14 14 views

Répondre

5

Ok, je ne ai pas trouvé une solution simple et personne ne m'a pointé à un. Le code suivant peut être utilisé pour ajouter une propriété attachée IsInEditMode à un DataGrid. Il aide quelqu'un l'espoir:

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

Pour l'utiliser, mettre sur la grille de données de la propriété ProcessIsInEditMode- true:

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

Afer que vous aurez la IsInEditMode-propriété en phase avec le mode de Grille de données. Si vous souhaitez également la cellule d'édition, modifiez le code en BeginningEdit de manière concise.

+0

Très bien, merci, à mon avis, vous devriez le publier dans une connexion à Microsoft et poster ici un lien afin que l'utilisateur puisse voter pour qu'il soit mis en œuvre dans la prochaine version. – Shimmy

+0

Je suggère de remplacer les paramètres obj DependendencyProperty avec DataGrid dg, de sorte que la propriété jointe peut être appliquée uniquement aux objets de type DataGrid. – Shimmy

+0

Vous avez raison - je l'ai changé. – HCL

3

Je trouve une solution plus courte (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

Parfois, GetContainerFromIndex ne renvoie pas de valeur. Je ne suis pas sûr si cela a quelque chose à voir avec des objets virtuels/non créés. Par conséquent item.IsEditing dans GetEditingRow provoque une exception NullReferenceException. Mais peu importe; c'est quelque chose de mineur et vous avez résolu mon problème: +1 – Markus

+0

@Markus devriez-vous jamais trouver un sln à ce que s'il vous plaît buzz dans – Shimmy

7

Il vous semble peut également obtenir cette information de la vue des articles, à savoir cela fonctionne:

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

Je ne l'ai pas confirmé, mais il est très probable que vous puissiez obtenir ces drapeaux dans un viewmodel si votre collection liée fournit un IEditableCollectionView.

0

Toutes les réponses ci-dessus en utilisant IsEditing sur le datagridrow ou IsEdititngItem sur la IEditableCollectionView sont des réponses partielles à moi:

Si l'utilisateur d'entrer édition, puis clics sur une autre cellule, l'événement EndEdit est tiré mais le DataGridRow a Toujours la propriété IsEditing à True !!! Et si vous essayez de trouver le responsable DataGridCell, son IsEditingProperty est toujours faux ... Je pense que c'est un bug. Et d'avoir le comportement souhaité, je devais écrire cette solution truand

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 

Cette force basiquement la grille pour définir IsEditing = false sur le datagridrow, quand toute modification arrête cellule.