This is my ViewModel Code:
vb:
Public Property Doctor() As Doctor
Get
Return _objDoctor
End Get
Set(ByVal Value As Doctor)
_objDoctor = Value
OnPropertyChanged("Doctor")
End Set
End Property
Public Property AddDate() As Nullable(Of DateTime)
Get
Return _objDoctor.AddDate
End Get
Set(ByVal Value As Nullable(Of DateTime))
_objDoctor.AddDate = Value
OnPropertyChanged("Doctor")
End Set
End Property
Public Property AddUserID() As String
Get
Return _objDoctor.AddUserID
End Get
Set(ByVal Value As String)
_objDoctor.AddUserID = Value
OnPropertyChanged("Doctor")
End Set
End Property
Public Property ChangeDate() As Nullable(Of DateTime)
Get
Return _objDoctor.ChangeDate
End Get
Set(ByVal Value As Nullable(Of DateTime))
_objDoctor.ChangeDate = Value
OnPropertyChanged("Doctor")
End Set
End Property
Public Property ChangeUserID() As String
Get
Return _objDoctor.ChangeUserID
End Get
Set(ByVal Value As String)
_objDoctor.ChangeUserID = Value
OnPropertyChanged("Doctor")
End Set
End Property
Public Property CollaboratingPhysicianID() As Nullable(Of Int64)
Get
Return _objDoctor.CollaboratingPhysicianID
End Get
Set(ByVal Value As Nullable(Of Int64))
_objDoctor.CollaboratingPhysicianID = Value
OnPropertyChanged("Doctor")
End Set
End Property
Public Property CredentialsID() As Int64
Get
Return _objDoctor.CredentialsID
End Get
Set(ByVal Value As Int64)
_objDoctor.CredentialsID = Value
OnPropertyChanged("Doctor")
End Set
End Property
Public Property DisplayName() As String
Get
Return _objDoctor.DisplayName
End Get
Set(ByVal Value As String)
_objDoctor.DisplayName = Value
OnPropertyChanged("Doctor")
End Set
End Property
Public Property DoctorSpecialtyID() As Int64
Get
Return _objDoctor.DoctorSpecialtyID
End Get
Set(ByVal Value As Int64)
_objDoctor.DoctorSpecialtyID = Value
OnPropertyChanged("Doctor")
End Set
End Property
Public Property FirstName() As String
Get
Return _objDoctor.FirstName
End Get
Set(ByVal Value As String)
_objDoctor.FirstName = Value
OnPropertyChanged("Doctor")
End Set
End Property
Public Property ID() As Int64
Get
Return _objDoctor.ID
End Get
Set(ByVal Value As Int64)
_objDoctor.ID = Value
OnPropertyChanged("Doctor")
End Set
End Property
Public Property LastName() As String
Get
Return _objDoctor.LastName
End Get
Set(ByVal Value As String)
_objDoctor.LastName = Value
OnPropertyChanged("LastName")
End Set
End Property
Here is on example of XAML that I could use:
<StackPanel>
<TextBox Text="{Binding LastName}" />
<TextBox Text="{Binding Doctor.LastName}" />
</StackPanel>
I would really prefer to bind to my data as the first textbox is so that I can do validation on changes. (if there is a way to do validation with the second way someone please let me know)
The problem is this:
If I load the doctor in the new constructor of the viewmodel as such:
Public Sub New()
If IsInDesignMode Then
Else
CreateEventSubscriptions()
End If
Me.Doctor = DoctorService.GetDoctor(4839)
End Sub
The Databinding works correctly the first time. But if I try to change the associated doctor with an Event, only the doctor.lastname binding works.
Private Sub onEdit(ByVal d As Doctor)
Me.Doctor = DoctorService.GetDoctor(d)
End Sub
I know I dont need to load a doctor from my service because I am actually passing the doctor...I was trying to see if there was something magical about using a service to fill the propery.
I got the code for my viewmodel properties using Karl Shifflet's XAML PowerToys. Knowing that Karl knows what he is doing I am not sure why I cant get this to work....hopefully it is something silly I am missing.
I believe if you change the doctor during an event, you should also call:
OnPropertyChanged("LastName")
Otherwise I don't think the binding code has any way of knowing the LastName property has been updated.
Related
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!
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.
I have a datagrid that uses a DataGridTemplateColumn and in the CellEditingTemplate a combobox. Everything works okay until a value is selected. I've spent a ton of time trying to figure out how to make this work. Basically a user selects a text item (Display Text) from the combobox, the value needed for the database is stored as the selected value, and the user only ever sees the display text. The way it behaves now is the user only sees the display text when opening the combobox to select an item. But after the item is selected the selected value is shown. Below is my xaml and vb code and screen shots.
Selecting an item from the combobox shows the display text, which is good.
After the user selects an item, instead of the display text being shown, the selected value is; which is what i don't want.
<Window.Resources>
<ObjectDataProvider x:Key="dispProvider" ObjectType="{x:Type local:QCDisposition}"
MethodName="GetDispositions"></ObjectDataProvider>
<ObjectDataProvider x:Key="defectDeptProvider" ObjectType="{x:Type local:QCDefectDept}"
MethodName="GetDepts"></ObjectDataProvider>
</Window.Resources>
<DataGridTemplateColumn x:Name="DispositionCol" Header="Disposition">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock x:Name="txtDisposition" Text="{Binding DispositionID, UpdateSourceTrigger=PropertyChanged}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<ComboBox x:Name="cboDisposition" DisplayMemberPath="DefectDesc" SelectionChanged="DispositionChanged" ItemsSource="{Binding Source={StaticResource dispProvider}}" SelectedItem="DispositionID" SelectedValuePath="DispositionID" SelectedValue="DispositionID" />
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
<DataGridTemplateColumn.CellStyle>
<Style>
<Setter Property="TextBlock.MinWidth" Value="100" />
<Setter Property="TextBlock.TextAlignment" Value="Left" />
</Style>
</DataGridTemplateColumn.CellStyle>
</DataGridTemplateColumn>
Class to get disposition codes:
Public Class QCDisposition
Implements INotifyPropertyChanged
Public Event PropertyChanged(sender As Object, e As PropertyChangedEventArgs) Implements INotifyPropertyChanged.PropertyChanged
'Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged
Public Sub OnPropertyChanged(ByVal e As PropertyChangedEventArgs)
If Not PropertyChangedEvent Is Nothing Then
RaiseEvent PropertyChanged(Me, e)
End If
End Sub
Private _dispositionID As Integer
Public Property QCDispID() As Integer
Get
Return _dispositionID
End Get
Set(ByVal value As Integer)
_dispositionID = value
OnPropertyChanged(New PropertyChangedEventArgs("QCDispositionID"))
End Set
End Property
Private _defectCode As String
Public Property DefectDesc() As String
Get
Return _defectCode
End Get
Set(ByVal value As String)
_defectCode = value
OnPropertyChanged(New PropertyChangedEventArgs("DefectCode"))
End Set
End Property
Public Sub New(dispositionID As Integer, defectCode As String)
Me.QCDispID = dispositionID
Me.DefectDesc = defectCode
End Sub
Public Shared Function GetDispositions() As ICollection(Of QCDisposition)
Try
Dim m_Dispositions As ObservableCollection(Of QCDisposition) = New ObservableCollection(Of QCDisposition)()
Dim db1 As New QCDispositionDataContext
Dim disp = From go In db1.QCDispositionCodes
Select go
For Each g In disp
m_Dispositions.Add(New QCDisposition(g.QCDispositionID, g.DefectCode))
Next
Return m_Dispositions
Catch ex As Exception
MessageBox.Show(ex.Message, "Unhandled Error", MessageBoxButton.OK, MessageBoxImage.Error)
Return Nothing
End Try
End Function
End Class
QC class:
Imports System.ComponentModel
Imports System.Collections.ObjectModel
Public Class QCItem
Inherits ObjectBase
Implements INotifyPropertyChanged
Public Event PropertyChanged(sender As Object, e As PropertyChangedEventArgs) Implements INotifyPropertyChanged.PropertyChanged
Public Sub OnPropertyChanged(ByVal e As PropertyChangedEventArgs)
If Not PropertyChangedEvent Is Nothing Then
RaiseEvent PropertyChanged(Me, e)
End If
End Sub
Private _salesOrder As Integer
Public Property SalesOrder() As Integer
Get
Return _salesOrder
End Get
Set(value As Integer)
_salesOrder = value
OnPropertyChanged(New PropertyChangedEventArgs("fldSalesOrder"))
End Set
End Property
Private _productRecordNo As Integer
Public Property ProductRecordNumber() As Integer
Get
Return _productRecordNo
End Get
Set(value As Integer)
_productRecordNo = value
OnPropertyChanged(New PropertyChangedEventArgs("fldProductRecordNumber"))
End Set
End Property
Private _taskNumber As Integer
Public Property TaskNumber() As Integer
Get
Return _taskNumber
End Get
Set(value As Integer)
_taskNumber = value
OnPropertyChanged(New PropertyChangedEventArgs("fldTaskNumber"))
End Set
End Property
Private _qcDesc As String
Public Property Description() As String
Get
Return _qcDesc
End Get
Set(value As String)
_qcDesc = value
OnPropertyChanged(New PropertyChangedEventArgs("fldDescription"))
End Set
End Property
Private _enteredBy As String
Public Property EnteredBy() As String
Get
Return _enteredBy
End Get
Set(value As String)
_enteredBy = value
OnPropertyChanged(New PropertyChangedEventArgs("fldEnteredBy"))
End Set
End Property
Private _enteredDate As String
Public Property EnteredDate() As String
Get
Return Convert.ToString(Convert.ToDateTime(_enteredDate).ToShortDateString)
End Get
Set(value As String)
_enteredDate = value
OnPropertyChanged(New PropertyChangedEventArgs("fldEnteredDate"))
End Set
End Property
Private _completedDate As Nullable(Of Date)
Public Property CompletedDate() As Nullable(Of Date)
Get
Return _completedDate
End Get
Set(value As Nullable(Of Date))
_completedDate = value
OnPropertyChanged(New PropertyChangedEventArgs("fldCompleteDate"))
End Set
End Property
Private _dispositionID As Integer
Public Property DispositionID() As Integer
Get
Return _dispositionID
End Get
Set(value As Integer)
_dispositionID = value
OnPropertyChanged(New PropertyChangedEventArgs("QCDispositionID"))
End Set
End Property
Private _deptCodeID As Decimal
Public Property DeptCodeID() As Decimal
Get
Return _deptCodeID
End Get
Set(value As Decimal)
_deptCodeID = value
OnPropertyChanged(New PropertyChangedEventArgs("QCDeptCodeID"))
End Set
End Property
Public Sub New(ByVal salesOrder As Integer, ByVal productRecNo As Integer, ByVal taskNumber As Integer, ByVal desc As String,
ByVal enteredBy As String, enteredDate As Nullable(Of Date), ByVal completedDate As Nullable(Of Date), ByVal dispositionID As Integer, ByVal deptCodeID As Decimal)
Try
Me.SalesOrder = salesOrder
Me.ProductRecordNumber = productRecNo
Me.TaskNumber = taskNumber
Me.Description = desc
Me.EnteredBy = enteredBy
Me.EnteredDate = enteredDate
Me.CompletedDate = completedDate
Me.DispositionID = dispositionID
Me.DeptCodeID = deptCodeID
Catch ex As Exception
MessageBox.Show(ex.Message, "New_Event", MessageBoxButton.OK, MessageBoxImage.Error)
End Try
End Sub
End Class
Public Class QCItems
Implements INotifyPropertyChanged
Private _qcItem As ICollection(Of QCItem)
Public Property QCItem As ICollection(Of QCItem)
Get
Return _qcItem
End Get
Set(value As ICollection(Of QCItem))
_qcItem = value
OnPropertyChanged(New PropertyChangedEventArgs("QCItem"))
End Set
End Property
Public Sub New()
Me.QCItem = New ObservableCollection(Of QCItem)
End Sub
Public Event PropertyChanged(sender As Object, e As PropertyChangedEventArgs) Implements INotifyPropertyChanged.PropertyChanged
Public Sub OnPropertyChanged(ByVal e As PropertyChangedEventArgs)
If Not PropertyChangedEvent Is Nothing Then
RaiseEvent PropertyChanged(Me, e)
End If
End Sub
End Class
ANSWER (thanks to bars222):
<TextBlock x:Name="txtDisposition" Text="{Binding DispositionID, Converter={StaticResource qcDispCvrt}, UpdateSourceTrigger=PropertyChanged}" />
Public Class QCDescConverter
Implements IValueConverter
Public Function Convert(value As Object, targetType As Type, parameter As Object, culture As System.Globalization.CultureInfo) As Object Implements IValueConverter.Convert
Try
If value IsNot Nothing AndAlso value.ToString().Length > 0 Then
Dim iVal As Integer = System.Convert.ToInt32(value)
Dim util As New DBUtil
Dim returnVal As String
returnVal = util.GetDefectDesc(iVal)
Return returnVal
End If
Return Nothing
Catch ex As Exception
Return Nothing
MessageBox.Show(ex.Message, "Insert Note Failed", MessageBoxButton.OK, MessageBoxImage.Error)
End Try
End Function
Public Function ConvertBack(value As Object, targetType As Type, parameter As Object, culture As System.Globalization.CultureInfo) As Object Implements IValueConverter.ConvertBack
Throw New NotImplementedException()
End Function
End Class
You observe DispositionID in the Disposition column, cause you have CellTemplate with txtDisposition that displayed this.
To display DefectDesc you can add ValueConverter to the txtDisposition binding that converts id to DefectDesc.
Or you can add DefectDesc property in QC class for displaying that description. And you should add code in the DispositionID property setter, that updates DefectDesc. And change txtDisposition binding to DefectDesc.
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
Let's admit a piece of code:
[...]
Private _filterContacts As FilterContacts
Public Property FilterContacts() As FilterContacts
Get
Return _filterContacts
End Get
Set(ByVal value As FilterContacts)
_filterContacts = value
OnPropertyChanged("FilterContacts")
End Set
End Property
Private _branchType As Nullable(Of Integer)
Public Property BranchType As Nullable(Of Integer)
Get
Return _branchType
End Get
Set(ByVal value As Nullable(Of Integer))
_branchType = value
OnPropertyChanged("BranchType")
End Set
End Property
[...]
Public Sub SomeSub()
FilterContacts.BranchType = BranchType
End Sub
I actually change the filter's "branchType", but I want to be notified that FilterContacts has changed, not just one of its fields. Is it possible? Thank you!
Set(ByVal value As Nullable(Of Integer))
_branchType = value
OnPropertyChanged("BranchType")
OnPropertyChanged("FilterContacts")
End Set
Or, if you want to invalidate all properties on the object, simply do this:
OnPropertyChanged("")