2010-11-21 2 views
1

Je veux, que si une cellule/ligne passe en mode édition, alors, si l'utilisateur tente de sélectionner une ligne différente, il devrait essayer de valider cette ligne, si la ligne n'est pas validée correctement, elle doit refuser la demande de sélection et la ligne d'édition doit rester sélectionnée et en mode d'édition.Existe-t-il un moyen d'empêcher un utilisateur de sélectionner une autre ligne lorsque DataGrid est en mode édition?

Avez-vous de l'expérience avec une bonne aide pour cela? une bonne solution de contournement?

NOTE: Je suis aux prises avec ce problème depuis longtemps et j'ai déjà de l'expérience, alors s'il vous plaît ne postez que des exemples de travail, pas des pensées aléatoires.

Répondre

1

Le code ci-dessous comprend l'extension de here (code normalisé pour s'adapter à l'écran StackOverflow, désolé).

Imports System.ComponentModel 
Imports System.Windows.Threading 
Namespace Components 


    Public NotInheritable Class DataGridSelectionChangingBehavior 

    Public Shared Function GetEnableSelectionChanging(
     ByVal element As DataGrid) As Boolean 
     If element Is Nothing Then Throw New ArgumentNullException("element") 
     Return element.GetValue(EnableSelectionChangingProperty) 
    End Function 
    Public Shared Sub SetEnableSelectionChanging(
     ByVal element As DataGrid, ByVal value As Boolean) 
     If element Is Nothing Then Throw New ArgumentNullException("element") 
     element.SetValue(EnableSelectionChangingProperty, value) 
    End Sub 
    Public Shared ReadOnly EnableSelectionChangingProperty As _ 
     DependencyProperty = 
     DependencyProperty.RegisterAttached("EnableSelectionChanging", 
     GetType(Boolean), 
     GetType(DataGridSelectionChangingBehavior), 
     New FrameworkPropertyMetadata(False, 
      New PropertyChangedCallback(
      AddressOf EnableSelectionChanging_PropertyChanged))) 

    Public Shared Sub AddSelectionChangingHandler(
     ByVal element As DataGrid, handler As SelectionChangingEventHandler) 
     If element IsNot Nothing Then _ 
     element.AddHandler(
      DataGridSelectionChangingBehavior.SelectionChangingEvent, handler) 
    End Sub 
    Public Shared Sub RemoveSelectionChangingHandler(
     ByVal element As DataGrid, handler As SelectionChangingEventHandler) 
     If element IsNot Nothing Then _ 
     element.RemoveHandler(
      DataGridSelectionChangingBehavior.SelectionChangingEvent, handler) 
    End Sub 
    Public Shared ReadOnly SelectionChangingEvent As RoutedEvent = 
     EventManager.RegisterRoutedEvent("SelectionChanging", 
     RoutingStrategy.Bubble, 
     GetType(SelectionChangingEventHandler), 
     GetType(DataGridSelectionChangingBehavior)) 

    Private Shared Sub EnableSelectionChanging_PropertyChanged(
     ByVal sender As Object, ByVal e As DependencyPropertyChangedEventArgs) 
     Dim dataGrid = DirectCast(sender, DataGrid) 
     If CBool(e.NewValue) Then 
     AddHandler dataGrid.PreparingCellForEdit, 
      AddressOf DataGrid_PreparingCellForEdit 
     AddHandler dataGrid.SelectionChanged, 
      AddressOf DataGrid_SelectionChanged 
     Else 
     RemoveHandler dataGrid.PreparingCellForEdit, 
      AddressOf DataGrid_PreparingCellForEdit 
     RemoveHandler dataGrid.SelectionChanged, 
      AddressOf DataGrid_SelectionChanged 
     RecentColumn.Remove(dataGrid) 
     End If 
    End Sub 

    Private Shared Sub DataGrid_SelectionChanged(
     ByVal sender As Object, ByVal e As SelectionChangedEventArgs) 
     If e.RemovedItems.Count = 0 Then Exit Sub 
     Dim dataGrid = DirectCast(sender, DataGrid) 
     Dim removed = e.RemovedItems(0) 
     Dim row = dataGrid.GetContainerFromItem(Of DataGridRow)(removed) 
     Dim scea As New SelectionChangingEventArgs(row, 
     DataGridSelectionChangingBehavior.SelectionChangingEvent, dataGrid) 
     dataGrid.RaiseEvent(scea) 

     If scea.Cancel Then 
     RemoveHandler dataGrid.SelectionChanged, 
      AddressOf DataGrid_SelectionChanged 
     Dim operation = dataGrid.Dispatcher.BeginInvoke(
      Sub() 
      dataGrid.SelectedItem = removed 
      Dim column As DataGridColumn = Nothing 
      If RecentColumn.TryGetValue(dataGrid, column) Then 
       Dim cellsPanel = 
       row.GetVisualDescendant(Of DataGridCellsPanel)(). 
        Children.Cast(Of DataGridCell)() 
       Dim recentCell = 
       If(cellsPanel.SingleOrDefault(
        Function(cell) cell.Column Is column), 
        cellsPanel.FirstOrDefault) 
       If recentCell IsNot Nothing Then 
       recentCell.IsEditing = True 
       Keyboard.Focus(recentCell) 
       End If 
      End If 
      End Sub, 
      DispatcherPriority.ContextIdle) 

     AddHandler operation.Completed, 
      Sub(s, ea) AddHandler dataGrid.SelectionChanged, 
      AddressOf DataGrid_SelectionChanged 
     End If 
    End Sub 

    Private Shared m_RecentColumn As Dictionary(Of DataGrid, DataGridColumn) 
    Public Shared ReadOnly Property RecentColumn() As Dictionary(Of DataGrid, 
                  DataGridColumn) 
     Get 
     If m_RecentColumn Is Nothing Then m_RecentColumn = 
      New Dictionary(Of DataGrid, DataGridColumn)() 
     Return m_RecentColumn 
     End Get 
    End Property 

    Private Shared Sub DataGrid_PreparingCellForEdit(
     ByVal sender As Object, e As DataGridPreparingCellForEditEventArgs) 
     Dim dataGrid = DirectCast(sender, DataGrid) 
     RecentColumn(dataGrid) = e.Column 
    End Sub 

    End Class 

    Public Delegate Sub SelectionChangingEventHandler(
    ByVal sender As Object, ByVal e As SelectionChangingEventArgs) 

    Public Class SelectionChangingEventArgs : Inherits RoutedEventArgs 

    Public Sub New(ByVal row As DataGridRow, routedEvent As RoutedEvent) 
     MyBase.New(routedEvent) 
     m_CurrentRow = row 
    End Sub 

    Public Sub New(ByVal row As DataGridRow, 
        ByVal routedEvent As RoutedEvent, 
        ByVal source As Object) 
     MyBase.New(routedEvent, source) 
     m_CurrentRow = row 
    End Sub 

    Private m_CurrentRow As DataGridRow 
    Public ReadOnly Property CurrentRow() As DataGridRow 
     Get 
     Return m_CurrentRow 
     End Get 
    End Property 

    Public ReadOnly Property Item() As Object 
     Get 
     If CurrentRow IsNot Nothing Then Return CurrentRow.Item 
     Return Nothing 
     End Get 
    End Property 

    Public Property Cancel As Boolean 

    End Class 

End Namespace 

Utilisation:

<DataGrid Name="dg" 
src:DataGridSelectionChangingBehavior.EnableSelectionChanging="True" 
src:DataGridSelectionChangingBehavior.SelectionChanging="dg_SelectionChanging"> 
code

derrière (de pseudu):

Private Sub dg_SelectionChanging(ByVal sender As Object, 
    ByVal e As SelectionChangingEventArgs) 
    If e.CurrentRow.IsEditing Then 
    Dim item = TryCast(e.CurrentRow.Item, MyEntityType) 

    If item IsNot Nothing AndAlso item.IsValid Then 
     Dim dataGrid = DirectCast(sender, DataGrid) 
     Dim committed = dataGrid.CommitEdit(DataGridEditingUnit.Row, True) 
     If committed Then Exit Sub 
    End If 
    e.Cancel = True 
    End If 
End Sub 

Note: visual studio pourrait ne pas montrer l'événement dans le IntelliSense et pourrait même générer une conception du temps erreur, mais il devrait compiler et fonctionner parfaitement.

FYI: code formaté modifié pour s'adapter à l'écran SO.

Questions connexes