Вот подкласс DataGrid
со MaxRows
свойством зависимости. Следует отметить, что если DataGrid
находится в режиме редактирования, а CanUserAddRows
изменяется, то произойдет InvalidOperationException
(как вы упомянули в вопросе) .
InvalidOperationException
'NewItemPlaceholderPosition' не является
разрешено во время транзакции, начатой
'AddNew'.
Чтобы обойти это, метод IsInEditMode
вызывается в OnItemsChanged
, и если он возвращает true, мы подписываемся на событие LayoutUpdated
, чтобы снова проверить IsInEditMode
.
Кроме того, если для MaxRows
установлено значение 20, то должно быть разрешено 20 строк, когда CanUserAddRows
равно True, и 19 строк, когда False (чтобы освободить место для NewItemPlaceHolder
, которого нет в False).
Может использоваться следующим образом
<local:MaxRowsDataGrid MaxRows="20"
CanUserAddRows="True"
...>
MaxRowsDataGrid
public class MaxRowsDataGrid : DataGrid
{
public static readonly DependencyProperty MaxRowsProperty =
DependencyProperty.Register("MaxRows",
typeof(int),
typeof(MaxRowsDataGrid),
new UIPropertyMetadata(0, MaxRowsPropertyChanged));
private static void MaxRowsPropertyChanged(DependencyObject source, DependencyPropertyChangedEventArgs e)
{
MaxRowsDataGrid maxRowsDataGrid = source as MaxRowsDataGrid;
maxRowsDataGrid.SetCanUserAddRowsState();
}
public int MaxRows
{
get { return (int)GetValue(MaxRowsProperty); }
set { SetValue(MaxRowsProperty, value); }
}
private bool m_changingState;
public MaxRowsDataGrid()
{
m_changingState = false;
}
protected override void OnItemsChanged(System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
base.OnItemsChanged(e);
if (IsInEditMode() == true)
{
EventHandler eventHandler = null;
eventHandler += new EventHandler(delegate
{
if (IsInEditMode() == false)
{
SetCanUserAddRowsState();
LayoutUpdated -= eventHandler;
}
});
LayoutUpdated += eventHandler;
}
else
{
SetCanUserAddRowsState();
}
}
private bool IsInEditMode()
{
IEditableCollectionView itemsView = Items;
if (itemsView.IsAddingNew == false && itemsView.IsEditingItem == false)
{
return false;
}
return true;
}
// This method will raise OnItemsChanged again
// because a NewItemPlaceHolder will be added or removed
// so to avoid infinite recursion a bool flag is added
private void SetCanUserAddRowsState()
{
if (m_changingState == false)
{
m_changingState = true;
int maxRows = (CanUserAddRows == true) ? MaxRows : MaxRows-1;
if (Items.Count > maxRows)
{
CanUserAddRows = false;
}
else
{
CanUserAddRows = true;
}
m_changingState = false;
}
}
}