How To Questions about WPF Data Grid

Jun 30, 2009 at 10:56 AM

Hi,

I am new to WPF data grid. Here is what I am trying to do: I have a data grid which I am binding to a DataTable (using DataTable.DefaultView). In my data grid, I have an Insert Button in the header to insert a new row in the grid. Now here is what I want to accomplish:

1. When I add a new row, a "NewItemPlaceHolder" row is created as well. Is there a way using which I can hide this row? I did look around the forums and one recommendation with to define the ItemsSource of the grid by creating a new CollectionView object (something like dg.ItemsSource = new CollectionView(dg.ItemsSource). This does remove the "NewItemPlaceHolder" but now my items source is no longer a DataView object.

2. When I insert a new row, I want the focus on the 1st cell of the newly created row. In Silverlight, I can simply do by putting the focus on the datagrid, call it's ScrollIntoView() method & then finding the cell content & putting the focus there. How do I do this here?

 

Any help would be highly appreciated.

Thanks

Gaurav

 

Coordinator
Jun 30, 2009 at 8:47 PM

Hi Gaurav,

1. I'm assuming that when you say you add a new row that you are doing this programmatically (either your app is pulling in new data and inserting it on its own or the end user enters the information for the new row in a separate dialog and then the app adds the new row after the dialog is closed) - is that correct?  If so, if you want to turn off the NewItemPlaceholder, you should just be able to set DataGrid's CanUserAddRows property to false.  Does that fix it for you?

2. The Silverlight and WPF DataGrids are 95% API and behaviorally compatible, so if this works for you in the Silverlight DataGrid, it should most likely work in the WPF DataGrid.  Have you tried this out in WPF yet?  If it does not work, let us know and we will take a closer look.

Thanks!
Samantha

Jul 1, 2009 at 4:13 AM

Hi Samantha,

Thanks for responding.

1. Basically what I am doing is I am providing a button in the first cell of the header row (with a + sign) and creating a new row when user clicks on that row. What I did in the code is handle RowLoading event and if I see that e.Row.Item == NewItemPlaceHolder, I am setting it's height to 0 (I tried changing it's visibility first but that did not help. I know it is not an elegant solution but for now it is working. I want user to add new rows so I guess I can't set CanUserAddRows property to false. Can you recommend some other solution? Here is the code for that:

        void DataGridEntityAttribute_LoadingRow(object sender, DataGridRowEventArgs e)
        {
            if (e.Row.Item == CollectionView.NewItemPlaceholder)
            {
                e.Row.Visibility = Visibility.Collapsed;
                e.Row.Height = 0;
                DataGridEntityAttribute.UpdateLayout();
            }
        }

2. I tried doing it but that did not work. Then I snooped around this forum and I found this thread: http://www.codeplex.com/wpf/Thread/View.aspx?ThreadId=34065. First I set the selected row of the DataGrid (last row inserted) and the I used GetCell() function to put focus on the desired cell. For now it is working fine. Is there any other way to do this?

 

        public static DataGridRow GetRow(DataGrid DataGrid_Standard, int index)
        {
            DataGridRow row = (DataGridRow)DataGrid_Standard.ItemContainerGenerator.ContainerFromIndex(index);
            if (row == null)
            {
                DataGrid_Standard.ScrollIntoView(DataGrid_Standard.Items[index]);
                row = (DataGridRow)DataGrid_Standard.ItemContainerGenerator.ContainerFromIndex(index);
            }
            return row;
        }

        public static DataGridCell GetCell(DataGrid DataGrid_Standard, int row, int column)
        {
            DataGridRow rowContainer = GetRow(DataGrid_Standard, row);

            if (rowContainer != null)
            {
                DataGridCellsPresenter presenter = GetVisualChild<DataGridCellsPresenter>(rowContainer);

                // try to get the cell but it may possibly be virtualized
                DataGridCell cell = (DataGridCell)presenter.ItemContainerGenerator.ContainerFromIndex(column);
                if (cell == null)
                {
                    // now try to bring into view and retreive the cell
                    DataGrid_Standard.ScrollIntoView(rowContainer, DataGrid_Standard.Columns[column]);
                    cell = (DataGridCell)presenter.ItemContainerGenerator.ContainerFromIndex(column);
                }
                return cell;
            }
            return null;
        }

        public static T GetVisualChild<T>(Visual parent) where T : Visual
        {
            T child = default(T);
            int numVisuals = VisualTreeHelper.GetChildrenCount(parent);
            for (int i = 0; i < numVisuals; i++)
            {
                Visual v = (Visual)VisualTreeHelper.GetChild(parent, i);
                child = v as T;
                if (child == null)
                {
                    child = GetVisualChild<T>(v);
                }
                if (child != null)
                {
                    break;
                }
            }
            return child;
        }

Thanks

Gaurav

 

 

Coordinator
Jul 7, 2009 at 8:22 PM

Hi Gaurav,

1. The CanUserAddRows property doesn't prevent you from adding rows programmatically, it just hides the NewItemPlaceholder row from the user in the UI.  If I'm interpreting your scenario correctly, it sounds like when the user clicks the "+" button, you are adding a new, blank item to the DataGrid and then the user can just edit that new item.  However, if I've interpreted this wrong and what you are actually doing is un-hiding the NewItemPlaceholder row in the UI (by setting the height to something other than 0) so that the user can edit and submit it, then setting CanUserAddRows to false wouldn't work because it will hide that NewItemPlaceholder row.

2. I think you are using the right approach here. 

Thanks!
Samantha