2010-11-21 5 views
1

Ich möchte, dass wenn eine Zelle/Zeile in Bearbeitungsmodus geht, wenn der Benutzer versucht, eine andere Zeile auszuwählen, sollte es versuchen, diese Zeile zu committen, wenn die Zeile nicht erfolgreich committed ist, sollte es die Auswahlanforderung ablehnen und die Bearbeitungszeile sollte ausgewählt und im Bearbeitungsmodus bleiben.Gibt es eine Möglichkeit zu verhindern, dass ein Benutzer eine andere Zeile auswählt, wenn sich DataGrid im Bearbeitungsmodus befindet?

Haben Sie Erfahrung mit einem guten Helfer dafür? eine gute Problemumgehung?

HINWEIS: Ich habe lange mit diesem Problem gekämpft und habe bereits einige Erfahrungen gesammelt, also bitte nur Arbeitsbeispiele, keine zufälligen Gedanken.

Antwort

1

Der folgende Code enthält eine Erweiterung von here (Code normalisiert, um StackOverflow Bildschirm withhh, Entschuldigung).

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 

Verbrauch:

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

-Code hinter (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 

Hinweis: Visual Studio nicht das Ereignis in der Intellisense zeigen könnte und vielleicht sogar eine Entwurfszeit erzeugen Fehler, aber es sollte kompilieren und perfekt funktionieren.

FYI: Code formatiert geändert, um SO Bildschirm zu passen.