Update DataTemplate Programmatically

May 20, 2009 at 4:14 PM

 We have a grid where we am programmatically creating columns.  A requirements has surfaced to add a button to a Column Header.  We are trying to use a dataTemplate.

Is there an event, similar to the LoadingRowDetails event, where I can do this and it will impact the instance which is part of the visual tree?  I think the issue is related to using "LoadContent".

pseudoCode:

DataGridTextColumn newColumn1 = new DataGridTextColumn();  //works

DataTemplate dt = (DataTemplate)this.FindResource("DatagridDataTemplate");

newColumn1.HeaderTemplate = dt;

Binding binding1 = new Binding("Country");//works

binding1.Mode = System.Windows.Data.BindingMode.TwoWay;//works

newColumn1.Binding = binding1;//works

dataGridParent.Columns.Add(newColumn1);//works

 

//This is the trouble:

Button headerButton = ((Button)(dataGridParent.Columns[2].HeaderTemplate.LoadContent() as StackPanel).FindName("ButtonColumn"));

headerButton.Content = "Column12";//the original placeholder content from the DataTemplate remains

headerButton.Click += [ . . . ]   //no delegate is added and no events are fired.

 

dataGridParent.UpdateLayout();

 

Thanks!

Tracy

May 25, 2009 at 12:57 PM

The Header property is an Object, so you can assign anything to it. Why not just assign a button instead of the normal simple string?

DataGridTextColumn column = new DataGridTextColumn();
...
Button button = new Button();
...
column.Header = button;
this.dataGrid.Columns.Add(column);

If you need to show multiple controls, a StackPanel works fine for wrapping them in a single object instance.

May 26, 2009 at 6:56 PM

Ok!  This works! Instead of using a DataTemplate that had a stackpanel, textblock and a button, I am doing this now in the code behind.  I do need to now set the Header row height probrammatically as well.  How can I do that?

here is my code snippet:

               #region Add a Column for the Parent Attribute

                DataGridTextColumn newColumn1 = new DataGridTextColumn();

                Binding binding1 = new Binding("Country");

                binding1.Mode = System.Windows.Data.BindingMode.TwoWay;

                newColumn1.Binding = binding1;

                #region Add a button here to the header 

                //create a simple stack panel to hold a text box as well as a button an not use a XAML dataTemplate

                StackPanel headerStackPanel = new StackPanel();

                TextBlock headerTextBlock = new TextBlock();

                #region set the attributes of the textBlock including the TEXT

                //http://msdn.microsoft.com/en-us/library/system.windows.controls.textblock.aspx

                headerTextBlock.TextWrapping = TextWrapping.Wrap;

                headerTextBlock.TextAlignment = TextAlignment.Center;

                headerTextBlock.Inlines.Add(new Run(" Centered Text Over the Button "));

                #endregion

                headerStackPanel.Children.Add(headerTextBlock);

                Button headerButton = new Button();

                headerButton.Content = "BannonButton";

                headerButton.Click += new RoutedEventHandler(headerButton_Click);

                headerStackPanel.Children.Add(headerButton);

                headerStackPanel.Height = double.NaN; //this sets the height = autosize

                newColumn1.Header = headerStackPanel;

//*** HOW CAN I SET THE HEIGHT OF THE DataGrid's Row Header?

          dataGridParent.Columns.Add(newColumn1);     //works

 


Coordinator
May 26, 2009 at 9:45 PM

Hi Tracy,

Going back to your original question, the reason that it wasn't working is because LoadContent will always load a copy of the element you're trying to load, instead of the actual instance which is instantiated in the tree.  So you were making your changes to a copy of that button, instead of the actual button.  The way that we would recommend to do this is:

1. It sounds like you need two different data templates for your column headers - one which has this button, and one which doesn't.  You should create the two data templates and then use DataGridColumn.HeaderTemplateSelector to choose when to apply the template with the button.  This will make things static rather than dynamic, which will simplify the situation.

2. If you want to attach an event for Button.Click within that data template, you have a couple options:

a) Walk the visual tree to find the instantiated instance of the button and set it directly on that button, OR

b) Use a Style to set the handler for the Click event.

This will allow you to avoid the problem with the header resizing that you've run into.  We discussed the header resizing issue and haven't been able to come up with a good solution yet, but I will let you know if we think of anything.

Thanks!
Samantha

 

May 26, 2009 at 11:25 PM

If at all possible, I’d like to use the simpler approach that doesn’t involve data templates… I had assumed that the sizing issue would not be too difficult… 

8( 

Let me know if your team can find a good way to do this.  I thought something like setting the datagrid ColumnRowHeader.Height….  but that didn’t appear to work.

I’ve never used “DataGridColumn.HeaderTemplateSelector”… can you point me to a sample/snippet in the interim?