Getting specified cell in a datagrid

May 5, 2009 at 11:51 AM

Hi everyone,

I'm trying to get to focus a certain cell in a datagrid. I've seen code here in CodePlex by Vincent Sibal that does that. Everything works fine but recently I encountered a problem when adding contents to an empty datagrid then immediately focusing on a cell. I've posted a sample XAML and code-behind that shows my problem. Press enter the first time to fill the datagrid - but the cell is null. Press enter 2nd time and cell is not null but positions it on 2nd row. And if you try to put a breakpoint in it and hover on the cell, you will see that the cell's value is tuition fee but focus is on other fees.



Here is the XAML:

<Window
 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
 x:Class="UntitledProject1.Window1"
 x:Name="Window"
 Title="Window1"
 Width="640" Height="480" xmlns:Custom="http://schemas.microsoft.com/wpf/2008/toolkit">

 <Grid x:Name="LayoutRoot">
  <Custom:DataGrid Margin="31,32,45,53" x:Name="dg" IsSynchronizedWithCurrentItem="True"/>
 </Grid>
</Window>


Here is the code behind:

using System;
using System.IO;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Navigation;
using System.Collections.Generic;
using Microsoft.Windows.Controls;
using Microsoft.Windows.Controls.Primitives;

namespace UntitledProject1
{
 public partial class Window1
 {
        private List<Tuition> _TuitionList = new List<Tuition>();
  public Window1()
  {
   this.InitializeComponent();
   
   // Insert code required on object creation below this point.
            this.Loaded += new RoutedEventHandler(Window1_Loaded);
            this.PreviewKeyDown += new System.Windows.Input.KeyEventHandler(Window1_PreviewKeyDown);
  }
        //
        // Event handlers
        //
        private void Window1_Loaded(object sender, RoutedEventArgs e)
        {
            dg.AutoGenerateColumns = false;
            dg.CanUserAddRows = false;
            dg.CanUserDeleteRows = false;

            // Columns.
            DataGridTextColumn colAccount = new DataGridTextColumn();
            Binding b = new Binding("Account");
            b.Mode = BindingMode.TwoWay;
            colAccount.Binding = b;
            // colAccount.Width = new DataGridLength(100, DataGridLengthUnitType.Star); Bug if not initially displayed tab on TabControl.
            colAccount.Width = new DataGridLength(250, DataGridLengthUnitType.Pixel);
            colAccount.CanUserSort = false;
            colAccount.Header = "Account";
            dg.Columns.Add(colAccount);
            DataGridTextColumn colAmount = new DataGridTextColumn();
            b = new Binding("Amount");
            b.Mode = BindingMode.TwoWay;
            colAmount.Binding = b;
            // colAmount.Width = new DataGridLength(50, DataGridLengthUnitType.Star); Bug if not initially displayed tab on TabControl.
            colAmount.Width = new DataGridLength(119, DataGridLengthUnitType.Pixel);
            colAmount.CanUserSort = false;
            colAmount.Header = "Amount";
            dg.Columns.Add(colAmount);
            dg.ItemsSource = _TuitionList;
        }

        private void Window1_PreviewKeyDown(object sender, System.Windows.Input.KeyEventArgs e)
        {
            if (e.Key == System.Windows.Input.Key.Return)
            {
                // Add items.
                _TuitionList.Add(new Tuition() { Account = "Tuition Fee", Amount = 100 });
                _TuitionList.Add(new Tuition() { Account = "Other Fees", Amount = 200 });
                _TuitionList.Add(new Tuition() { Account = "Miscellaneous Fees", Amount = 300 });

                // Focus on cell.
                DataGridCell cell = GetCell(0, 0);
                if (cell != null)
                    cell.Focus();
            }
        }
        //
        // DataGrid Helper Functions
        //
        public DataGridCell GetCell(int row, int column)
        {
            DataGridRow rowContainer = GetRow(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.
                    dg.ScrollIntoView(rowContainer, dg.Columns[column]);
                    cell = (DataGridCell)presenter.ItemContainerGenerator.ContainerFromIndex(column);
                }
                return cell;
            }
            return null;
        }

        public DataGridRow GetRow(int index)
        {
            DataGridRow row = (DataGridRow)dg.ItemContainerGenerator.ContainerFromIndex(index);
            if (row == null)
            {
                // May be virtualized, bring into view and try again.
                dg.UpdateLayout();
                dg.ScrollIntoView(dg.Items[index]);
                row = (DataGridRow)dg.ItemContainerGenerator.ContainerFromIndex(index);
            }
            return row;
        }

        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;
        }
        //
        // Helper class
        //
        public class Tuition
        {
            public string Account { get; set; }
            public decimal Amount { get; set; }
        }
 }
}