This message was discovered on ASPFriends.com 'aspngcontrolscs' list.
| Michael |
Well... I've posted a couple of pretty simple (dare I say dumb) questions recently, thanks Vandana for answering the last one. Hopefully this one is a little less of a flop !!
I've created a control with a property of type DataSet. It compiles fine. It works fine in the designer. ie when added to a web page, after creating a dataset, I can select the dataset for my DataSource property.
However when the web application is run I'm getting an exception which I'm unable to determine the cause of. I've tested using this same dataset with a datagrid and it ran as expected, so I'm positive it's something to do with my control and not the page. The exception seems to be occuring during the compilation stage of my web application. Can anyone help me out here ?
My control's code and the exception are as follows:-
MyText.cs:-
using System; using System.Data; using System.ComponentModel;
namespace TestControl { /// <summary> /// Test Textbox /// </summary> public class MyText : System.Web.UI.WebControls.TextBox { private DataSet _myDataSet = null;
/// <summary> /// DataSource /// </summary> [Bindable(false), Category("Data"), DefaultValue("")] public DataSet DataSource { get { return _myDataSet; }
set { _myDataSet = value; } }
public void DataBind() { Text = _myDataSet.GetXml(); } } }
Exception:-
Unable to generate code for a value of type 'System.Data.DataSet'. This error occurred while trying to generate the property value for DataSource. Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.Web.HttpException: Unable to generate code for a value of type 'System.Data.DataSet'. This error occurred while trying to generate the property value for DataSource.
Source Error:
An unhandled exception was generated during the execution of the current web request. Information regarding the origin and location of the exception can be identified using the exception stack trace below.
Stack Trace:
[HttpException (0x80004005): Unable to generate code for a value of type 'System.Data.DataSet'. This error occurred while trying to generate the property value for DataSource.]
System.Web.Compilation.CodeDomUtility.GenerateExpressionForValue(PropertyInf o propertyInfo, Object value, Type valueType)
System.Web.Compilation.TemplateControlCompiler.BuildBuildMethod(ControlBuild er builder, Boolean fTemplate, PropertySetterEntry pse)
System.Web.Compilation.TemplateControlCompiler.BuildSourceDataTreeFromBuilde r(ControlBuilder builder, Boolean fInTemplate, PropertySetterEntry pse)
System.Web.Compilation.TemplateControlCompiler.BuildSourceDataTreeFromBuilde r(ControlBuilder builder, Boolean fInTemplate, PropertySetterEntry pse)
System.Web.Compilation.TemplateControlCompiler.BuildSourceDataTreeFromBuilde r(ControlBuilder builder, Boolean fInTemplate, PropertySetterEntry pse) System.Web.Compilation.TemplateControlCompiler.BuildMiscClassMembers() System.Web.Compilation.PageCompiler.BuildMiscClassMembers() System.Web.Compilation.BaseCompiler.BuildSourceDataTree() System.Web.Compilation.BaseCompiler.GetCompiledType() System.Web.Compilation.PageCompiler.CompilePageType(PageParser pageParser) System.Web.UI.PageParser.CompileIntoType() System.Web.UI.TemplateParser.GetParserCacheItemThroughCompilation()
[HttpException (0x80004005): Unable to generate code for a value of type 'System.Data.DataSet'. This error occurred while trying to generate the property value for DataSource.] System.Web.UI.TemplateParser.GetParserCacheItemInternal(Boolean fCreateIfNotFound) System.Web.UI.TemplateParser.GetParserCacheItemWithNewConfigPath() System.Web.UI.TemplateParser.GetParserCacheItem() System.Web.UI.TemplateControlParser.CompileAndGetParserCacheItem(String virtualPath, String inputFile, HttpContext context) System.Web.UI.TemplateControlParser.GetCompiledInstance(String virtualPath, String inputFile, HttpContext context) System.Web.UI.PageParser.GetCompiledPageInstance(String virtualPath, String inputFile, HttpContext context) System.Web.UI.PageHandlerFactory.GetHandler(HttpContext context, String requestType, String url, String path) System.Web.HttpApplication.MapHttpHandler(HttpContext context, String requestType, String path, String pathTranslated, Boolean useAppConfig) System.Web.MapHandlerExecutionStep.Execute() System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)
|
|
| |
| |
| Dennis McCarthy |
Michael,
The problem is that the web form designer is not using the data binding syntax for the DataSource attribute of your control in the .aspx file. You need to implement a custom control designer that "shadows" the DataSource property of your control with a data binding. My solution to this problem, which was posted on microsoft.public.dotnet.framework.aspnet.buildingcontrols, is inlcuded below. (The code is in VB.NET, so you will have to translate to C# syntax.)
Dennis
----------------------------------------------------------------------------------------------------------------------
After much trial and error, along with poking around the .NET documentation, here is the answer. This is much simpler than the "Web Forms Templated Data-Bound Control Designer Sample" in the SDK documentation.
As Victor pointed out, you need to set the DesignerSerializationVisibility attribute of the DataSource property to Hidden, and implement a custom control designer.
<Designer("WebCustomControls.CustomControlDesigner"), _ ToolboxData("<{0}:DataBoundControl runat=server></{0}:DataBoundControl>")> _ Public Class DataBoundControl Inherits System.Web.UI.WebControls.WebControl : Implements INamingContainer
<Bindable(True), _
DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)> _ Public Property DataSource() As DataSet ...
The control designer class must work with the web forms designer to (A) write a DataSource attribute using data binding syntax to the .aspx file when the DataSource property is set using the property window (e.g., DataSource="<%#DataSet1%>"), and (B) inititialize the DataSource property using the DataSource attribute value whent the web form designer opens the .aspx file.
To implement (A) you override ControlDesigner.OnComponentChanged method. In this method you find the dataset component corresponding to the new value of the DataSource property, add a data binding for it, and call OnBindingsCollectionChanged to tell the web form designer to write the new binding to the .aspx file.
Public Overrides Sub OnComponentChanged(ByVal sender As Object, ByVal e As System.ComponentModel.Design.ComponentChangedEventArgs) If Not (e.Member Is Nothing) Then Dim memberName As String = e.Member.Name If memberName.Equals("DataSource") Then If e.NewValue Is Nothing Then DataBindings.Remove("DataSource") Else ' Find the component name of the new DataSource value Dim comp As IComponent Dim source As String = "" For Each comp In Me.Component.Site.Container.Components If comp Is e.NewValue Then source = comp.Site.Name End If Next ' Add a data binding for the new DataSource value Dim binding As New DataBinding("DataSource", GetType(AuthorTitles), source) Me.DataBindings.Add(binding) End If Me.OnBindingsCollectionChanged("DataSource") Me.UpdateDesignTimeHtml() End If End If MyBase.OnComponentChanged(sender, e) End Sub
To implement (B), you find the component whose name matches the data binding expression for the DataSource property, and set the DataSource property to that component. The trick is that this cannot be done until the web form designer has created both your control and the dataset component. So I put the logic to do this in the GetDesignTimeHtml method, and override the DesignTimeHtmlRequiresLoadComplete method to ensure that the GetDesignTimeHtml method is not called until after the dataset component has been loaded.
Public Overrides ReadOnly Property DesignTimeHtmlRequiresLoadComplete() As Boolean Get ' If there is a data binding for the DataSource, then the dataset component ' must be loaded so that the DataSource property can be set. If Me.DataBindings("DataSource") Is Nothing Then Return False Else Return True End If End Get End Property
Public Overrides Function GetDesignTimeHtml() As String ' Make sure that the DataSource property has been initialized. Dim control As DataBoundControl = CType(Component, DataBoundControl) Dim binding As DataBinding = Me.DataBindings("DataSource") If (control.DataSource Is Nothing) And (Not binding Is Nothing) Then Dim comp As IComponent For Each comp In Me.Component.Site.Container.Components If comp.Site.Name.Equals(binding.Expression) Then ' Set the DataSource to the dataset component with the matching name. control.DataSource = CType(comp.Site.Component, DataSet) End If Next End If ...
|
|
| |
|
|
|
|
|