Hookup button event in the template. But you have to define the header template in UserControl.Resources section instead of Application.Resources.
Optoin2:
Write a ListHeader UserControl, wrap up all the controls layout and event handler in that UserControl. Then use that UserControl in your DataGridHeaderTemplate. This way you can put the header template in the Application.Resouces.
Sally Xu
Software Engineer
Aprimo, Inc
Please remember to mark the replies as answers if they answered your question
Thank you. I think, I don't understand what you exactly mean by "wrap up all the controls layout and events ..". Even if I move all layouts and events of the ListHeader to the UserControl (into separate control in XAML + related code), I will not be able
to set my own properties of ListHeader after settin the HeaderStyle. The main problem is that HeaderStyle generates its own instance of the ListHeader and there is no way to update its properties after setting the style. There is no way to set up those properties
before setting the HeaderStyle, too. Or ... I don't know how to do it.
[TemplatePart(Name = GridHeader.HeaderTextElement, Type = typeof(FrameworkElement))]
[TemplatePart(Name = GridHeader.FilterTextElement, Type = typeof(TextBox))]
public class GridHeader : Control
{
/// <summary>
/// Gets or sets the HeaderText possible Value of the int object.
/// </summary>
public string HeaderText
{
get { return (string)GetValue(HeaderTextProperty); }
set { SetValue(HeaderTextProperty, value); }
}
#endregion HeaderText
#region FilterText
/// <summary>
/// Identifies the FilterText dependency property.
/// </summary>
public static readonly DependencyProperty FilterTextProperty = DependencyProperty.Register("FilterText", typeof(string), typeof(GridHeader), null);
/// <summary>
/// Gets or sets the FilterText possible Value of the string object.
/// </summary>
public string FilterText
{
get { return (string)GetValue(FilterTextProperty); }
set { SetValue(FilterTextProperty, value); }
}
#endregion FilterText
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
this.filterText = this.GetTemplateChild("FilterText") as TextBox;
this.header = this.GetTemplateChild("HeaderText") as Button;
if(this.filterText != null)
this.filterText.LostFocus += new RoutedEventHandler(filterText_LostFocus);
if(this.header != null)
this.header.Click += new RoutedEventHandler(header_Click);
}
col.HeaderStyle = col.HeaderStyle = Application.Current.Resources["grid-header"] as Style;
What I have found for sorting in RC0 DataGrid works differently from beta2:
If you want to use Default Sort function, either use default header or define your own header template but do not put a button in the template. This way, when you click the header, the sort would work. If you put a button in the Header template, click that
button won't fire default sort.
If you defined your own header template, the sort indicator image no longer shows up even sort still work.
Sally Xu
Software Engineer
Aprimo, Inc
Please remember to mark the replies as answers if they answered your question
Thank you very much! The code is working. I really appreciate your effort!
But I think this approach doesn't solve my problem. The final code loks like below:
public Page()
{
InitializeComponent();
DataGridTextColumn col1 = new DataGridTextColumn();
DataGridTextColumn col2 = new DataGridTextColumn();
DataGridTextColumn col3 = new DataGridTextColumn();
col1.HeaderStyle = Application.Current.Resources["grid-header"] as Style;
col2.HeaderStyle = Application.Current.Resources["grid-header"] as Style;
col3.HeaderStyle = Application.Current.Resources["grid-header"] as Style;
theDataGrid.Columns.Add(col1);
theDataGrid.Columns.Add(col2);
theDataGrid.Columns.Add(col3);
}
Everything works OK with Generic.xaml and style in App.xaml. But I still can't set up properties of the GridHeader BEFORE or AFTER setting the Column Style. I supposed something like that:
col1.Header.FilterText = .... // in order to take the last column text from db
col1.FilterLostFocus += .... // in order to store the last column text into db
...
col2.Header.FilterText = ...
col2.FilterLostFocus += ....
...
The "business" problem is that the client wants to store in db the width of the column after changing the size, last "sort order" on the column after changing the sort order and finally the last filter text put into the column header (maby there will be
more "needs" in the future ...).
private void GridHeader_Loaded(object sender, RoutedEventArgs e)
{
GridHeader h = sender as GridHeader;
// Check h.HeaderText to know which col you are on, based on that, set the FilterText, and Hookup Event handler (make sure you add the public event in the custom control)
h.FilterText = "YourFilterTest";
h.FilterLostFocus += ....
}
Well, I still like the way in beta2 better where we can set the control to the column.Header. Now it's really hard to get access to the controls defined in template ( a cross-board issue for getting access to the controls in template in Silverlight).
Sally Xu
Software Engineer
Aprimo, Inc
Please remember to mark the replies as answers if they answered your question
Good idea. The problem is that this <UserControl.Resources> in my case shoul be inside the XAML control of
DataGridTemplateColumn. I don't know yet how to create the XAML file for DataGridColumn type because at present each my DataGridTemplateColumn is created in code, without XAML. On the other hand, a simple creation of the XAML control "myDataGridTemplateColumn"
doesn't work, because UserControl type cann't be added as a Column: "DataGrid.Columns.Add(myDataGridTemplateColumn)". And (of course...) the base class of "myDataGridTemplateColumn" can't be a DataGridColumn type (must be "UserControl"). Thank
you for all your help!
The more I play with this, the more I think the design change for how to set col header in RC0 is flawed, unless I haven't found the correct way to do this.
The DataGridColumn.Header property is still Object type (just like in beta2), but you can not set anything other than the header text string to it which I think is wrong.
I even wrote a custom Header that inherited from DataGridColumnHeader object, but there is no way for me to set it to the DataGridColumnHeader._headerCell to replace the original DataGridColumnHeader object which is set internally.
I wrote a request in another thread asking this question. Hope someone from Microsoft can answer it.
It's nice to hear somebody supports me. I've written the "suggestion" in another thread, too (http://silverlight.net/forums/p/31442/99361.aspx) but there is no answer. After your suggestion of
"Loaded" event I've also tried to find "Parent" of my GridHeader in order to find the DataGridHeader, but the code:
For finding Parent for any control, you now need to use VisualTreeHelper.GetParent function instead of control.Parent property. Try that and see if you get the parent of the header.
Sally Xu
Software Engineer
Aprimo, Inc
Please remember to mark the replies as answers if they answered your question
The problem is that the DataGridColumn of that header takes place in property "OwningColumn" (of the obj in this example) which is "Non-Public member".
sladapter
All-Star
43609 Points
7910 Posts
Re: Custom DataGrid.Header - BUG in RC0.
Sep 29, 2008 04:16 PM | LINK
Option1:
Hookup button event in the template. But you have to define the header template in UserControl.Resources section instead of Application.Resources.
Optoin2:
Write a ListHeader UserControl, wrap up all the controls layout and event handler in that UserControl. Then use that UserControl in your DataGridHeaderTemplate. This way you can put the header template in the Application.Resouces.
Software Engineer
Aprimo, Inc
Please remember to mark the replies as answers if they answered your question
Bartlomiej
Member
68 Points
45 Posts
Re: Custom DataGrid.Header - BUG in RC0.
Sep 29, 2008 05:58 PM | LINK
Thank you. I think, I don't understand what you exactly mean by "wrap up all the controls layout and events ..". Even if I move all layouts and events of the ListHeader to the UserControl (into separate control in XAML + related code), I will not be able to set my own properties of ListHeader after settin the HeaderStyle. The main problem is that HeaderStyle generates its own instance of the ListHeader and there is no way to update its properties after setting the style. There is no way to set up those properties before setting the HeaderStyle, too. Or ... I don't know how to do it.
B.
sladapter
All-Star
43609 Points
7910 Posts
Re: Custom DataGrid.Header - BUG in RC0.
Sep 29, 2008 07:21 PM | LINK
Here is the code I have tested:
1) Create a GridHeader custom control
[TemplatePart(Name = GridHeader.HeaderTextElement, Type = typeof(FrameworkElement))]
[TemplatePart(Name = GridHeader.FilterTextElement, Type = typeof(TextBox))]
public class GridHeader : Control
{
protected const string HeaderTextElement = "HeaderText";
protected const string FilterTextElement = "FilerText";
Button header;
TextBox filterText;
#region Constructor
public GridHeader()
{
this.DefaultStyleKey = typeof(GridHeader);
}
#endregion
#region HeaderText
/// <summary>
/// Identifies the HeaderText dependency property.
/// </summary>
public static readonly DependencyProperty HeaderTextProperty = DependencyProperty.Register("HeaderText", typeof(string), typeof(GridHeader), null);
/// <summary>
/// Gets or sets the HeaderText possible Value of the int object.
/// </summary>
public string HeaderText
{
get { return (string)GetValue(HeaderTextProperty); }
set { SetValue(HeaderTextProperty, value); }
}
#endregion HeaderText
#region FilterText
/// <summary>
/// Identifies the FilterText dependency property.
/// </summary>
public static readonly DependencyProperty FilterTextProperty = DependencyProperty.Register("FilterText", typeof(string), typeof(GridHeader), null);
/// <summary>
/// Gets or sets the FilterText possible Value of the string object.
/// </summary>
public string FilterText
{
get { return (string)GetValue(FilterTextProperty); }
set { SetValue(FilterTextProperty, value); }
}
#endregion FilterText
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
this.filterText = this.GetTemplateChild("FilterText") as TextBox;
this.header = this.GetTemplateChild("HeaderText") as Button;
if(this.filterText != null)
this.filterText.LostFocus += new RoutedEventHandler(filterText_LostFocus);
if(this.header != null)
this.header.Click += new RoutedEventHandler(header_Click);
}
void header_Click(object sender, RoutedEventArgs e)
{
}
void filterText_LostFocus(object sender, RoutedEventArgs e)
{
}
}
Put the following Template in the themes/generic.xaml file
<Style TargetType="controls:GridHeader">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="controls:GridHeader">
<StackPanel x:Name="LayoutRoot" Margin="3" Background="{TemplateBinding Background}">
<StackPanel HorizontalAlignment="Center" Orientation="Horizontal">
<TextBlock Text="{TemplateBinding HeaderText}" /> <!-- if you want default Sort -->
OR
<Button Content="{TemplateBinding HeaderText}" /> <!-- if you want to implement your own Sort -->
<!-- Your can add the Sort indicator image here -->
</StackPanel>
<TextBox Margin="2" x:Name="FilterTextBox" Text="{TemplateBinding FilterText}"/>
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Define Grid-header Style in the app.xaml:
<Application.Resources>
<Style x:Key="grid-header" TargetType="primitives:DataGridColumnHeader">
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="HorizontalAlignment" Value="Stretch" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<my:GridHeader HeaderText="{TemplateBinding Content}" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Application.Resources>
In your code:
col.Header = "YourColHeaderText";
col.HeaderStyle = col.HeaderStyle = Application.Current.Resources["grid-header"] as Style;
What I have found for sorting in RC0 DataGrid works differently from beta2:
If you want to use Default Sort function, either use default header or define your own header template but do not put a button in the template. This way, when you click the header, the sort would work. If you put a button in the Header template, click that button won't fire default sort.
If you defined your own header template, the sort indicator image no longer shows up even sort still work.
Software Engineer
Aprimo, Inc
Please remember to mark the replies as answers if they answered your question
Bartlomiej
Member
68 Points
45 Posts
Re: Custom DataGrid.Header - BUG in RC0.
Sep 30, 2008 10:41 AM | LINK
Thank you very much! The code is working. I really appreciate your effort!
But I think this approach doesn't solve my problem. The final code loks like below:
Everything works OK with Generic.xaml and style in App.xaml. But I still can't set up properties of the GridHeader BEFORE or AFTER setting the Column Style. I supposed something like that:
The "business" problem is that the client wants to store in db the width of the column after changing the size, last "sort order" on the column after changing the sort order and finally the last filter text put into the column header (maby there will be more "needs" in the future ...).
B.
sladapter
All-Star
43609 Points
7910 Posts
Re: Custom DataGrid.Header - BUG in RC0.
Sep 30, 2008 04:13 PM | LINK
Hi, So far I can think of is this: Move the grid_header style (Template) to the UserControl.Resources, then hook up Header_Loaded Event.
<UserControl.Resources>
<Style x:Key="grid-header" TargetType="primitives:DataGridColumnHeader">
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="HorizontalAlignment" Value="Stretch" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<my:GridHeader HeaderText="{TemplateBinding Content}" Loaded="Header_Loaded" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</UserControl.Resources>
private void GridHeader_Loaded(object sender, RoutedEventArgs e)
{
GridHeader h = sender as GridHeader;
// Check h.HeaderText to know which col you are on, based on that, set the FilterText, and Hookup Event handler (make sure you add the public event in the custom control)
h.FilterText = "YourFilterTest";
h.FilterLostFocus += ....
}
Well, I still like the way in beta2 better where we can set the control to the column.Header. Now it's really hard to get access to the controls defined in template ( a cross-board issue for getting access to the controls in template in Silverlight).
Software Engineer
Aprimo, Inc
Please remember to mark the replies as answers if they answered your question
Bartlomiej
Member
68 Points
45 Posts
Re: Custom DataGrid.Header - BUG in RC0.
Oct 01, 2008 03:25 PM | LINK
Good idea. The problem is that this <UserControl.Resources> in my case shoul be inside the XAML control of DataGridTemplateColumn. I don't know yet how to create the XAML file for DataGridColumn type because at present each my DataGridTemplateColumn is created in code, without XAML. On the other hand, a simple creation of the XAML control "myDataGridTemplateColumn" doesn't work, because UserControl type cann't be added as a Column: "DataGrid.Columns.Add(myDataGridTemplateColumn)". And (of course...) the base class of "myDataGridTemplateColumn" can't be a DataGridColumn type (must be "UserControl"). Thank you for all your help!
B.
sladapter
All-Star
43609 Points
7910 Posts
Re: Custom DataGrid.Header - BUG in RC0.
Oct 01, 2008 03:43 PM | LINK
The more I play with this, the more I think the design change for how to set col header in RC0 is flawed, unless I haven't found the correct way to do this.
The DataGridColumn.Header property is still Object type (just like in beta2), but you can not set anything other than the header text string to it which I think is wrong.
I even wrote a custom Header that inherited from DataGridColumnHeader object, but there is no way for me to set it to the DataGridColumnHeader._headerCell to replace the original DataGridColumnHeader object which is set internally.
I wrote a request in another thread asking this question. Hope someone from Microsoft can answer it.
You can follow that thread: http://silverlight.net/forums/t/30731.aspx
Software Engineer
Aprimo, Inc
Please remember to mark the replies as answers if they answered your question
Bartlomiej
Member
68 Points
45 Posts
Re: Custom DataGrid.Header - BUG in RC0.
Oct 01, 2008 04:06 PM | LINK
It's nice to hear somebody supports me. I've written the "suggestion" in another thread, too (http://silverlight.net/forums/p/31442/99361.aspx) but there is no answer. After your suggestion of "Loaded" event I've also tried to find "Parent" of my GridHeader in order to find the DataGridHeader, but the code:
gives null.
My next idea was to find the myHeader inside the HeaderStyle.Setters collection or sth, but with no effect, too.
In my opinion, the present type of using DataGrid.Header is completly useless when you want to make headers from code.
Thanks for the link. I'm interested in every information about this subject.
B.
sladapter
All-Star
43609 Points
7910 Posts
Re: Custom DataGrid.Header - BUG in RC0.
Oct 02, 2008 01:29 PM | LINK
For finding Parent for any control, you now need to use VisualTreeHelper.GetParent function instead of control.Parent property. Try that and see if you get the parent of the header.
Software Engineer
Aprimo, Inc
Please remember to mark the replies as answers if they answered your question
Bartlomiej
Member
68 Points
45 Posts
Re: Custom DataGrid.Header - BUG in RC0.
Oct 02, 2008 03:08 PM | LINK
Thanks for advice. Here is the tree of DataGridColumnHeader parents:
DataGridColumnHeader obj = (DataGridColumnHeader)VisualTreeHelper.GetParent(this); DataGridColumnHeadersPresenter obj1 = (DataGridColumnHeadersPresenter)VisualTreeHelper.GetParent(obj); Grid obj2 = (Grid)VisualTreeHelper.GetParent(obj1); Border obj3 = (Border)VisualTreeHelper.GetParent(obj2); DataGrid obj4 = (DataGrid)VisualTreeHelper.GetParent(obj3);