Attempting to load up a combobox from database using a dataset; items do not show up in the combobox. Attempting to do this without writing any codebehind.
The Model:
Imports System.Data.OleDb
Public Class ChainModel
Public Property ChainId As String
Public Property ChainType As String
Public Sub New(chainId As String, chainType As String)
Me.ChainId = chainId
Me.ChainType = chainType
End Sub
End Class
The Dataset population:
Public Class DBCollection
Public Shared dsChains As DataSet
Public Shared Sub FillDataSet()
Try
dsChains = New DataSet()
Dim adpt As OleDbDataAdapter = New OleDbDataAdapter With {
.SelectCommand = New OleDbCommand("SELECT * FROM Chain ORDER BY Name, Manufacturer;", DbConn)
}
adpt.Fill(dsChains, Tbl)
adpt.Dispose()
Catch ex As Autodesk.AutoCAD.Runtime.Exception
MsgBox("Unable to populate dataset! " & vbCrLf & ex.Message.ToString)
End Try
End Sub
End Class
The ViewModel:
Public Class TTStraightViewModel
Implements INotifyPropertyChanged
Private Sub NotifyPropertyChanged(Optional propertyName As String = "")
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propertyName))
End Sub
Public Event PropertyChanged As PropertyChangedEventHandler Implements
INotifyPropertyChanged.PropertyChanged
Dim _chainTypes As ObservableCollection(Of ChainModel) = New ObservableCollection(Of ChainModel)()
Public Sub New()
End Sub
Public Property ChainTypes As ObservableCollection(Of ChainModel)
Get
If _chainTypes.Count = 0 Then DBLoadChains()
Return _chainTypes
End Get
Set(value As ObservableCollection(Of ChainModel))
_chainTypes = value
NotifyPropertyChanged("ChainTypes")
End Set
End Property
Private Sub DBLoadChains()
For Each row As DataRow In DBCollection.dsChains.Tables("ChainTable").Rows
Dim display As String = row("Name").ToString
Dim value As String = row("id").ToString
If display = String.Empty Then display = value
_chainTypes.Add(New ChainModel(value, display))
Next
End Sub
End Class
The XAML:
<Window x:Class="TtStraightView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace: LayoutTools" ResizeMode="NoResize" Width="Auto"
xmlns:p="clr-namespace:LayoutTools.My"
Title="Table Top Conveyor Straight" SizeToContent="WidthAndHeight" Height="Auto">
<Window.DataContext>
<local:TTStraightViewModel />
</Window.DataContext>
<Window.Resources>
<p:MySettings x:Key="MySettings" />
</Window.Resources>
<StackPanel>
<ComboBox Margin="0,3,0,3" Grid.Column="2" Grid.Row="1" Width="230" SelectedValuePath="ChainId" DisplayMemberPath="ChainType" ItemsSource="{Binding ChainTypes}"/>
</StackPanel>
</Window>
DBCollection.FillDataSet() is called during program startup.
Been grappling with this for days, research, previous code and all, and still can't figure out why the combobox doesn't show any items when I run the code. Any ideas?
Finally resolved this sticky situation of mine, and, for anyone working in VB.NET who might be remotely interested in how to populate a combobox with database data the MvvM way (without any codebehind), here's how I accomplished it.
1) Create a class to emulate the properties of the database table as required:
Public Class ChainModel
Public Property ChainId As Integer
Public Property ChainType As String
Public Sub New(chainId As Integer, chainType As String)
Me.ChainId = chainId
Me.ChainType = chainType
End Sub
End Class
2) Create a database class to populate the dataset to be used (be sure to have your database connection set up before this step):
Public Class DBCollection
Public Shared dsChains As DataSet
Public Shared Sub FillDataSet()
dsChains = New DataSet()
Dim adpt As OleDbDataAdapter = New OleDbDataAdapter With {
.SelectCommand = New OleDbCommand("SELECT id,Name FROM Chain ORDER BY Name, Manufacturer;", Cat.DbConn)
}
adpt.Fill(dsChains,"Chain")
adpt.Dispose()
End Sub
End Class
3) Set up the MvvM model class such that the dataset is populated in constructor, and the observable collection property of the model is populated directly from dataset:
Public Class TTStraightModel
Dim _chainType As String = My.Settings.TTStraightChainType
Dim _chainTypeList As ObservableCollection(Of ChainModel)
Public Sub New()
DBCollection.FillDataSet()
End Sub
Public Property ChainType As String
Get
Return _chainType
End Get
Set(value As String)
_chainType = value
My.Settings.TTStraightChainType = _chainType
End Set
End Property
Public Property ChainTypeList As ObservableCollection(Of ChainModel)
Get
_chainTypeList = New ObservableCollection(Of ChainModel)()
For Each row As DataRow In DBCollection.dsChains.Tables("Chain").Rows
Dim display As String = row("Name").ToString
Dim value As String = row("id").ToString
If display = String.Empty Then display = value
_chainTypeList.Add(New ChainModel(value, display))
Next
Return _chainTypeList
End Get
Set(value As ObservableCollection(Of ChainModel))
_chainTypeList = value
End Set
End Property
End Class
4) Set up the MvvM view-model such that it reads the model's observable collection property into an observable collection property of its own:
Public Class TTStraightViewModel
Implements INotifyPropertyChanged
Private Sub NotifyPropertyChanged(Optional propertyName As String = "")
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propertyName))
End Sub
Public Event PropertyChanged As PropertyChangedEventHandler Implements
INotifyPropertyChanged.PropertyChanged
ReadOnly _ttStraightModel As New TTStraightModel()
Public Sub New()
End Sub
Public Property ChainType As String
Get
Return _ttStraightModel.ChainType
End Get
Set(value As String)
_ttStraightModel.ChainType = value
NotifyPropertyChanged("ChainType")
End Set
End Property
Public Property ChainTypeList As ObservableCollection(Of ChainModel)
Get
Return _ttStraightModel.ChainTypeList
End Get
Set(value As ObservableCollection(Of ChainModel))
_ttStraightModel.ChainTypeList = value
NotifyPropertyChanged("ChainTypeList")
End Set
End Property
End Class
5) Finally, set up the MvvM XAML view such that the combobox binds directly to the view model's exposed property (after having first set up the view model as data context for the view):
<Window x:Class="TtStraightView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:CatScriptLayoutTools" ResizeMode="NoResize" Width="Auto"
xmlns:p="clr-namespace:CatScriptLayoutTools.My"
Title="Table Top Conveyor Straight" SizeToContent="WidthAndHeight" Height="Auto">
<Window.DataContext>
<local:TTStraightViewModel />
</Window.DataContext>
<Window.Resources>
<p:MySettings x:Key="MySettings" />
</Window.Resources>
<StackPanel>
<ComboBox Margin="0,3,0,3" Width="230" SelectedValuePath="ChainId" DisplayMemberPath="ChainType" ItemsSource="{Binding ChainTypeList}" SelectedItem="{Binding ChainType}"/>
</StackPanel>
</Window>
The SelectedValuePath="ChainId" DisplayMemberPath="ChainType" ensure that the proper id/value combination is bound to the combobox.