TheSwamp

Code Red => .NET => Topic started by: mindofcat on August 04, 2017, 07:48:12 PM

Title: Load Combobox from DataSet using VB.Net MVVM (WPF)
Post by: mindofcat on August 04, 2017, 07:48:12 PM
Hi All,

Just writing in WPF for the first time, and I ran into this situation:
I'm attempting to load a combobox with values from a dataset without writing anything in codebehind (as per the MVVM way). Many things  I have tried failed. Here's the latest:

The Model:
Code - vb.net: [Select]
  1.  
  2. Public Class ChainTableModel
  3.     Dim _chainId As String
  4.     Dim _chainType As String
  5.  
  6.     Public Property ChainId As String
  7.         Get
  8.             Return _chainId
  9.         End Get
  10.         Set(value As String)
  11.             _chainId = value
  12.         End Set
  13.     End Property
  14.  
  15.     Public Property ChainType As String
  16.         Get
  17.             Return _chainType
  18.         End Get
  19.         Set(value As String)
  20.             _chainType = value
  21.         End Set
  22.     End Property
  23.  
  24.     Public Sub New(chainId As String, chainType As String)
  25.         _chainId = chainId
  26.         _chainType = chainType
  27.     End Sub
  28. End Class
  29.  
  30.  


The ViewModel:
Code - vb.net: [Select]
  1.  
  2. Public Class ChainViewModel
  3.     Implements INotifyPropertyChanged
  4.     Dim _chainTypes As ObservableCollection(Of ChainTableModel) = New ObservableCollection(Of ChainTableModel)()
  5.  
  6.     Public Property ChainTypes As ObservableCollection(Of ChainTableModel)
  7.         Get
  8.             If _chainTypes.Count = 0 Then DBLoadChains()
  9.             Return _chainTypes
  10.         End Get
  11.         Set(value As ObservableCollection(Of ChainTableModel))
  12.             _chainTypes = value
  13.             NotifyPropertyChanged("ChainTypes")
  14.         End Set
  15.     End Property
  16.  
  17.     Private Sub DBLoadChains()
  18.         For Each row As DataRow In CatCollections.dsChains.Tables("ChainTable").Rows
  19.             Dim display As String = row("Name").ToString
  20.             Dim value As String = row("id").ToString
  21.             If display = String.Empty Then display = value
  22.             _chainTypes.Add(New ChainTableModel(value, display))
  23.         Next
  24.     End Sub
  25.  
  26.     Private Sub NotifyPropertyChanged(propertyName As String)
  27.         RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propertyName))
  28.     End Sub
  29.  
  30.     Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged
  31. End Class
  32.  

The XAML:

Code - vb.net: [Select]
  1. <Window x:Class="ChainView"
  2.         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  3.         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  4.         xmlns:local="clr-namespace:CatLayoutTools"
  5.         Title="CatScript Layout Tools (WPF) - Chain Options" SizeToContent="WidthAndHeight" Height="Auto"
  6.         ResizeMode="NoResize" Width="Auto">
  7.  
  8.     <Window.DataContext>
  9.         <local:ChainViewModel />
  10.     </Window.DataContext>
  11.  
  12.     <Window.Resources>
  13.         <Style TargetType="GroupBox">
  14.             <Setter Property="Margin"  Value="3,3,3,3" />
  15.             <Setter Property="Padding"  Value="0,5,0,0" />
  16.             <Setter Property="VerticalAlignment" Value="Top" />
  17.         </Style>
  18.     </Window.Resources>
  19.  
  20.             <StackPanel>
  21.                 <ComboBox SelectedValuePath="id" ItemsSource="{Binding ChainTypes}" />
  22.             </StackPanel>
  23. </Window>
  24.  


When I run the code, the combobox is populated with the following text "CatLayoutTools.ChainTableModel" the number of times as there are rows in the database query.

What am I missing here? I'm trying to accomplish the combobox loading and selecting of current item the MVVM way: Binding to a ViewModel.

Also, I have a question: as you can see, I am loading my observablecollection with data from the dataset in the viewmodel in the 'ChainTypes' property Get. Somehow I don't think this is the right place to do this, but then if I put a constructor in the viewmodel, the "<local:ChainViewModel />" line in the XAML bugs out, telling me that object is not set to an instance of...

And if I handle the loading of observablecollection from my AutoCAD initialization sub, how do I preserve the observablecollection for when it is needed to be bound to combobox?

Any help is appreciated.

Thanks,
Title: Re: Load Combobox from DataSet using VB.Net MVVM (WPF)
Post by: mindofcat on August 05, 2017, 03:19:49 PM
SOLVED.

Was missing SelectedValuePath and DisplayMemberPath in the XAML. This solved it for me:

<ComboBox SelectedValuePath="ChainId" Margin="0,3,0,3" DisplayMemberPath="ChainType" ItemsSource="{Binding ChainTypes}" />
Title: Re: Load Combobox from DataSet using VB.Net MVVM (WPF)
Post by: MexicanCustard on August 08, 2017, 07:20:17 AM
Quote
Also, I have a question: as you can see, I am loading my observablecollection with data from the dataset in the viewmodel in the 'ChainTypes' property Get. Somehow I don't think this is the right place to do this, but then if I put a constructor in the viewmodel, the "<local:ChainViewModel />" line in the XAML bugs out, telling me that object is not set to an instance of...

Take the construction of your ViewModel out of XAML and put it into the constructor of your UserControl/Window in the code behind. 
1. This will let you manipulate the ViewModel before XAML components are Initialized.
2. This will set you up for Dependency Injection in the future.
Title: Re: Load Combobox from DataSet using VB.Net MVVM (WPF)
Post by: mindofcat on August 14, 2017, 10:22:43 PM
You're right. Taking the constructor of the view model out of the XAML and moving it to code behind helped tremendously. I was able to handle my observable collections initialization there; a lot cleaner too! Thanks.