all groups > asp.net building controls > february 2007 >
You're in the asp.net building controls group:
GridView DataBind() Not Working
asp.net building controls:
I have a GridView as a child control in a custom composite control which is stubornly refusing to databind at design time. I'm convinced I must be missing something about how the databinding process works differently at design time. Here is the code that constructs the GridView in CreateChildControls(): gridSearch = new GridView(); gridSearch.AutoGenerateColumns = true; CommandField cmdField = new CommandField(); cmdField.ShowSelectButton = false; cmdField.SelectText = "select"; gridSearch.Columns.Add(cmdField); FieldInfoCollection fieldColl = DesignMode ? DummyData.Fields : SearchFields; for( int idx = 0; idx < fieldColl.Count; idx++ ) { BoundField curField = new BoundField(); curField.HeaderText = fieldColl[idx].Friendly; curField.DataField = fieldColl[idx].FieldName; curField.ReadOnly = true; curField.ShowHeader = true; curField.Visible = true; gridSearch.Columns.Add(curField); } At design time DummyData.Fields is composed of five "rows" of data in a List<>, where each row is a simple object: public class DummyDataItem { private int row = 0; public DummyDataItem( int row ) { this.row = row; } protected string FieldValue( int row, int col ) { return String.Format("Field{0}_Row{1}", col, row); } public string Field1 { get { return FieldValue(row, 1); } } public string Field2 { get { return FieldValue(row, 2); } } public string Field3 { get { return FieldValue(row, 3); } } } DummyData.Fields simply returns a list that has FieldNames of Field1, Field2 and Field3, corresponding to the properties in DummyDataItem. Later on the composite control that contains the GridView has its DataSource property set to that List<> of DummyDataItems, and then the following code gets called in an event handler: gridSearch.DataSource = DataSource; gridSearch.DataBind(); No rows are created. No exceptions are thrown. I can walk over the code in the debugger, so I know the event handler is being triggered. I verified that the gridSearch, at the point of the DataBind() call, has columns with DataField properties equal to Field1, Field2 and Field3. Yet it doesn't work. How could this be any simpler? Do GridViews not work with List<> of objects exposing public string properties? I would appreciate some advice or suggestions.
Hello Mark, From your description, you're developing an ASP.NET custom web control which contains a child Gridview control. However, you're getting difficulty when try rendering the custom control in design-view, the gridview does not display, correct? Based on my experience, for ASP.NET custom webcontrol, it would preferred that we separate the design-time rendering code from runtime code as much as possible. And normally there would exists a ControlDesigner associated with a given webcontrol and provide the "GetDesignTimeHtml" that do the design-time rendering task. For your scenario, you've added a chld GridView in your custom web control, then how do you assign the datasource and perform the databinding on the child gridview? I haven't found the related code in code snippet you attached. I assume you've exposed a top level property on your custom control to accept the DataSource, and make the custom control's DataBind method to trigger the child GridView's DataBinding, correct? I think the problem that GridView not display may caused by the databinding is not correctly performed at the design-time rendering stage, I'll try performing some tests on my side to see whether I can get it work with the control designer interface. I'll update you as soon as possible. Also, if there is anything I missed above, please feel free to inform me. Sincerely, Steven Cheng Microsoft MSDN Online Support Lead ================================================== Get notification to my posts through email? Please refer to http://msdn.microsoft.com/subscriptions/managednewsgroups/default.aspx#notif ications. Note: The MSDN Managed Newsgroup support offering is for non-urgent issues where an initial response from the community or a Microsoft Support Engineer within 1 business day is acceptable. Please note that each follow up response may take approximately 2 business days as the support professional working with you may need further investigation to reach the most efficient resolution. The offering is not appropriate for situations that require urgent, real-time or phone-based interactions or complex project analysis and dump analysis issues. Issues of this nature are best handled working with a dedicated Microsoft Support Engineer by contacting Microsoft Customer Support Services (CSS) at http://msdn.microsoft.com/subscriptions/support/default.aspx. ================================================== This posting is provided "AS IS" with no warranties, and confers no rights.
Steven, Thanks for looking into this. I'm interested in hearing what you come up with. I have continued to struggle with this problem (I think I'm now up to the 20th different approach, which involves replicating a lot of the functionality of the Wizard control because, unfortunately, some of the key classes I'd like to utilize, like the WizardSteps ControlBuilder, are sealed). This GridView problem is a real puzzler, however. I've tried approaches where the custom control it's created within is a databound control, and approaches where it isnt', without any success. The thing I find most confusing, though, is that, regardless of the type of control on which it's hosted (i.e., regardless of whether or not the hosting control is a databound control or not), even these code snippets fail (all this stuff would be in the custom control hosting the GridView): public class SomeCustomControl : <either DataBoundCompositeControl or CompositeControl> { private GridView theGrid; protected override void CreateChildControls() { ... theGrid = new GridView(); Controls.Add(theGrid); ... } protected override void OnInit( EventArgs e ) { base.OnInit(e); theGrid.DataSource = <some dummy data source>; theGrid.DataBind(); // fails; no rows created, no exceptions thrown } protected override RenderControl( HtmlWriter writer ) { theGrid.DataSource = <some dummy data source>; theGrid.DataBind(); // fails; no rows created, no exceptions thrown base.RenderControl(writer); } ... } I tried sticking that test code into OnInit and RenderControl because I read somewhere that, at design-time, the control life-cycle is "abbreviated", and only the OnInit and Rendering phases get executed (i.e., no OnLoad()). But why wouldn't the DataBind() in either of those handlers work? I know that I could run into problems with persistance if I bind too late, but for the test I don't care if the rows "disappear" later -- I just want to see them created. And they never get created! I keep thinking that maybe there's something wrong with my dummy data source, but all it is is five objects in a list, where each object has three properties (Field1, Field2, and Field3)...and I've verified that, at the point of the DataBind(), the GridView has three columns with DataField values of Field1, Field2 and Field3. So I dont' see how the data could be a problem. I've also created some dummy derived GridView classes that don't add any functionality to the GridView: [Designer(MyGridViewDesigner)] public class MyGridView : GridView { } I overrode a bunch of methods in MyGridViewDesigner (but added no new functionality), and then put an instance of MyGridView on a test web page so I could watch how the design-time databinding takes place -- it works fine (i.e., dummy rows and columns get displayed), and I can see where the designer methods get called. But then using MyGridView in my composite control leads to...nothing again. No calls to the designer methods. No dummy data displayed. So the GridView is behaving differently depending upon whether it's instantiated on a webpage at design time, or within a custom control that, in turn, is instantiated at design time. Why in the world should that happen? I look forward to hearing what you come up with. - Mark
Thanks for your reply Mark, yes, based on my research, if you completely add the rendering code logic(both for runtime and design-time) in your control's code(CreateChildcontrols), the designer (of your toplevel custom control) will not render the child GridView. Also, as you discussed in another thread with my colleague Walter, for child controls added into top custom control's controls collection, it hasn't a designer associated like the top level control. Currently, what I'm still trying is use our own custom control designer and render the control (and its child controls) manually. And I've got the following result so far: *in our custom control designer, we can create a new instance of our custom control type and render it(or you can set some additional attributes on it) e.g. ================================= [DefaultProperty("Text")] [ToolboxData("<{0}:MyComposite runat=server></{0}:MyComposite>")] [Designer(typeof(MyCompositeDesigner))] public class MyComposite : CompositeControl { Label _label; GridView _grid; [Bindable(true)] [Category("Appearance")] [DefaultValue("")] [Localizable(true)] public string Text { get { String s = (String)ViewState["Text"]; return ((s == null) ? String.Empty : s); } set { ViewState["Text"] = value; } } protected override void CreateChildControls() { Controls.Clear(); _label = new Label(); _label.ID = "lblMessage"; Controls.Add(_label); _label.Text = Text; _grid = new GridView(); _grid.ID = "gvData"; Controls.Add(_grid); _grid.AutoGenerateColumns = true; _grid.DataSource = HelperUtil.GetDummyListItems(); _grid.DataBind(); } } internal class HelperUtil { internal static ListItem[] GetDummyListItems() { ListItem[] items = new ListItem[5]; for (int i = 0; i < items.Length; i++) { items[i] = new ListItem("key" + i, "value" + i); } return items; } } internal class MyCompositeDesigner : CompositeControlDesigner { public override string GetDesignTimeHtml() { string html = string.Empty; MyCompositeControl mc1 = new MyCompositeControl(); ICompositeControlDesignerAccessor accessor = mc1 as ICompositeControlDesignerAccessor; accessor.RecreateChildControls(); StringWriter sw = new StringWriter(); XhtmlTextWriter hw = new XhtmlTextWriter(sw); mc1.RenderControl(hw); html+= sw.ToString(); return html; } } ========================== However, if I try using the control instance from the designer's "ViewControl" property to render, the child GridView always not display. e.g. ====================== public override string GetDesignTimeHtml() { string html = string.Empty; WebControl mc1 = new MyComposite(); mc1 = this.ViewControl as WebControl; ICompositeControlDesignerAccessor accessor = mc1 as ICompositeControlDesignerAccessor; accessor.RecreateChildControls(); StringWriter sw = new StringWriter(); XhtmlTextWriter hw = new XhtmlTextWriter(sw); mc1.RenderControl(hw); html+= sw.ToString(); return html; } ======================= I will do some further research on this to see whether it does be not supported to use the original instance for manual rendering in designer or if there is any other means. Anyway, at least you can do custom rendering in custom control designer by manually creating a control instance. I'll update you when I get any progress at the earliest time. Sincerely, Steven Cheng Microsoft MSDN Online Support Lead This posting is provided "AS IS" with no warranties, and confers no rights.
Steven, Thanks for the research. I await further results. What do you mean by "...at least you can do custom rendering in custom control designer by manually creating a control instance"? Do you mean to create a dummy GridView and slip it into the Controls collection for the control being designed? Or into the render stream for GetDesignTimeHtml()? - Mark [quoted text, click to view] >Thanks for your reply Mark, > >yes, based on my research, if you completely add the rendering code >logic(both for runtime and design-time) in your control's >code(CreateChildcontrols), the designer (of your toplevel custom control) >will not render the child GridView. Also, as you discussed in another >thread with my colleague Walter, for child controls added into top custom >control's controls collection, it hasn't a designer associated like the top >level control. > >Currently, what I'm still trying is use our own custom control designer and >render the control (and its child controls) manually. And I've got the >following result so far: > >*in our custom control designer, we can create a new instance of our custom >control type and render it(or you can set some additional attributes on it) >e.g. > >================================= > [DefaultProperty("Text")] > [ToolboxData("<{0}:MyComposite runat=server></{0}:MyComposite>")] > [Designer(typeof(MyCompositeDesigner))] > public class MyComposite : CompositeControl > { > Label _label; > GridView _grid; > > > [Bindable(true)] > [Category("Appearance")] > [DefaultValue("")] > [Localizable(true)] > public string Text > { > get > { > String s = (String)ViewState["Text"]; > return ((s == null) ? String.Empty : s); > } > > set > { > ViewState["Text"] = value; > } > } > > > > protected override void CreateChildControls() > { > Controls.Clear(); > > _label = new Label(); > _label.ID = "lblMessage"; > Controls.Add(_label); > > _label.Text = Text; > > _grid = new GridView(); > _grid.ID = "gvData"; > Controls.Add(_grid); > > _grid.AutoGenerateColumns = true; > > _grid.DataSource = HelperUtil.GetDummyListItems(); > _grid.DataBind(); > > > } > > > > > } > > internal class HelperUtil > { > internal static ListItem[] GetDummyListItems() > { > ListItem[] items = new ListItem[5]; > for (int i = 0; i < items.Length; i++) > { > items[i] = new ListItem("key" + i, "value" + i); > } > > return items; > } > } > > internal class MyCompositeDesigner : CompositeControlDesigner > { > >public override string GetDesignTimeHtml() > { > string html = string.Empty; > > MyCompositeControl mc1 = new MyCompositeControl(); > > > ICompositeControlDesignerAccessor accessor = mc1 as >ICompositeControlDesignerAccessor; > > accessor.RecreateChildControls(); > > > > StringWriter sw = new StringWriter(); > XhtmlTextWriter hw = new XhtmlTextWriter(sw); > > mc1.RenderControl(hw); > > html+= sw.ToString(); > > > return html; > } >} >========================== > >However, if I try using the control instance from the designer's >"ViewControl" property to render, the child GridView always not display. >e.g. >====================== >public override string GetDesignTimeHtml() > { > string html = string.Empty; > > > > WebControl mc1 = new MyComposite(); > > mc1 = this.ViewControl as WebControl; > > > ICompositeControlDesignerAccessor accessor = mc1 as >ICompositeControlDesignerAccessor; > > accessor.RecreateChildControls(); > > > > > StringWriter sw = new StringWriter(); > XhtmlTextWriter hw = new XhtmlTextWriter(sw); > > mc1.RenderControl(hw); > > html+= sw.ToString(); > > > return html; > } >======================= > >I will do some further research on this to see whether it does be not >supported to use the original instance for manual rendering in designer or >if there is any other means. Anyway, at least you can do custom rendering >in custom control designer by manually creating a control instance. I'll >update you when I get any progress at the earliest time. > > >Sincerely, > >Steven Cheng > >Microsoft MSDN Online Support Lead > > > >This posting is provided "AS IS" with no warranties, and confers no rights. > >
Hi Mark, I mean completely create a new instance of the custom control type in Designer's GetDesignTimeHtml method and render it manually. e.g. ========================== public override string GetDesignTimeHtml() { string html = string.Empty; MyCompositeControl mc1 = new MyCompositeControl(); ICompositeControlDesignerAccessor accessor = mc1 as ICompositeControlDesignerAccessor; accessor.RecreateChildControls(); StringWriter sw = new StringWriter(); XhtmlTextWriter hw = new XhtmlTextWriter(sw); mc1.RenderControl(hw); html+= sw.ToString(); return html; } ============================== I'll update you for any new information on this. Sincerely, Steven Cheng Microsoft MSDN Online Support Lead This posting is provided "AS IS" with no warranties, and confers no rights.
Hi Mark, Just inform you that I'm still working on this. So far I still haven't been able to make the designer automatically render out the child nested Gridview in designer view. I'll perform some further research. Sincerely, Steven Cheng Microsoft MSDN Online Support Lead This posting is provided "AS IS" with no warranties, and confers no rights.
Hi Mark, After some further investigation and discussing with some other engineers. I've found the cause of the problem. Actually, it is related to our control's creation code in "CreaetChildControls" method(I have pasted my modified test control which works at design-time). The problem is that we need to add the child controls into parent container control after they have been initialized(or databound). For example, You should first create the GridView, and set the certain properties on it, bind it with data, after all those operations, you add it into parent container's controls collection. If you add it into parent container right after you create it, then, the designer won't render out the changes you did later. I think this behavior is due to the internal rendering mechanism of designer. ===complete test control==== namespace WebControlLib { [DefaultProperty("Text")] [ToolboxData("<{0}:MyComposite runat=server></{0}:MyComposite>")] public class MyComposite : CompositeControl { Label _label; GridView _grid; [Bindable(true)] [Category("Appearance")] [DefaultValue("")] [Localizable(true)] public string Text { get { String s = (String)ViewState["Text"]; return ((s == null) ? String.Empty : s); } set { ViewState["Text"] = value; } } protected override void CreateChildControls() { Controls.Clear(); _label = new Label(); _label.ID = "lblMessage"; _label.Text = Text; _grid = new GridView(); _grid.ID = "gvData"; _grid.AutoGenerateColumns = true; if (DesignMode) { _grid.DataSource = HelperUtil.GetDummyListItems(); _grid.DataBind(); } Controls.Add(_label); Controls.Add(_grid); } } internal class HelperUtil { internal static ListItem[] GetDummyListItems() { ListItem[] items = new ListItem[5]; for (int i = 0; i < items.Length; i++) { items[i] = new ListItem("key" + i, "value" + i); } return items; } } } ================================= Sincerely, Steven Cheng Microsoft MSDN Online Support Lead This posting is provided "AS IS" with no warranties, and confers no rights.
Steven, Thanx for digging into the issue. That's effectively what I'm doing now. I hope you share with your engineers the notion that it's really not a good idea to have code execute methods like DataBind() on a datasource...and have nothing happen. >>Something<< has to happen, even if it's just an exception! - Mark [quoted text, click to view] On Wed, 28 Feb 2007 13:38:12 GMT, stcheng@online.microsoft.com (Steven Cheng[MSFT]) wrote: >Hi Mark, > >After some further investigation and discussing with some other engineers. >I've found the cause of the problem. Actually, it is related to our >control's creation code in "CreaetChildControls" method(I have pasted my >modified test control which works at design-time). The problem is that we >need to add the child controls into parent container control after they >have been initialized(or databound). For example, > >You should first create the GridView, and set the certain properties on it, >bind it with data, after all those operations, you add it into parent >container's controls collection. If you add it into parent container right >after you create it, then, the designer won't render out the changes you >did later. I think this behavior is due to the internal rendering >mechanism of designer. > > > >===complete test control==== >namespace WebControlLib >{ > [DefaultProperty("Text")] > [ToolboxData("<{0}:MyComposite runat=server></{0}:MyComposite>")] > public class MyComposite : CompositeControl > { > Label _label; > GridView _grid; > > [Bindable(true)] > [Category("Appearance")] > [DefaultValue("")] > [Localizable(true)] > public string Text > { > get > { > String s = (String)ViewState["Text"]; > return ((s == null) ? String.Empty : s); > } > set > { > ViewState["Text"] = value; > } > } > > protected override void CreateChildControls() > { > Controls.Clear(); > > _label = new Label(); > _label.ID = "lblMessage"; > _label.Text = Text; > > _grid = new GridView(); > _grid.ID = "gvData"; > > _grid.AutoGenerateColumns = true; > > if (DesignMode) > { > _grid.DataSource = HelperUtil.GetDummyListItems(); > _grid.DataBind(); > } > > Controls.Add(_label); > Controls.Add(_grid); > > } > } > > internal class HelperUtil > { > internal static ListItem[] GetDummyListItems() > { > ListItem[] items = new ListItem[5]; > for (int i = 0; i < items.Length; i++) > { > items[i] = new ListItem("key" + i, "value" + i); > } > return items; > } > } >} >================================= > > >Sincerely, > >Steven Cheng > >Microsoft MSDN Online Support Lead > > >
I am having a slightly different problem trying to use a gridview in a composite control. If I set the AutoGenerateColumns = True, everything works fine. However, I want to control the columns that are displayed, so I want to set AutoGenerateColumns = False. I then create several BoundField objects that I add to the columns collection. The problem is, no columns show up at all. Is there something else that I have to do to have it generate the columns using my Columns collection? An abbreviated code snippet from my CreateChildControls function is as follows: gv.ID = "gv" gv.AutoGenerateColumns = False gv.DataKeyNames = strDataKeyNames gv.DataSource = CoreCategoryLookupTable gv.DataBind() Dim objBoundField As BoundField objBoundField = New BoundField objBoundField.DataField = "Category1" objBoundField.HeaderText = "Category 1" gv.Columns.Add(objBoundField) Me.Controls.Add(gv) Any help that you can give would be very much appreciated. Thank you.
Thanks for your reply Mark, Glad that you've also found that. Sure, I'll take care of the datasource issue, and also recommend you submit this to our product feedback center so that the product team and also get awared of this: http://connect.microsoft.com/feedback/default.aspx?SiteID=210 Sincerely, Steven Cheng Microsoft MSDN Online Support Lead This posting is provided "AS IS" with no warranties, and confers no rights.
Don't see what you're looking for? Try a search.
|
|
|