hi Paul, I know you got his covered Jeffery and hope you dont mind, but I
got a quick answer here coz this is something i uselessly implemented into a
custom control i were building last month and then after all that
work(homework) had to remove it coz the needs of my control changed, lol ;P
Luckily I had come by an article online written by Shaun Wilde
http://www.codeproject.com/aspnet/webcontrolsdatabinding.asp to whom i'm
eternally grateful, and converted his C# implementation to vb.net. So I
really didnt do too much work ;P
Ok so, if i'm not wrong your looking for something like a datasource
property exposed by your control, and when the datasource is selected, you
could have them use the dataMember property to select a particular table
from within the supplied data source and if that is not enough, you can
further expose a DataTextField and DataValueField properties to select a
particular field from the default or selected table(datamember) from the
already selected data source.
Your going to have to use your designer class for this and implement the
IDataSourceProvider interface. IDataSourceProvider defines an interface that
a control designer can implement to provide access to a data source. That
said, when implementing this interface in your designer class you must
override : GetResolvedSelectedDataSource and GetSelectedDataSource. Your
going to have to also override the PreFilterProperties method in your
designer class. This is the method that binds the controls
DataSource,DataTextField,DataValueField,DataMember property and the
designers DataSource, DataTextField, DataValueField, DataMember property
together. This is how you see the dropdowns when selecting the datamember
property for instance showing the available tables.
The IDataSourceProvider interface is also used by DataSourceConverter ,
DataFieldConverter and DataMemberConverter which you will be using in your
designer class.
Here is what you need to do in your control first, depending on what
properties you want to expose, I'm exposing all three properties,
Datasource, DataMember and DataField. Comment out the ones you dont want ;P
in your control class :
<Bindable(True), _
DefaultValue(""), _
Category("Data"), _
Description("The data source.")> _
Public Property DataTextField() As String
Get
Return _dataTextField
End Get
Set(ByVal Value As String)
_dataTextField = Value
End Set
End Property
<Bindable(True), _
DefaultValue(""), _
Category("Data"), _
Description("select a particular field from the default or
selected table")> _
Public Property DataValueField() As String
Get
Return _dataValueField
End Get
Set(ByVal Value As String)
_dataValueField = Value
End Set
End Property
<Bindable(True), _
DefaultValue(""), _
Category("Data"), _
Description("The table from within the selected datasource.")> _
Public Property DataMember() As String
Get
Return _dataMember
End Get
Set(ByVal Value As String)
_dataMember = Value
End Set
End Property
now your designer class :
Implements IDataSourceProvider
'We use the designer to allow us to represent DataSource
'which is an object type property as a string type.
'To this designer class we add a DataSource property that is of type
string
'This property of type string is needed to wire the DataSource
property of the
'control at design-time
Public Property DataSource() As String
Get
Dim binding As DataBinding = DataBindings("DataSource")
If Not (binding Is Nothing) Then
Return binding.Expression
End If
Return [String].Empty
End Get
Set(ByVal Value As String)
If Value Is Nothing Or Value.Length = 0 Then
DataBindings.Remove("DataSource")
Else
Dim binding As DataBinding = DataBindings("DataSource")
If binding Is Nothing Then
binding = New DataBinding("DataSource",
GetType(IEnumerable), Value)
Else
binding.Expression = Value
End If
DataBindings.Add(binding)
End If
'This is the method that actually adds the <%# %>
OnBindingsCollectionChanged("DataSource")
End Set
End Property
'The DataMember is used to select a particular table from within
'a supplied data source such as a DataSet or if it is empty
'then the control should use the first available table or DataView.
'All of the work to implement a DataMember property such that in
'the Properties window it will be represented as a combobox with a
'list of available tables is done in the designer class.
Public Property DataMember() As String
Get
Return CType(Me.Component, MyControl).DataMember
End Get
Set(ByVal Value As String)
CType(Me.Component, MyControl).DataMember = Value
End Set
End Property
'The DataTextField and DataValueField properties are to be
'used to select a particular field from the default or selected
'table from a preselected data source. Again all the work required
to
'allow us to select from a list of available fields is also done in
this class.
'We add a property that is used to attach the required type
converter,
'which is DataFieldConverter, and we also add the type converter to
'the attributes in the PreFilterProperties method.
Public Property DataTextField() As String
Get
Return CType(Me.Component, MyControl).DataTextField
End Get
Set(ByVal Value As String)
CType(Me.Component, MyControl).DataTextField = Value
End Set
End Property
Public Property DataValueField() As String
Get
Return CType(Me.Component, MyControl).DataValueField
End Get
Set(ByVal Value As String)
CType(Me.Component, MyControl).DataValueField = Value
End Set
End Property
' Adding a type converter called
DataSourceConverter,DataFieldConverter,DataMemberConverter to the above
property
'so that it will correctly enumerate the available data
'sources that exist on the WebForm and present them in the
'Properties window as a combobox.
'To add this converter we need to override the PreFilterProperties
method
'and add the TypeConverter attribute dynamically to the
'DataSource,DataTextField,DataValueField,DataMember property at
Design runtime
'This is the glue that binds the controls
'DataSource,DataTextField,DataValueField,DataMember property and
'the designers DataSource,DataTextField,DataValueField,DataMember
property
'together as well as gives us the
'dropdown list of the datasources available to choose from.
Protected Overrides Sub PreFilterProperties(ByVal properties As
IDictionary)
MyBase.PreFilterProperties(properties)
Dim prop As PropertyDescriptor = CType(properties("DataSource"),
PropertyDescriptor)
If Not (prop Is Nothing) Then
Dim runtimeAttributes As AttributeCollection =
prop.Attributes
Dim attrs(runtimeAttributes.Count) As Attribute
runtimeAttributes.CopyTo(attrs, 0)
attrs(runtimeAttributes.Count) = New
TypeConverterAttribute(GetType(DataSourceConverter))
prop = TypeDescriptor.CreateProperty(Me.GetType(),
"DataSource", GetType(String), attrs)
properties("DataSource") = prop
End If
prop = CType(properties("DataMember"), PropertyDescriptor)
If Not (prop Is Nothing) Then
Dim runtimeAttributes As AttributeCollection =
prop.Attributes
Dim attrs(runtimeAttributes.Count) As Attribute
runtimeAttributes.CopyTo(attrs, 0)
attrs(runtimeAttributes.Count) = New
TypeConverterAttribute(GetType(DataMemberConverter))
prop = TypeDescriptor.CreateProperty(Me.GetType(),
"DataMember", GetType(String), attrs)
properties("DataMember") = prop
End If
prop = CType(properties("DataValueField"), PropertyDescriptor)
If Not (prop Is Nothing) Then
Dim runtimeAttributes As AttributeCollection =
prop.Attributes
Dim attrs(runtimeAttributes.Count) As Attribute
runtimeAttributes.CopyTo(attrs, 0)
attrs(runtimeAttributes.Count) = New
TypeConverterAttribute(GetType(DataFieldConverter))
prop = TypeDescriptor.CreateProperty(Me.GetType(),
"DataValueField", GetType(String), attrs)
properties("DataValueField") = prop
End If
prop = CType(properties("DataTextField"), PropertyDescriptor)
If Not (prop Is Nothing) Then
Dim runtimeAttributes As AttributeCollection =
prop.Attributes
Dim attrs(runtimeAttributes.Count) As Attribute
runtimeAttributes.CopyTo(attrs, 0)
attrs(runtimeAttributes.Count) = New
TypeConverterAttribute(GetType(DataFieldConverter))
prop = TypeDescriptor.CreateProperty(Me.GetType(),
"DataTextField", GetType(String), attrs)
properties("DataTextField") = prop
End If
End Sub 'PreFilterProperties
Function GetResolvedSelectedDataSource() As IEnumerable Implements
IDataSourceProvider.GetResolvedSelectedDataSource
Dim binding As DataBinding
binding = Me.DataBindings("DataSource")
If Not (binding Is Nothing) Then
Return DesignTimeData.GetSelectedDataSource(Me.Component,
binding.Expression, Me.DataMember)
End If
Return Nothing
End Function 'IDataSourceProvider.GetResolvedSelectedDataSource
Function GetSelectedDataSource() As Object Implements
IDataSourceProvider.GetSelectedDataSource
Dim binding As DataBinding
binding = Me.DataBindings("DataSource")
If Not (binding Is Nothing) Then
Return DesignTimeData.GetSelectedDataSource(Me.Component,
binding.Expression)
End If
Return Nothing
End Function 'IDataSourceProvider.GetSelectedDataSource
Paul Reed said:
Jeffrey,
Hi....
Let's say my custom control has a property called District. Using the
property designer at design time, they can select properties for the
control and see this property. When they click on the District, I wan
their to be a drop down of the valid Districts they can choose from.
This valid list of disticts needs to come from a database and not be
hard coded because the number of districts can change over time.
In other examples I have seen, the custom control declares an enum
structure with the allowable values. Then the property just returns a
data type of the enum. That is what I meant be enum. However, this
though limits you to only the values specified in the enum...I need mine
to be derived from a database, because the number of districts are
fluid. I hope that clarifies it for you.
Thanks,
Paul Reed
www.jacksonreed.com