Doing Code behind stuff.

Aug 22, 2008 at 12:51 PM
I ask the code behind question meaning the c# code behind.  It seems that everytime you see an example in WPF it's always shown in xaml.  While that is great, I will hardly every create a datagrid using xaml.  I might do the layout and set up the headers in xaml but it will be populated manually with the c# code behind.

With the new Datagrid. Using c#,  how do you .....

1.  Create a new table.
2.  Add a new row.
3.  Add a new row at run time.
4.  Add a new column.
5.  Add a new column at run time.
6.  Place data into individual cells.
7.  Extract data from individual cells.

Sorry if these questions seem trivial, but I feel like I'm stumbling around in the the dark.

Thanks
Aug 22, 2008 at 2:50 PM
Sorry about #1. I don't know what I was thinking.  I need coffee.....
Coordinator
Aug 23, 2008 at 12:01 AM
Just curious, but what is the scenario where you are want to populate the DataGrid manually? 

Add a new row manually (at runtime or whenever):

DataGrid.Items.Add(

new DataItem());

Add a new column (at runtime or whenever):

 

DataGrid.Columns.Add(

new DataGridTextColumn());

 

 

 

Aug 23, 2008 at 9:28 PM
Hi, 
Here's my scenario.  I have a DataSet.  In that DataSet there are two DataTables.  I set the ItemSource for my DataGrid to the DataTable containing the items I want to display.  The other DataTable in the DataSet contains a user specified layout of the columns that user wishes to see.  While the AutoGenerateColumns feature is nice, my DataTable may contain more columns than I wish to display for a given user.  How can I display specified columns in the code behind?  Using the GridView on a ListView control it is fairly easy and I can even define CellTemplates in my codebehind.  There is no CellTemplate for a DataGridColumn like there is for GridViewColumn.  Does anybody have an example of doing this in codebehind?  Am I just missing something simple here?

Kindest Reagards,
-LT
Aug 24, 2008 at 5:23 PM
Edited Aug 25, 2008 at 3:27 PM
OK, after much digging and dissecting of all two samples that are currently out there for the CTP DataGrid, I stand corrected.  There is a CellTemplate accessible for the DataGridTemplateColumn.  
Jaime Rodriguez's sample was the key for me.

In C#:
void BigKahuna_AutoGeneratingColumn(object sender, Microsoft.Windows.Controls.DataGridAutoGeneratingColumnEventArgs e)

{

if
( e.PropertyName == "PurchasedDate" )

{

DataGridTemplateColumn
column = new DataGridTemplateColumn();

column.Header = e.PropertyName;

column.CellTemplate =
this.FindResource("DateTimeTemplate") as DataTemplate ;

e.Column = column ;

 



So in my scenario above I set the ItemSource of my DataGrid to the DataTable containing the items I want to display.  I set AutoGeneratingColumns to False.  I then loop through my DataTable containing my layout columns and do the following for each column:
in VB:
Dim myColumn As New DataGridTemplateColumn()
       myColumn.Header = CStr(dr.Item("ColumnName"))
       myColumn.CellTemplate = TryCast(Me.FindResource(strDataTemplateName), DataTemplate)
       myDataGrid.Columns.Add(myColumn)

In C#, something like this:
{
    DataGridTemplateColumn myColumn = new DataGridTemplateColumn();
    myColumn.Header = (string)dr.Item("ColumnName");
    myColumn.CellTemplate = this.FindResource(strDataTemplateName) as DataTemplate;
    myDataGrid.Columns.Add(myColumn);
}

Thanks.
-LT
Aug 25, 2008 at 1:31 PM
Edited Aug 25, 2008 at 7:52 PM

Thanks for your help

DataGrid.Columns.Add(new DataGridTextColumn());  Did the trick. But still unclear about the "DataItem"?

DataGrid.Items.Add(new DataItem());??????????

What about

6.  Place data into individual cells.
7.  Extract data from individual cells.

You know this is not intuative.  A simple thing like datagrid.column[1].text = doesn't exist. I suppose it is because no one could really ever figure why anyone would ever populate a grid manually.  Like you asked.

Why I want to populate the DataGrid manually?

1.  I have a program written years ago that is being replaced with a WPF C# program.  In older program requires the user to select certain scenarios where there are a set defined descriptions for columns and a defined set of descriptions for rows.  But in-case the user makes a mistake he has to have the ability of increasing the rows and columns accordingly. 

2.  There are times I don't know how big the rows or columns will be until the user sets them.  They will also set the Headers and Row Headers.

3.  There are times when I use a datagrid to display calculations for a column.  These can't be bound.

4.  If the data wasn't created on the fly and just wanted to list the data.

5.  If the data is being loaded from a text file. You might want to do it manually.

6.  If the data is beling loaded from a binary file. You might want to do it manually.

I could probably think of a dozen others.  I try to use the correct tool for the job.  If there is a set defined reason for hard coding something in xaml. That's fine. But there are a lot of reasons not to.

Robert
Coordinator
Aug 26, 2008 at 7:36 PM

DataItem is just some generic object.

DataGrid is an ItemsControl just like ListBox or ListView.  So adding data manually is just a matter of adding items to the ItemsControl.Items collection.  As for the columns, you can think of them like GridViewColumns where they can describe a property on a specific item of the Items collection.  So you have to setup which property you want to show in that column through DataFieldBinding. 

What do you want datagrid.column[1].text to be exactly, the name of the header?  If so, there is datagrid.Column[1].Header.

As for populating the DataGrid manually, I have a few comments on the things you describe:

"1.  I have a program written years ago that is being replaced with a WPF C# program.  In older program requires the user to select certain scenarios where there are a set defined descriptions for columns and a defined set of descriptions for rows.  But in-case the user makes a mistake he has to have the ability of increasing the rows and columns accordingly."

For increasing rows, this can be handled automatically for you by IEditableCollectionView which is already implemented by ListCollectionView and BindingListCollectionView and therefore is baked into the DataGrid.  For a sample and more info on this see, http://blogs.msdn.com/vinsibal/archive/2008/05/20/wpf-3-5-sp1-feature-ieditablecollectionview.aspx

"2.  There are times I don't know how big the rows or columns will be until the user sets them.  They will also set the Headers and Row Headers."

Setting DataGrid.ItemsSource to an IEnumerable collection handles the number of rows dynamically.  There are no problems with setting DataGrid.ItemsSource at runtime.

"3.  There are times when I use a datagrid to display calculations for a column.  These can't be bound."

Why not?  If you follow the MVVM pattern, you should be able to bind in situations like this.

Generally, populating a DataGrid manually is an option you have but takes away from one of the core concepts that WPF is all about, which is data binding.  Even with the 3.5 SP1 release, more features related to data binding were introduced to further push for designing with data binding in mind and really to enable the DataGrid.  As an example, IEditableCollectionView and BindingGroups are two core features that will power the DataGrid editing and validation functionality.  By using DataGrid.ItemsSource (or any ItemsControl.ItemsSource really) as the hook from the UI to your data, you gain a lot of this functionality for free and there is no need to have to keep track of your data through the UI by adding/deleting rows yourself.

 

Aug 26, 2008 at 9:54 PM
I guess I just don't like giving up control.  Binding has it's place but sometimes it's way easier and necessary to use an unbound grid, I know you don't think so, but what I'm doing is not that complicated and I can't define the rows or columns in xaml.  I know you guys have done all this work making everything to be bound and I appreciate your efforts but I'm beating my head against the wall trying to figure out how to do something really simple like.

1. Can you write data directly to a cell in the c# code behind?  If so, how? 
2. Can you read data directly from a cell in the c# code behind?  If so, how?

Thanks
Coordinator
Aug 27, 2008 at 5:19 PM

This is probably not what you are really trying to ask for but here is how you can Read/Write data from a cell:

 

DataGridCell

 

cell = GetCell(0, 0);
// read from a cell
object content = cell.Content;
// write directly to a cell
cell.Content = "new content";

 

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
            DataGrid_Standard.ScrollIntoView(rowContainer, DataGrid_Standard.Columns[column]);
            cell = (DataGridCell)presenter.ItemContainerGenerator.ContainerFromIndex(column);
        }
        return cell;
    }
    return null;
}

 

public

 

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


If you can give me an example of the data structure that you are trying to populate with the DataGrid, I may be able to better answer to this question.

Aug 27, 2008 at 8:49 PM
Great that was exactly what I needed. Thanks.  I have one final question, but I'll start a new thread.
Sep 5, 2008 at 8:02 AM
I also think everything you need can be done by changing the data itself. That's the whole point of data binding controls.
Sep 5, 2008 at 12:23 PM
While I will agree with you that bound controls are very cool.  It does make sense to have an unbound control.  Why do you think there have been so many in the past that you could use unbound?  And you also couldn't say "EVERYTHING" you need can be done by a bound control.  That's like saying everything can be fixed by a cresent wrench.  In some cases creating a bound control is way more time consuming than just listing read only data.
Oct 17, 2008 at 3:05 AM
Hi, vinsible

you are using GetVisualChild mehtod in above code snippet  (
"DataGridCellsPresenter presenter = GetVisualChild<DataGridCellsPresenter>(rowContainer);"), but my question is how do you override the GetVisualChild method.


Oct 17, 2008 at 4:48 AM
Sorry, I found this overriding implementation in your CTP example.

thanks.
Dec 10, 2008 at 7:24 PM
Edited Dec 10, 2008 at 7:25 PM
I would like clarification on the "DataGridCellsPresenter presenter = GetVisualChild<DDataGridCellsPresenter(rowContainer);" line;
I see that that method is overridden in DataGridColumnHeadersPresenter in DataGrid\Microsoft\Windows\Controls\Primitives\DataGridColumnHeadersPresenter.cs
, do I need to create asimular method in \DataGrid\Microsoft\Windows\Controls\Primitives\DataGridCellsPresenter.cs and recomplie the DataGrid? 
Is there a way I could subclass DataGrid?

I would like to have a column dedicated to non-bound controls and need a way to access the objects.
Dec 10, 2008 at 7:27 PM
Sorry for the formatting, I had to manually put in carriage returns. Is that typical?
Coordinator
Dec 19, 2008 at 5:01 PM
You don't have to subclass DataGrid to get access to a cell from an unbound column.  Programmatically you just need to go through the visual tree to get it's content.  GetVisualChild<T> is just another custom helper function.

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;
}

 

Mar 17, 2009 at 10:01 PM

Just a footnote for anyone trying out the example code above. If I try using the code in the following fashion, in order to set the cell focus to the next one,

var cell = GetCell(YearlyCapitalRowGrid, currentCell.Row, currentCell.Column);

var request = new TraversalRequest(FocusNavigationDirection.Next) { Wrapped = true };

cell.MoveFocus(request);

I get a NullReferenceException and the source of which is in the WPF Toolkit at System.Windows.Controls.VirtualizingStackPanel.InsertContainer(Int32 childIndex, UIElement container, Boolean isRecycled).

Not sure if I'm using this code correctly or not. But it would be nice to get it working.

Gavin

Mar 17, 2009 at 10:02 PM
This occurs within the DataGrid_Standard.ScrollIntoView(DataGrid_Standard.Items[index]); statement of the GetRow method.
Mar 23, 2009 at 9:28 PM
I just wanted to know if anyone has got vinisbal's GetCell method to work, as I having a completely frustrating time of it.

Thanks.
Mar 23, 2009 at 9:45 PM
Gavin
No not really. If not populated correctly before you read the cell it will return unexpected results and quite often bombs. Instead of fighting city hall, these guys designed this grid to be bound to something and it just doesn't work very well if you don't. I don't agree with it but that's the way it is. But fear not, all is not lost. In the example below I'm using Sqlite database but this could be any ado.net database. You just use a datatable to read and write your data and it will do the same thing as reading and writing to the cells themselves.
Robert

sqliteconnection = new SQLiteConnection();

ds = new DataSet();

string connString = @"Data Source=" + gl.IconFolder + @"\StressTables.db" + ";Version=3;New=True;Synchronous=Off";

string query = @"SELECT * FROM [" + List + "]";

// Fill the Set with the data

using (sqliteconnection = new SQLiteConnection(connString))

{

da = new SQLiteDataAdapter(query, sqliteconnection);

// SQLiteCommandBuilder builder = new SQLiteCommandBuilder(da);

da.Fill(ds, List);

dt = ds.Tables[0];

}

dataGrid2.ItemsSource = ds.Tables[List].DefaultView;


From: Gavin99
Sent: Monday, March 23, 2009 4:28 PM
Subject: [!! SPAM] Re: Doing Code behind stuff. [wpf:34065]

From: Gavin99

I just wanted to know if anyone has got vinisbal's GetCell method to work, as I having a completely frustrating time of it.

Thanks.
Mar 23, 2009 at 9:46 PM
Finally got it!

In an obscure discussion I found this snippet by vinsibal:

right before calling DataGrid.ScrollIntoView, call DataGrid.UpdateLayout()

And if DataGrid.ScrollIntoView is called in his GetCell implementation - it works!! Nothing like leaving out a crucial piece, eh?
Mar 25, 2009 at 3:55 AM
I need to have my row headers display their row number (i.e. 1, 2, 3...). In my datagrid, a user can insert above/below the current row,
reorder the rows (move one up/down), delete any given row, etc. No matter what the operation is, the rows will still be numbered sequentially.  So, I rely on
GetRow to help get me row access for renumbering when my datagridRowLoading event fires.

I am using the GetRow as specified in the above thread-- and I have even added an UpdateLayout before calling scroll into view.  It all works
beautifully UNTIL...the datagrid has reached its max height and the vertical scroll bar appears. Once that happens, I always get back null rows.

Can you make any suggestions? If I cannot get the row header, the only way that I can think of to solve it is to have my first column act as a row header and numerically number that...
Thanks in advance!!!

Apr 1, 2009 at 1:30 PM
I gave up on this and bound the content of the row header
to an ID field in my collection. Works beautifully. Given the
virtualization of rows in the datagrid, I now believe that there
is no other way to reasonably do this if you have insert above/below and
swap order functionality in the grid.
Apr 1, 2009 at 1:46 PM
Your right. Unfortunately the Grid doesn't work very well unless you bind it.
Oct 13, 2010 at 12:47 PM

Is there a better way to do this(Read/Write Data to the Cell) in WPF 4.0.?

Oct 13, 2010 at 2:03 PM

Hi

How to copy items from one datagrid to anather programmatically at runtime (as in TottalCommander) when we pres button "F5"?