有没有办法阻止用户在DataGrid处于编辑模式时选择另一行?

时间:2010-11-21 02:02:57

标签: wpf datagrid selection selector

我想,如果一个单元格/行进入编辑模式,那么,如果用户尝试选择另一行,它应该尝试提交该行,如果该行未成功提交,则应拒绝选择请求和编辑行应保持选中状态。

你是否有一个好帮手的经验?任何好的解决方法?

注意:我已经在这个问题上苦苦挣扎了很长时间并且已经有了一些经验,所以请发布工作实例,而不是随意的想法。

1 个答案:

答案 0 :(得分:1)

下面的代码包含来自here的扩展名(代码规范化以适应StackOverflow屏幕,对不起)。

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

用法:

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

背后的代码(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

注意:visual studio可能不会在intellisense中显示事件,甚至可能会产生设计时错误,但它应该编译并且工作正常。

仅供参考:修改后的代码格式适合SO屏幕。