I need to make the DataGrid, so if I am in edit mode, and the current row is not valid, the user should not be able to select a different row.
In fact, I think that the DataGrid
is supposed to avoid selection of another row once the CollectionChangingEventArgs
of the CollectionView
is flagged for cancellation, the DataGrid
should stick to the CollectionView
.
Now that I have to refresh, it's alright and works fine as long as the CollectionView is refreshable (i.e. is not in edit mode), once it's in edit mode, the Refresh
method throws an InvalidOperationException telling that "'Refresh' is not allowed during an AddNew or EditItem transaction.".
I tried the following but it doesn't help, create a WPF application with the follwing content and see for yourself:
<Window
x:Class="MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Window.Resources>
<CollectionViewSource x:Key="ItemsCollection"/>
</Window.Resources>
<DataGrid
Name="dataGrid"
AutoGenerateColumns="False"
IsSynchronizedWithCurrentItem="True"
ItemsSource="{Binding Source={StaticResource ItemsCollection}}">
<DataGrid.Columns>
<DataGridTextColumn
Binding="{Binding Title, UpdateSourceTrigger=PropertyChanged}"/>
<DataGridTextColumn Binding="{Binding Value}"/>
<DataGridCheckBoxColumn Binding="{Binding IsValid, Mode=OneWay}"/>
</DataGrid.Columns>
</DataGrid>
</Window>
Imports System.ComponentModel
Imports System.Collections.ObjectModel
Class MainWindow
WithEvents collectionView As CollectionView
Private Sub Window_Loaded(ByVal sender As Object,
ByVal e As RoutedEventArgs) Handles MyBase.Loaded
Dim ItemsCollection = DirectCast(Resources("ItemsCollection"),
CollectionViewSource)
ItemsCollection.Source =
New ObservableCollection(Of Item) From
{
New Item("item 1", 1),
New Item("item 2", 2),
New Item("item 3", 3),
New Item("item 4", 4)
}
collectionView = ItemsCollection.View
End Sub
Private Sub ItemsCollectionView_CurrentChanging(ByVal sender As Object,
ByVal e As CurrentChangingEventArgs) Handles collectionView.CurrentChanging
If Not e.IsCancelable Then Exit Sub
If isInEditMode Then
dataGrid.SelectedIndex = collectionView.CurrentPosition
collectionView.Refresh()
End If
End Sub
Private isInEditMode As Boolean
Private Sub dataGrid_BeginningEdit(ByVal sender As Object,
ByVal e As DataGridBeginningEditEventArgs) Handles dataGrid.BeginningEdit
isInEditMode = True
End Sub
Private Sub dataGrid_CellEditEnding(ByVal sender As Object,
ByVal e As DataGridCellEditEndingEventArgs) Handles dataGrid.CellEditEnding
If Not DirectCast(e.Row.Item, Item).IsValid Then
e.Cancel = True
Else
isInEditMode = False
End If
End Sub
End Class
Public Class Item : Implements INotifyPropertyChanged
Public Sub New()
End Sub
Public Sub New(ByVal title As String, ByVal value As Integer)
m_Title = title
m_Value = value
End Sub
Private m_Title As String
Public Property Title() As String
Get
Return m_Title
End Get
Set(ByVal value As String)
If value = m_Title Then Exit Property
m_Title = value
OnPropertyChanged("Title")
OnPropertyChanged("IsValid")
End Set
End Property
Private m_Value As Integer
Public Property Value() As Integer
Get
Return m_Value
End Get
Set(ByVal value As Integer)
m_Value = value
OnPropertyChanged("Value")
End Set
End Property
Public ReadOnly Property IsValid As Boolean
Get
Return Not String.IsNullOrWhiteSpace(Title)
End Get
End Property
Protected Overridable Sub OnPropertyChanged(ByVal propertyName As String)
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propertyName))
End Sub
Public Event PropertyChanged(ByVal sender As Object,
ByVal e As PropertyChangedEventArgs) _
Implements INotifyPropertyChanged.PropertyChanged
End Class