Why is my data binding not working? (WPF/vb.net) - wpf

I want to bind each property of my class "Artikelstammdaten" to a textbox, but my textbox stays empty. This is what the class looks like:
Public Class Artikelstammdaten
Private _Artikel As String
Private _BezeichnungDE As String
Private _BezeichnungEN As String
Private _Einheit As String
Private _MatGrp As String
Private _Kostenart As Integer
Private _Vertriebstext_DE As String
Private _Vertriebstext_EN As String
Private _Stuecklistennummer As String
Private _Status As String
Private _Klasse As String
Private _Mantelflaeche As Double
Private _Gewicht As Double
Private _KlasseID As String
Private _Stueckliste As IList(Of Stueckliste)
Private _Arbeitsgaenge As IList(Of Arbeitsgaenge)
Public Property Artikel As String
Get
Return _Artikel
End Get
Set
_Artikel = Value
End Set
End Property
Public Property BezeichnungDE As String
Get
Return _BezeichnungDE
End Get
Set
_BezeichnungDE = Value
End Set
End Property
Public Property BezeichnungEN As String
Get
Return _BezeichnungEN
End Get
Set
_BezeichnungEN = Value
End Set
End Property
Public Property Einheit As String
Get
Return _Einheit
End Get
Set
_Einheit = Value
End Set
End Property
Public Property MatGrp As String
Get
Return _MatGrp
End Get
Set
_MatGrp = Value
End Set
End Property
Public Property Kostenart As Integer
Get
Return _Kostenart
End Get
Set
_Kostenart = Value
End Set
End Property
Public Property Vertriebstext_DE As String
Get
Return _Vertriebstext_DE
End Get
Set
_Vertriebstext_DE = Value
End Set
End Property
Public Property Vertriebstext_EN As String
Get
Return _Vertriebstext_EN
End Get
Set
_Vertriebstext_EN = Value
End Set
End Property
Public Property Stuecklistennummer As String
Get
Return _Stuecklistennummer
End Get
Set
_Stuecklistennummer = Value
End Set
End Property
Public Property Status As String
Get
Return _Status
End Get
Set
_Status = Value
End Set
End Property
Public Property Klasse As String
Get
Return _Klasse
End Get
Set
_Klasse = Value
End Set
End Property
Public Property Mantelflaeche As Double
Get
Return _Mantelflaeche
End Get
Set
_Mantelflaeche = Value
End Set
End Property
Public Property Gewicht As Double
Get
Return _Gewicht
End Get
Set
_Gewicht = Value
End Set
End Property
Public Property KlasseID As String
Get
Return _KlasseID
End Get
Set
_KlasseID = Value
End Set
End Property
Public Property Stueckliste As IList(Of Stueckliste)
Get
Return _Stueckliste
End Get
Set
_Stueckliste = Value
End Set
End Property
Public Property Arbeitsgaenge As IList(Of Arbeitsgaenge)
Get
Return _Arbeitsgaenge
End Get
Set
_Arbeitsgaenge = Value
End Set
End Property
End Class
I'm using a ViewModel where i implement the INotifyChanged Interface:
Public Class ArtikelstammdatenViewModel
Implements INotifyPropertyChanged
Private _ArtikelstammdatenList As List(Of Artikelstammdaten)
Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged
Public Property ArtikelstammdatenList As List(Of Artikelstammdaten)
Get
Return _ArtikelstammdatenList
End Get
Set
_ArtikelstammdatenList = Value
NotifyPropertyChanged("ArtikelstammdatenList")
End Set
End Property
Private Sub NotifyPropertyChanged(ByVal info As String)
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(info))
End Sub
End Class
I'm initializing an object in the MainWindow and fill it with data, which should bind to "EditArtikelstammdaten.xaml"
Dim asd As New Artikelstammdaten
With asd
.Artikel = "VAUBEF0010"
.BezeichnungDE = "Sammelbandantrieb"
.BezeichnungEN = "Collection Belt Drive N50"
.Einheit = "STK"
.MatGrp = "VAU"
.Kostenart = 1500
.Vertriebstext_DE = "Antrieb Umlenkungen"
.Vertriebstext_EN = "Drive, Deflections"
.Stuecklistennummer = "VAUBEF0010"
.Status = "F"
.Klasse = "VTPIMV"
.Mantelflaeche = 1.3
.Gewicht = 120
.KlasseID = "1.2.6.5"
End With
I used "Artikelstammdaten" as DataContext and finally bind each Property to the text Properites.
<Window.DataContext>
<local:Artikelstammdaten></local:Artikelstammdaten>
</Window.DataContext>
<TextBox x:Name="txtItem"
Text="{Binding Artikel}"
Grid.Column="2"
Grid.Row="1"
Margin="0, 5, 0, 8"
FontSize="13"
></TextBox>
What am i missing or doing wrong? Thank you for your time!

Related

VBNet: List of items inside a class, I cant change the value for a single item

My Problem:
I have a Class and a list of other class inside:
Public Class Signal_Type_Read
Private c_signal_count As Integer = 0 ' counter for read signals
Private _items As List(Of Signal_Item)
Private item As New Signal_Item
Sub add_sig()
c_signal_count += 1
items.Add(item)
End Sub
Public Property items() As List(Of Signal_Item)
Get
Return _items
End Get
Set(value As List(Of Signal_Item))
_items = value
End Set
End Property
Function item_counter() As Integer
item_counter = c_signal_count
End Function
Public Sub New()
_items = New List(Of Signal_Item)
End Sub
End Class
Public Class Signal_Item
Private _original_name As String
Public Property Original_name() As String
Get
Return _original_name
End Get
Set(value As String)
_original_name = value
End Set
End Property
'Many other properties
End Class
My problem is when I use in a loop
Public Shared ReadSignals As New Signal_Type_Read
//Part of a Loop to read cells values and store in the variable
ReadSignals.add_sig()
Dim c_index As Integer = ReadSignals.item_counter - 1
ReadSignals.items.item(c_index).Original_name = c_row.Cells(e_Signame).Value
It always changes the "Original_name" Property in all items of my Variable. Where is my error? I want only that oe item is changed.
I found the cause of the problem... I need to create a new instane of item in my ADD_sig() sub
Sub add_sig()
Dim s_item As New Signal_Item
c_signal_count += 1
items.Add(s_item)
End Sub

Databinding breaks after reloading DBcontext

I have the following ViewModel, bound to a DataGrid in my view using ItemsSource="{Binding Path=ItemsViewSource.View}":
Public Class DataTableViewModel
Inherits ViewModelBase
Private _dataContext As DbContext
Private _items As IList
Private _itemsType As Type
Private _contextType As Type
Private _itemsViewSource As CollectionViewSource
Private _itemsView As ListCollectionView
'Commands
Private _refreshTableCommand As ICommand
Public ReadOnly Property RefreshTableCommand As ICommand
Get
If _refreshTableCommand Is Nothing Then
_refreshTableCommand = New RelayCommand(AddressOf ExecuteRefreshTable, AddressOf CanExecuteRefreshTable)
End If
Return _refreshTableCommand
End Get
End Property
Private Function CanExecuteRefreshTable() As Boolean
'This command can always run.
Return True
End Function
Private Sub ExecuteRefreshTable()
Me.RefreshTable()
End Sub
Public Property Items As IList
Get
Return Me._items
End Get
Set(value As IList)
_items = value
MyBase.OnPropertyChanged("Items")
End Set
End Property
Public Property ItemsViewSource As CollectionViewSource
Get
Return Me._itemsViewSource
End Get
Set(value As CollectionViewSource)
Me._itemsViewSource = value
MyBase.OnPropertyChanged("ItemsViewSource")
End Set
End Property
Public Property ItemsView As ListCollectionView
Get
Return Me._itemsView
End Get
Set(value As ListCollectionView)
Me._itemsView = value
MyBase.OnPropertyChanged("ItemsView")
End Set
End Property
Public ReadOnly Property DataContext As DbContext
Get
Return Me._dataContext
End Get
End Property
Public ReadOnly Overrides Property IsDirty As Boolean
Get
Return Me._dataContext.ChangeTracker.HasChanges
End Get
End Property
Private Sub RefreshTable()
NewDataContext()
End Sub
Private Sub NewDataContext()
If Me._dataContext IsNot Nothing Then
Me._dataContext.Dispose()
End If
Me._dataContext = Activator.CreateInstance(_contextType)
Me._dataContext.Set(_itemsType).Load
Me.Items = _dataContext.Set(_itemsType).Local
End Sub
Public Sub New(displayName As String, contextType As Type, recordType As Type)
MyBase.DisplayName = displayName
Me._itemsType = recordType
Me._contextType = contextType
NewDataContext()
Me._itemsViewSource = New CollectionViewSource
Me.ItemsViewSource.Source = Me.Items
Me.ItemsView = CType(Me.ItemsViewSource.View, ListCollectionView)
Me.ItemsView.Filter = New Predicate(Of Object)(AddressOf FilterByString)
End Sub
End Class
The code functions perfectly until the RefreshTable() method is called at which point the databinding seems to break. Any new data from the database is loaded into the ViewModel and is available in the Items list, however the new data is not shown in the datagrid and any changes made by the user in the DataGrid are not reflected by the DBContext.ChangeTracker.
What am I missing?
Edit:
Upon further testing, the problem seems to be somehow related to the CollectionViewSource; if I bind directly to the Items property, updated records are properly shown in the DataGrid.
Apparently I've been staring at the screen too long.
The CollectionViewSource needs to be rebuilt as well and the DataGrid notified via OnPropertyChanged("ItemsViewSource").
Fix:
Private Sub RefreshTable()
NewDataContext()
Me._itemsViewSource = New CollectionViewSource
Me.ItemsViewSource.Source = Me.Items
Me.ItemsView = CType(Me.ItemsViewSource.View, ListCollectionView)
Me.ItemsView.Filter = New Predicate(Of Object)(AddressOf FilterByString)
'Let WPF know the data changed in the ViewModel
OnPropertyChanged("ItemsViewSource")
End Sub

Create table dynamically in WPF (VB.Net)

I want to create an editable table and it size is defined by user (size can be 10*10 or 20*20 or 30*30).
--
I found this topic (here) but it's running in WinForms, and the DataGridView is not supported by WPF.
I tried with a DataGrid, but the following row doesn't working :
Me.DataGridTableau.ItemsSource = dt
--
I tried with a RadGridView (Telerik) but rows are only updatable by ItemsSource property, and like I don't know how many columns will be, I can't create an object which represents the table (x properties for x columns).
Can anybody help me?
You can set the ItemsSource of a DataGrid to any IEnumerable, including a DataView of a DataTable:
Me.DataGridTableau.ItemsSource = dt.DefaultView
If anybody need it, I found a solution using a RadGridView (Telerik) :
Create this class :
Imports System.Dynamic
Imports System.Collections.Generic
Imports System.ComponentModel
Public Class MyDataRow
Inherits DynamicObject
Implements INotifyPropertyChanged
ReadOnly data As IDictionary(Of String, Object)
Public Sub New()
data = New Dictionary(Of String, Object)()
End Sub
Public Sub New(ByVal source As IDictionary(Of String, Object))
data = source
End Sub
Public Overrides Function GetDynamicMemberNames() As IEnumerable(Of String)
Return data.Keys
End Function
Public Overrides Function TryGetMember(ByVal binder As GetMemberBinder, ByRef result As Object) As Boolean
result = Me(binder.Name)
Return True
End Function
Public Overrides Function TrySetMember(ByVal binder As SetMemberBinder, ByVal value As Object) As Boolean
Me(binder.Name) = value
Return True
End Function
Default Public Property Item(ByVal columnName As String) As Object
Get
If data.ContainsKey(columnName) Then
Return data(columnName)
End If
Return Nothing
End Get
Set(ByVal value As Object)
If Not data.ContainsKey(columnName) Then
data.Add(columnName, value)
OnPropertyChanged(columnName)
Else
If data(columnName) <> value Then
data(columnName) = value
OnPropertyChanged(columnName)
End If
End If
End Set
End Property
Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged
Protected Sub OnPropertyChanged(name As String)
Try
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(name))
Catch
If Debugger.IsAttached Then Debugger.Break()
Throw ' rethrow exception
End Try
End Sub
Protected Sub OnPropertyChanged(event_args As PropertyChangedEventArgs)
RaiseEvent PropertyChanged(Me, event_args)
End Sub
End Class
In your VM, you need a public property :
Private _tableau As ObservableCollection(Of MyDataRow)
Public Property Tableau() As ObservableCollection(Of MyDataRow)
Get
Return _tableau
End Get
Set(ByVal value As ObservableCollection(Of MyDataRow))
_tableau = value
OnPropertyChanged("Tableau")
End Set
End Property
You need to create a method to load your table :
Private Function LoadTableau() As ObservableCollection(Of MyDataRow)
Dim taille As Integer = Me.GetTailleTableau()
If taille = 0 Then Return Nothing
Dim data As New ObservableCollection(Of MyDataRow)()
For i As Integer = 0 To (taille - 1)
Dim row = New MyDataRow()
For j As Integer = 0 To (taille - 1)
'row(String.Format("Column{0}", j)) = String.Format("Cell {0} {1}", i, j)
row(j) = ""
Next
data.Add(row)
Next
Return data
End Function
You need to load your table :
Me.Tableau = Me.LoadTableau()
And you need to bind your table :
<telerik:RadGridView x:Name="RadGridViewTableau" ItemsSource="{Binding Tableau}" >
I hope this help :)

WPF Radgridview with ObservableCollection and INotifyPropertyChanged

Despite the many online tutorials, I still do not quite understand how this is supposed to work. I have a radgridview where the user can enter an address per row. I want them to enter the zip code first. The city and state will be supplied from a database matching the zip code. So the radgridview must be updated as soon as the zip code is entered.
It appears that using INotifyProperty is the way to go. I can get the collection to update but cannot get the datagrid to update.
View Model:
Public Class ShipTo
Implements INotifyPropertyChanged
Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged
Private Sub NotifyPropertyChanged(ByVal info As String)
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(info))
End Sub
Public Property shipAddressType As String = String.Empty
Public Property orderID As String = String.Empty
Public Property shipName As String = String.Empty
Public Property shipAddr1 As String = String.Empty
Public Property shipAddr2 As String = String.Empty
Private _shipCity As String
Public Property shipCity As String
Get
Return _shipCity
End Get
Set(value As String)
_shipCity = value
NotifyPropertyChanged("shipZip")
End Set
End Property
Private _shipState As String
Public Property shipState As String
Get
Return _shipState
End Get
Set(value As String)
_shipState = value
NotifyPropertyChanged("shipZip")
End Set
End Property
Public Property shipZip As String = String.Empty
Code to find City and State:
Dim shipCS As New ShipTo
shipCS.shipCity = GetCityAndState.CityLookup(CStr(CType(dgShippingAddresses.SelectedItem, ShipTo).shipZip))
shipCS.shipState = GetCityAndState.StateLookup(CStr(CType(dgShippingAddresses.SelectedItem, ShipTo).shipZip))
XAML:
Any help appreciated. Thanks.
I finally got this to work well. For anyone else who is struggling here is my solution:
Private _shipSelected As Boolean
Public Property shipSelected As Boolean
Get
Return _shipSelected
End Get
Set(value As Boolean)
_shipSelected = value
NotifyPropertyChanged("shipSelected")
End Set
End Property
Public Property shipAddressType As String = String.Empty
Public Property orderID As String = String.Empty
Public Property shipName As String = String.Empty
Public Property shipAddr1 As String = String.Empty
Public Property shipAddr2 As String = String.Empty
Private _shipCity As String
Public Property shipCity As String
Get
Return _shipCity
End Get
Set(value As String)
_shipCity = value
NotifyPropertyChanged("shipCity")
End Set
End Property
Private _shipState As String
Public Property shipState As String
Get
Return _shipState
End Get
Set(value As String)
_shipState = value
NotifyPropertyChanged("shipState")
End Set
End Property
Private _shipZip As String
Public Property shipZip As String
Get
Return _shipZip
End Get
Set(value As String)
_shipZip = value
shipCity = GetCityAndState.CityLookup(_shipZip)
shipState = GetCityAndState.StateLookup(_shipZip)
NotifyPropertyChanged("shipZip")
End Set
End Property
Now when the zip is entered in the datagrid, the city and state automatically update.

Combobox and IDataErrorInfo

This is my problem.
When I select an item from the combobox, (combobox is populated) I have always red outline.
Why ?
<ComboBox x:Name="Cmb_USER"
TabIndex="5"
ItemsSource="{Binding User_USER,
ValidatesOnExceptions=True,
ValidatesOnDataErrors=True,NotifyOnValidationError=True}"
IsEditable="True"
DisplayMemberPath ="DescUser"
Text="{Binding Path=USER}" Margin="114,105,98,179"/>
Public Property User_USER As ObservableCollection(Of Model_User)
Private p_USER As String
Public Property USER() As String
Get
Return p_USER
End Get
Set(ByVal value As String)
p_USER = value
OnPropertyChanged("USER")
End Set
End Property
#Region "IDataErrorInfo Members"
Public ReadOnly Property [Error]() As String Implements System.ComponentModel.IDataErrorInfo.Error
Get
Return Nothing
End Get
End Property
Default Public ReadOnly Property Item(ByVal Name As String) As String Implements System.ComponentModel.IDataErrorInfo.Item
Get
Dim result As String = Nothing
Select Case Name
Case "User_USER"
If USER = "" Then
result = "ERROR"
End If
End Select
Return result
End Get
End Property
#End Region
Solved ..
This is the solution
Public Property USER() As String
Get
Return p_USER
End Get
Set(ByVal value As String)
p_USER = value
OnPropertyChanged("USER")
OnPropertyChanged("User_USER")
End Set
End Property

Resources