Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Wpf Datagrid Max Rows

I am currently working with data grid where I only want to allow the user to enter UP TO 20 rows of data before making CanUserAddRows to false.

I made a dependency property on my own datagrid (that derives from the original one). I tried using the event "ItemContainerGenerator.ItemsChanged" and check for row count in there and if row count = max rows, then make can user add row = false (I get an exception for that saying i'm not allow to change it during "Add Row".

I was wondering if there is a good way on implementing this ....

Thanks and Regards, Kevin

like image 264
Kev84 Avatar asked Feb 03 '11 20:02

Kev84


2 Answers

I am an adept of K.I.S.S. To reduce the amount of lines required to do the job and keep it simple, use the following:

    private void MyDataGrid_LoadingRow( object sender, DataGridRowEventArgs e )
    {
        // The user cannot add more rows than allowed
        IEditableCollectionView itemsView = this.myDataGrid.Items;
        if( this.myDataGrid.Items.Count == max_RowCount + 1 && itemsView.IsAddingNew == true )
        {
            // Commit the current one added by the user
            itemsView.CommitNew();

            // Once the adding transaction is commit the user cannot add an other one
            this.myDataGrid.CanUserAddRows = false;
        }
    }

Simple and compact ;0)

like image 153
Mart Avatar answered Oct 22 '22 03:10

Mart


Here's a subclassed DataGrid with a MaxRows Dependency Property. The things to note about the implementation is if the DataGrid is in edit mode and CanUserAddRows is changed an InvalidOperationException will occur (like you mentioned in the question).

InvalidOperationException
'NewItemPlaceholderPosition' is not allowed during a transaction begun by 'AddNew'.

To workaround this, a method called IsInEditMode is called in OnItemsChanged and if it returns true we subscribe to the event LayoutUpdated to check IsInEditMode again.

Also, if MaxRows is set to 20, it must allow 20 rows when CanUserAddRows is True, and 19 rows when False (to make place for the NewItemPlaceHolder which isn't present on False).

It can be used like this

<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;
        }
    }
}
like image 38
Fredrik Hedblad Avatar answered Oct 22 '22 01:10

Fredrik Hedblad