| Home | Forums | Reviews | Guides | Newsgroups | Register | Search |
![]() |
| Thread Tools |
| Bill Anderson |
|
|
|
| |
|
Bill Anderson
Guest
Posts: n/a
|
I think I achieved what I wanted to do, so here is a
follow up in case any one wants to know. I found Rick Strahl's article on two way databinding. This works great, except you have to type the object name you want to bind to in the BindingSourceObject property (the value is a valid instance variable declared in code behind). Then you have to type the property of that object you want to bind to in the BindingSourceProperty. If a designer is not familar with the properties of an object, they would have to find them out somehow. I wanted this to be more RAD. I wanted to have these properties as dropdown boxes showing valid values. Here is what I did to achieve that. I created two custom typeconverters. The first type converter iterates through the code behind class of the active document that the textbox is sitting on. It finds all family level fields (protected) using reflection. Then, by attaching the typeconverter attribute to the bindingsourceobject property of the textbox, this creates a drop down at design time that shows all valid objects from the codebehind this textbox can bind to. The second type converter looks at the selected value from above. Based on the object selected, it uses reflection to get all public properties of the selected object and displays them in a drop down box. I attached this typeconverter to the BindingSourceProperty object. There are a couple of caveats. The code behind type has to be the same name as the web form (by default this is always the case when you create a new web form). Here is the code of the inherited textbox and the type converters..... ' ******************************************* ' TypeConverter Classes - WebBindingTypeConverters.vb '******************************************** Imports System.ComponentModel Imports EnvDTE Imports VSLangProj Imports System.Web.UI.Design Imports System.Web.UI Imports System.Reflection Public Class TypeInstanceConverter : Inherits DataSourceConverter Public Overloads Overrides Function GetStandardValues (ByVal context As System.ComponentModel.ITypeDescriptorContext) As System.ComponentModel.TypeConverter.StandardValues Collecti on Dim list1 As ArrayList Dim array1() As Object Dim sAssemblyName As String = "" Dim sTypeName As String = "" Dim a As System.Reflection.Assembly sAssemblyName = ReflectionHelperFunctions.GetProjectAssemblyName(c ontext) sTypeName = ReflectionHelperFunctions.GetActiveDocumentType(co ntext) list1 = New ArrayList If Not context Is Nothing Then Dim ass As System.Reflection.Assembly Try ass = System.Reflection.Assembly.Load (sAssemblyName) Catch ex As Exception ass = Nothing End Try If Not ass Is Nothing Then Dim t As System.Type Try t = ass.GetType(sAssemblyName & "." & sTypeName) Catch ex As Exception MsgBox(ex.Message) t = Nothing End Try If Not t Is Nothing Then For Each fi As FieldInfo In t.GetFields(ReflectionHelperFunctions.MemberAccess ) If fi.IsFamily Then list1.Add(fi.Name) End If Next End If End If End If array1 = list1.ToArray Array.Sort(array1, Comparer.Default) Return New StandardValuesCollection(array1) End Function End Class Public Class TypePropertyNameConverter : Inherits DataSourceConverter Public Overloads Overrides Function GetStandardValues (ByVal context As System.ComponentModel.ITypeDescriptorContext) As System.ComponentModel.TypeConverter.StandardValues Collecti on Dim list1 As ArrayList Dim array1() As Object Dim sAssemblyName As String Dim sTypeName As String sAssemblyName = ReflectionHelperFunctions.GetProjectAssemblyName(c ontext) sTypeName = ReflectionHelperFunctions.GetActiveDocumentType(co ntext) list1 = New ArrayList If Not context Is Nothing Then If TypeOf context.Instance Is IWebDataControl Then Dim c As IWebDataControl = CType (context.Instance, IWebDataControl) If Not c Is Nothing Then If Trim(c.BindingSourceObject).Length > 0 Then Dim ass As System.Reflection.Assembly ass = System.Reflection.Assembly.Load(sAssemblyName) Dim t As Type Try t = ass.GetType(sAssemblyName & "." & sTypeName, True) Catch ex As Exception t = Nothing End Try If Not t Is Nothing Then Try For Each f As FieldInfo In t.GetFields(ReflectionHelperFunctions.MemberAccess ) If f.IsFamily Then If f.Name = c.BindingSourceObject Then For Each p As PropertyInfo In f.FieldType.GetProperties Try list1.Add(p.Name) Catch ex As Exception End Try Next Exit For End If End If Next Catch ex As Exception MsgBox(ex.Message) End Try End If End If End If End If End If array1 = list1.ToArray Array.Sort(array1, Comparer.Default) Return New StandardValuesCollection(array1) End Function End Class Public Class ReflectionHelperFunctions Public Const MemberAccess As BindingFlags = BindingFlags.Public Or _ BindingFlags.NonPublic Or _ BindingFlags.Static Or _ BindingFlags.Instance Or _ BindingFlags.IgnoreCase Public Shared Function GetProjectAssemblyName(ByVal context As ITypeDescriptorContext) As String Dim item As ProjectItem Dim sAssemblyName As String item = CType(context.GetService(GetType (EnvDTE.ProjectItem)), ProjectItem) If Not item Is Nothing Then Dim project As VSProject project = CType (item.ContainingProject.Object, VSProject) If Not project Is Nothing Then For i As Int32 = 1 To project.Project.Properties.Count If project.Project.Properties.Item (i).Name = "AssemblyName" Then sAssemblyName = project.Project.Properties.Item(i).Value Exit For End If Next End If Else sAssemblyName = "" End If Return sAssemblyName End Function Public Shared Function GetActiveDocumentType(ByVal context As ITypeDescriptorContext) As String Dim sTypeName As String = "" Dim item As EnvDTE._DTE item = CType(context.GetService(GetType (EnvDTE._DTE)), EnvDTE._DTE) sTypeName = item.ActiveDocument.Name Return Trim(Left(sTypeName, sTypeName.IndexOf (".aspx"))) End Function End Class ' ********************************** ' TextBox Class - WebTextBox.vb ' *********************************** Imports System.Web.UI Imports System.Web.UI.Design Imports System.Web.I.WebControls Imports System.ComponentModel Imports System.Reflection Imports System.Drawing <DefaultProperty("BindingSourceObject"), _ ToolboxBitmap(GetType(TextBox)), _ ToolboxData("<{0}:WebTextBox runat=server></ {0}:WebTextBox>")> _ Public Class WebTextBox : Inherits TextBox Implements IWebDataControl Private mBindingSourceObject As String = "" Private mBindingSourceProperty As String = "" Private mBindingProperty As String = "Text" Private mDisplayFormat As String = "" Private mUserFieldName As String = "" Private mBindingErrorMessage As String = "" <TypeConverter(GetType(TypeInstanceConverter))> _ Public Property BindingSourceObject() As String Implements IWebDataControl.BindingSourceObject Get Return mBindingSourceObject End Get Set(ByVal Value As String) mBindingSourceObject = Value End Set End Property <TypeConverter(GetType(TypePropertyNameConverter)) > _ Public Property BindingSourceProperty() As String Implements IWebDataControl.BindingSourceProperty Get Return mBindingSourceProperty End Get Set(ByVal Value As String) mBindingSourceProperty = Value End Set End Property Public Property BindingErrorMessage() As String Implements IWebDataControl.BindingErrorMessage Get Return mBindingErrorMessage End Get Set(ByVal Value As String) mBindingErrorMessage = Value End Set End Property <DefaultValue("Text")> _ Public Property BindingProperty() As String Implements IWebDataControl.BindingProperty Get Return mBindingProperty End Get Set(ByVal Value As String) mBindingProperty = Value End Set End Property Public Property DisplayFormat() As String Implements IWebDataControl.DisplayFormat Get Return mDisplayFormat End Get Set(ByVal Value As String) mDisplayFormat = Value End Set End Property Public Overrides Property Text() As String Implements IWebDataControl.Text Get Return MyBase.Text End Get Set(ByVal Value As String) MyBase.Text = Value End Set End Property Public Property UserFieldName() As String Implements IWebDataControl.UserFieldName Get Return mUserFieldName End Get Set(ByVal Value As String) mUserFieldName = Value End Set End Property Public Sub UnbindData(ByVal WebForm As System.Web.UI.Page) Implements IWebDataControl.UnbindData WebDataHelper.ControlUnbindData(WebForm, Me) End Sub Public Sub BindData(ByVal WebForm As System.Web.UI.Page) Implements IWebDataControl.BindData WebDataHelper.ControlBindData(WebForm, Me) End Sub End Class >-----Original Message----- >Hi, > >I am trying to accomplish the following. > >Here is what I want to do: >1. Drop a custom business object component onto the >design surface and have it show up in the area below the >designer grid in VisStudio (like a dataadapter or dataset >does). > >2. Drag a textbox webcontrol and change a custom >datasource property to the component from step 1. The >property grid will display a drop down of available >datasources (i want the textbox to work like a dropdown >control). > >3. Based on the datasource chosen, change a >DataTextField property to a valid property of the >component. The property grid will show a drop down of >available Public Properties (fields) from the component >selected (basically, binding values to the textbox work >like the dropdown box does when binding to a dataset). > >4. The Datasource and DataTextField values chosen will >persist as attributes in HTML on the custom component. > >5. The componet is a basic business object. It does not >implement IEnumerable or IListsource (it does implement >IComponent). It just exposes public properties. > >I have all of this working fine if the custom component >is of type Collection. But I don't want a Collection, >just the ability to bind to Public Properties of a basic >class. > >I think have taken care of most of the items as follow, >but I am stuck on #5: >1. Implement IComponent on the business class. >2. Created custom control derived from Textbox webcontrol. >3. Created custom Designer that implements >IDatasourceprovider, and attach to custom textbox control. >4. Put designerserialization attribute of visible on >properties of custom textbox control. >5. Can't get to work unless the component Implements >IEnumerable, and then it only shows up in the datasource >drop down. I can never get the properties to list out >unless i have a stongly typed collection of busines >objects. > >here is some sample code(i shortened syntax for brevity): > ><Designer(Gettype(MyCustomDesigner)), otherattributes...> >_ >Public Class MyTextBox : Inherits from TextBox > >Private mDataSource as string = "" >Private mDataTextField as string = "" > ><otherattributes, designerserialation...(visible)> _ >Public Property DataSource as string >get >return mDataSource >end get >set(Value as string) >mDataSource = Value >end set >end property > >'Repeat for the DataTextField Property > >End Class > >Public Class MyAddressObject : Implements IComponent, >IEnumberable 'IEnumerable causes this to become a valid >datasource in the datasource drop down. Should I use >something else?. > >Private mStreet as string >Private mCity as string >Private mSite as ISite >'etc. > >'Implement IComponet stuff here >'If IEnumberable is needed, how to implement >GetEnumerator? > >Public Property Street as string >get >return mStreet >end get >set(Value as string) >mStreet = Value >end set >end property > >'Implement the rest of the properties > >End Class > >Public Class WebDataBoundDesigner : Inherits >ControlDesigner > Implements IDataSourceProvider > >Public Property DataTextField() As String > Get > Return CType(Me.Component, >MyTextBox).DataTextField > End Get > Set(ByVal Value As String) > CType(Me.Component, MyTextBox).DataTextField >= Value > End Set > End Property > >Public Property DataSource() As String > Get > Return CType(Me.Component, >MyTextBox).DataSource > End Get > Set(ByVal Value As String) > CType(Me.Component, MyTextBox).DataSource = >Value > OnBindingsCollectionChanged("DataSource") > End Set > End Property > >Public Function GetResolvedSelectedDataSource() As >System.Collections.IEnumerable Implements >System.Web.UI.Design.IDataSourceProvider.GetResol vedSelec t >edDataSource > If Me.DataSource.Length > 0 Then > Return DesignTimeData.GetSelectedDataSource >(Me.Component, Me.DataSource, Me.DataTextField) > End If > Return Nothing > End Function > >Public Function GetSelectedDataSource() As Object >Implements >System.Web.UI.Design.IDataSourceProvider.GetSelec tedDataS o >urce > If Me.DataSource.Length > 0 Then > Return DesignTimeData.GetSelectedDataSource >(Me.Component, Me.DataSource) > End If > Return Nothing > End Function > >Protected Overrides Sub PreFilterProperties(ByVal >properties As System.Collections.IDictionary) > MyBase.PreFilterProperties(properties) > Dim prop As PropertyDescriptor > > prop = CType(properties("DataSource"), >PropertyDescriptor) > prop = TypeDescriptor.CreateProperty >(Me.GetType, "DataSource", GetType(String), New Attribute >() {New TypeConverterAttribute(GetType >(DataSourceConverter))}) > properties("DataSource") = prop > > prop = CType(properties("DataTextField"), >PropertyDescriptor) > prop = TypeDescriptor.CreateProperty >(Me.GetType, "DataTextField", GetType(String), New >Attribute() {New TypeConverterAttribute(GetType >(DataFieldConverter))}) > properties("DataTextField") = prop >End Sub >End Class >. > |
|
|
|
|
|||
|
|||
| Bill Anderson |
|
|
|
| |
![]() |
| Thread Tools | |
|
|
Similar Threads
|
||||
| Thread | Thread Starter | Forum | Replies | Last Post |
| Complex data binding question, binding child objects of a custom collection. | JcFx | ASP .Net Datagrid Control | 0 | 06-01-2005 04:01 PM |
| Is there any POP3 and NNTP component I can use as a ASP Component? | Miguel Minora | ASP General | 1 | 01-11-2005 10:16 PM |
| com+ component and Component Service | Karuppasamy | ASP .Net | 1 | 01-14-2004 11:30 PM |
| com+ component and Component Service | Karuppasamy | ASP .Net | 0 | 01-13-2004 06:09 PM |
| event binding and component.config | Scott Holmes | Python | 1 | 08-27-2003 01:03 PM |
Powered by vBulletin®. Copyright ©2000 - 2013, vBulletin Solutions, Inc..
SEO by vBSEO ©2010, Crawlability, Inc. |




