DataGrid - change edit behaviour
I have an ObservableCollection of ChildViewModels with somewhat complex behaviour.
When I go to edit a row - the DataGrid goes into 'edit-mode' - this effectively disables UI-notifications outside the current cell until the row is committed - is this intended behaviour and more importantly can it be changed?
Example:
public class ViewModel
{
public ViewModel()
{
Childs = new ObservableCollection<ChildViewModel> {new ChildViewModel()};
}
public ObservableCollection<ChildViewModel> Childs { get; private set; }
}
public class ChildViewModel : INotifyPropertyChanged
{
private string _firstProperty;
public string FirstProperty
{
get { return _firstProperty; }
set
{
_firstProperty = value;
_secondProperty = value;
OnPropetyChanged("FirstProperty");
OnPropetyChanged("SecondProperty");
}
}
private string _secondProperty;
public string SecondProperty
{
get { return _secondProperty; }
set
{
_secondProperty = value;
OnPropetyChanged("SecondProperty");
}
}
private void OnPropetyChanged(string property)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(property));
}
public event PropertyChangedEventHandler PropertyChanged;
开发者_运维问答}
And in View:
<Window.Resources>
<local:ViewModel x:Key="Data"/>
</Window.Resources>
<DataGrid DataContext="{Binding Source={StaticResource Data}}" ItemsSource="{Binding Childs}"/>
Notice how the second notification when editing first column is hidden until you leave the row.
EDIT: Implementing IEditableObject does nothing:
public class ChildViewModel : INotifyPropertyChanged,IEditableObject
{
...
private ChildViewModel _localCopy;
public void BeginEdit()
{
_localCopy = new ChildViewModel {FirstProperty = FirstProperty, SecondProperty = SecondProperty};
}
public void EndEdit()
{
_localCopy = null;
}
public void CancelEdit()
{
SecondProperty = _localCopy.SecondProperty;
FirstProperty = _localCopy.FirstProperty;
}
}
This behavior is implemented in DataGrid using BindingGroup
. The DataGrid sets ItemsControl.ItemBindingGroup
in order to apply a BindingGroup
to every row. It initializes this in MeasureOverride
, so you can override MeasureOverride
and clear them out:
public class NoBindingGroupGrid
: DataGrid
{
protected override Size MeasureOverride(Size availableSize)
{
var desiredSize = base.MeasureOverride(availableSize);
ClearBindingGroup();
return desiredSize;
}
private void ClearBindingGroup()
{
// Clear ItemBindingGroup so it isn't applied to new rows
ItemBindingGroup = null;
// Clear BindingGroup on already created rows
foreach (var item in Items)
{
var row = ItemContainerGenerator.ContainerFromItem(item) as FrameworkElement;
row.BindingGroup = null;
}
}
}
This is very old question, but a much better solution which doesn't require subclassing DataGrid exists. Just call CommitEdit() in the CellEditEnding event:
bool manualCommit = false;
private void MyDataGrid_CellEditEnding(object sender, DataGridCellEditEndingEventArgs e)
{
if (!manualCommit)
{
manualCommit = true;
MyDataGrid.CommitEdit(DataGridEditingUnit.Row, true);
manualCommit = false;
}
}
ok, so, here is the problem. Observable Collection does NOT notify of objects that it contains changing. It only notifies on add/remove/etc. operations that update the collection is-self.
I had this problem and had to manually add my columns to the datagrid, then set the Binding item on the Column object. so that it would bind to my contents.
Also, I made the objects that are in my ICollectionView
derive from IEditableObject
so when they are "updated" the grid will refresh itself.
this sucks, but its what i had to do to get it to work.
Optionally, you could make your own ObservableCollection that attaches/detaches property changed handlers when an item is addeed and remove.
精彩评论