I finally figured out an acceptable solution.
The TemplateFields themselves are automatically restored from viewstate, but the templates themselves aren't (the field's Item/Header/FooterTemplate properties are null).
Note: I can't explain it, but I have to call gv.Columns.Clear() before adding dynamic columns, otherwise it doesn't even remember the TemplateFields...
So my solution is to cache the gridview's columns collection and call the following method in Page_Load (or earlier):
protected void restore_columns() {
DataControlFieldCollection columns = (DataControlFieldCollection)Cache["cols"];
gvSchluessel.Columns.Clear(); // gvSchluessel is the GridView
foreach (DataControlField field in columns) {
gvSchluessel.Columns.Add(field);
if (field.GetType() == typeof(TemplateField)) {
TemplateField tf = (TemplateField)field;
int i = gvSchluessel.Columns.IndexOf(tf);
if (tf.HeaderTemplate != null) {
tf.HeaderTemplate.InstantiateIn(gvSchluessel.HeaderRow.Cells[i]);
}
foreach (GridViewRow row in gvSchluessel.Rows)
{
if (tf.ItemTemplate != null) {
tf.ItemTemplate.InstantiateIn(row.Cells[i]);
}
}
if (tf.FooterTemplate != null) {
tf.FooterTemplate.InstantiateIn(gvSchluessel.FooterRow.Cells[i]);
}
}
}
}Note that I call the template's InstantiateIn() method manually instead of binding the gridview, so I don't need to cache any data source for it.
If your grid also contains many predefined fields (bound fields etc.), you could further improve performance by only caching and replacing the TemplateFields.
I hope this is of use for some of you.