2010-11-21 9 views
1

セル/行が編集モードになると、ユーザーが別の行を選択しようとすると、その行をコミットしようとします。行が正常にコミットされていない場合は、選択要求が拒否されます。編集行は選択されたままであり、編集モードでなければなりません。DataGridが編集モードのときにユーザーが別の行を選択しないようにする方法はありますか?

いいヘルパーを経験しましたか?良い回避策はありますか?

注:私は長い間この問題に苦労してきましたが、既に経験がありますので、ランダムな考え方ではなく、実際の例だけを投稿してください。

答えて

1

コードには、here(コードはStackOverflow画面witdhに合うように正規化されたコードです)が含まれています。ごめんなさい。

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がインテリセンスでイベントが表示されないことがあり、さらには、設計時に生成される可能性がありますエラーは、コンパイルし、完璧に動作する必要があります。

FYI:SO画面に適合するように書式設定されたコード。

関連する問題