I have a complex project that utilizes various inherited forms to reference different tables from a strongly-typed dataset (InventoryDataSet). The base form contains all of the common controls and components, and each inherited form fills in the details applicable to the datatable it maintains. In order to simplify the coding necessary for each form, I have created interfaces to enable the base form to manipulate data in each inherited form and its components.
One of the interfaces I use implements a component class (TableInterface) that holds references to its datatable’s BindingSource and TableAdapter and the derived (owner) form. The component uses reflection to access the tableadapter’s methods (loading, updating, etc) along with data validation control and errorprovider methods. That part was written as a workaround for the limitations presented by Microsoft because of the lack of a base TableAdapter class, and it works great!
The problem I am having revolves around the form designer and an interfaced component's property. That is, when I attempt to set the property to the system-generated bindingsource (in this case, VendorBindingSource) in the designer for an inherited form, I get the error:
Unable to cast object of type 'VendorDataTable' to type 'InventoryManager.ITableInterface'
The error stems from the conversion attempted in the last statement of sub SetTable. There, I attempt to point back to the TableInterface component from the datatable, where I have implemented ITableInterface in the user-code partial class of the InventoryDataSet’s VendorDataTable definition.
I thought that the error could be the result of some extraneous processing within the assignment, but it is a simple, single-line, get/set property definition. And the weird thing is that if I hard-code the assignment within the derived form (immediately following the sub New’s call to InitializeComponent), it all works as expected!
Does anybody have any ideas how to fix/workaround this situation? I would really prefer to use the designer for the property assignment, rather than having to hard-code into each form (although I will do that if necessary...).
Public Class TableInterface
Inherits Component
Public Property BindingSource As BindingSource
Get
BindingSource = _BindingSource
End Get
Set(value As BindingSource)
_BindingSource = value
Me.SetTable()
End Set
End Property
Private WithEvents _BindingSource As BindingSource
Public ReadOnly Property DataSet As DataSet
Get
DataSet = CType(_BindingSource.DataSource, DataSet)
End Get
End Property
Public Property Owner As ITableInterfaceForm
Get
Owner = _Owner
End Get
Set(value As ITableInterfaceForm)
_Owner = value
If _Owner IsNot Nothing Then _Owner.TableInterface = Me
End Set
End Property
Private _Owner As ITableInterfaceForm
Public Property TableAdapter As Component
Get
TableAdapter = _TableAdapter
End Get
Set(value As Component)
_TableAdapter = value
_TableAdapterType = value.GetType
End Set
End Property
Private _TableAdapter As Component
Private _TableAdapterType As Type
Public Sub SetTable() Handles _BindingSource.DataMemberChanged, _BindingSource.DataSourceChanged
Dim dataSet As DataSet = Me.DataSet
If dataSet Is Nothing OrElse _BindingSource.DataMember Is Nothing Then _Table = Nothing : Exit Sub
_Table = CType(_BindingSource.DataSource, DataSet).Tables(Me.TableName)
If _Table IsNot Nothing Then CType(_Table, ITableInterface).TableInterface = Me
End Sub
Private WithEvents _Table As DataTable
#Region " TableAdapter Methods " …
#End Region
#Region " Table/ErrorProvider Methods " …
#End Region
End Class
Public Interface ITableInterface
Property TableInterface As TableInterface
Sub ValidateColumn(e As DataColumnChangeEventArgs)
End Interface
Public Interface ITableInterfaceForm
Property TableInterface As TableInterface
End Interface
Partial Class InventoryDataSet
Partial Class VendorDataTable
Implements InventoryManager.ITableInterface
Public Property TableInterface As TableInterface Implements ITableInterface.TableInterface
Friend Sub ValidateColumn(e As DataColumnChangeEventArgs) Implements ITableInterface.ValidateColumn
…
End Sub
End Class
End Class
Side Note: At one time this arrangement was indeed working, but I was having trouble with the dynamic reformatting of the UI, so I had to redesign the base form a number of times. I also tried to organize the project directory by putting forms in one subfolder, common controls in another, etc; while doing so I moved the dataset definition to a subfolder, and it seems to me that the problem started at that point (I have since moved the dataset back to the project’s main folder, cleaned and rebuilt the solution – to no avail). I do not know if this was a factor but I thought that I should mention it.
Off-Topic Request: Can anyone tell me how to limit the designer propertygrid dropdown for the TableInterface’s TableAdapter property to just tableadapters (eg: components with names ending in “TableAdapter”, or even just components)? By default, the dropdown apparently includes all components and controls in the form!
I am using:
Microsoft Visual Basic 2010 Express - ENU Service Pack 1 - Version 10.0.40219.1 SP1Rel
Microsoft .NET Framework - Version 4.5.51209 SP1Rel
Hotfix for Microsoft Visual Basic 2010 Express - ENU (KB2635973)
with Vista Home Premium Service Pack 2 (Version 6.0.6002) x64.
Thank you in advance for any help you can give!
What I have tried:
I have searched the internet, but I have found nothing that bears on my situation. I have also tried to mutate my code but I just end up going down the rabbit hole over and over...