WPF INotifyPropertyChanged not allowing null value - wpf

Using WPF and EF and new to both. I may use the wrong terminology.
Using the EF wizard and code generators, I set up an EF using several tables, one of which is a lookup table.
I set up a form with a datagrid for the user to edit items in this lookup table. An issue I'm having is that the user can edit a cell, then close the form, but the editing of the cell will not update the underlying SQL database. I researched INotifyPropertyChanged and it seemed to be what I needed.
I implemented INotifyPropertyChanged to class bound to the datagrid. Before the implementation, the datagrid displayed all null values. After implementation, a message displays when the first null value is read that a nullable object must have a value.
Code:
Public Property ProcedureName As String
Get
Return _ProcedureName
End Get
Set(value As String)
_ProcedureName = value
RaisePropertyChanged("ProcedureName")
End Set
End Property
Private _ProcedureName As String
The exception occurs at "_ProcedureName = value".
Entire class:
Imports System
Imports System.Collections.ObjectModel
Partial Public Class tlkpProcedures_PartB
Inherits PropertyChangedBase
Public Property CPT As String
Get
Return _CPT
End Get
Set(value As String)
_CPT = value
RaisePropertyChanged("CPT")
End Set
End Property
Private _CPT As String
Public Property ProcedureName As String
Get
Return _ProcedureName
End Get
Set(value As String)
_ProcedureName = value
RaisePropertyChanged("ProcedureName")
End Set
End Property
Private _ProcedureName As String
Public Property BillingAmount As Nullable(Of Decimal)
Get
Return _BillingAmount
End Get
Set(value As Nullable(Of Decimal))
_BillingAmount = value
RaisePropertyChanged("BillingAmount")
End Set
End Property
Private _BillingAmount As Decimal
Public Property UniqueID As Integer
Public Overridable Property tblBilling_PartB As ObservableCollection(Of tblBilling_PartB) = New ObservableCollection(Of tblBilling_PartB)
End Class
Any help or advice is appreciated.

I'm not very good at VB but it seems like you try to assign a Nullable ( value As Nullable(Of Decimal) ) to a non-nullable (Private _BillingAmount As Decimal).
You should either cast value as Decimal or define _BillingAmount as Nullable(Of Decimal).

Related

WPF Textbox Binding. VB.Net 2017

Scenario:
A structure is associated with an indexed random access file.
Data is loaded from the file in the constructor at boot time , and the structure is automatically assigned the data values from the file, and the textboxes in the WPF window is automatically populated.
The structure is also updated if the user enter new values in a textbox. So far so good.
The problem arise when the user loads a different dataset from the file when the program is running. This happen in a Button Click event. The structure is updated, but this change is not reflected in the textboxes.
Can someone hopefully shed some light on this.
Pretty new to both WPF and VB.Net
Public Class MainWindow
Shared myStruct As aStruct
Public Structure aStruct
Implements INotifyPropertyChanged
Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged
Public year As Integer
Public Property YearP As Integer
Get
Return myStruct.year
End Get
Set(value As Integer)
myStruct.year = value
End Set
End Property
Public salary as Integer
Public Property SalaryP As Integer
Get
Return myStruct.salary
End Get
Set(value As Integer)
myStruct.salary = value
End Set
End Property
.......
.......
End Structure
Public Sub New()
Me.New(".\indxfile.ptx", ".\datafile.dat")
' This call is required by the designer.
'InitializeComponent() ' Moved
' Add any initialization after the InitializeComponent() call.
End Sub
Public Sub New(Optional _IndexFileName As String = "", Optional _DataFileName As String = "")
' This call is required by the designer.
InitializeComponent()
' Add any initialization after the InitializeComponent() call.
Me.DataContext = myStruct
Dim Retval As Integer
Retval = GetRecord(2018, DataFileName, Len(myStruct), myStruct, IndexFilename)
If Retval <> 0 Then
MsgBox("Error")
End If
End Class
<TextBox x:Name="Year" Text = "{Binding YearP, Mode = TwoWay}"
Your 'Set' properties need to invoke the PropertyChanged event so that the data binding updates.

Filter observablecollection (mvvm) [duplicate]

This question already has answers here:
Filter an observable collection
(3 answers)
Closed 4 years ago.
I've got an ObservableCollection(Of PdfMarkupAnnotationDataWrapper) which is bound to a ListBoxEdit. In addition I've got a textbox which should work as a filter.
Now when the user types something in the textbox the ObservableCollection in my Viewmodel should be filtered by the input of the textbox.
Here is my collection
Private Property _annotationList As ObservableCollection(Of PdfMarkupAnnotationDataWrapper)
Public Property AnnotationList As ObservableCollection(Of
PdfMarkupAnnotationDataWrapper)
Get
Return _annotationList
End Get
Set(value As ObservableCollection(Of PdfMarkupAnnotationDataWrapper))
_annotationList = value
OnPropertyChanged()
End Set
End Property
Is there any way to accomplish this task?
I was thinking about copying the collection but there has to be better solution.
I was thinking about copying the collection but there has to be better solution.
That would be to remove or add items from it. But you still need to store the original unfiltered items in another collection.
You could use LINQ to do the filtering, e.g.:
Private _unFilteredAnnotationList As ObservableCollection(Of PdfMarkupAnnotationDataWrapper) 'make sure to populate this one
Private _annotationList As ObservableCollection(Of PdfMarkupAnnotationDataWrapper)
Public Property AnnotationList As ObservableCollection(Of PdfMarkupAnnotationDataWrapper)
Get
Return _annotationList
End Get
Set(value As ObservableCollection(Of PdfMarkupAnnotationDataWrapper))
_annotationList = value
OnPropertyChanged()
End Set
End Property
Private _text As String
Public Property Text As String
Get
Return _text
End Get
Set(value As String)
_text = value
OnPropertyChanged()
'filter
AnnotationList = New ObservableCollection(Of PdfMarkupAnnotationDataWrapper)(_unFilteredAnnotationList.Where(Function(x)
Return x.YourStringProperty.StartsWith(_text)
End Function))
End Set
End Property

How to update the View using an init method in the ViewModel?

I'm new in WPF and MVVM (I'm using MvvmLight Toolkit) so the way I'm coding is maybe wrong.
The scenario is the following:
I would like to perform initialisation stuff every time i switch views.
So I have created a new InitViewModelBase which inherits ViewModel
Public MustInherit Class InitViewModelBase
Inherits ViewModelBase
...
Public MustOverride Sub Init()
End Class
I call this Init method when switching view
Private _currentViewModel As InitViewModel
Public Property CurrentViewModel() As InitViewModel
Get
Return _currentViewModel
End Get
Set(ByVal value As InitViewModel)
If _currentViewModel IsNot value Then
_currentViewModel = value
_currentViewModel.Init
End If
End Set
End Property
Now I would like to update for example the content of a Label in the Init method
Private _test As String
Public Property Test() As String = "TEST"
Get
Return _test
End Get
Set(ByVal value As String)
_test = value
RaisePropertyChanged("Test")
End Set
End Property
Public Overrides Sub Init()
Test = "UPDATE"
End Sub
<Label Content="{Binding Test}"/>
Why is my label content never updated when i set a new value in my Init method ?
If I set a new value in the constructor it works great.

InotifyPropertyChanged : expression recursively calls the containing property

On Set Property if certain condition match then i want to change the value of Set Property.
E.g. Item Gross Wt. = 5.55 Item Sales Rate = 2.892 Sales Value = 16.05 (Sales Value should rounded to 2 decimal) But actually (Sales Value / Gross Wt) <> 2.892. It should be 2.89189189 (Rate should be round upto 8 Decimal)
So whenever i enter rate 2.892 and it will set the Rate property and will set the Sales Value Property and again from there it will set the Rate Property.
By doing above property side there is no issue but my UI is not updating with 2.89189189 in Sales Rate TextBox.
See the code what i want to do this is not related to above example but having same issue.
Imports System.ComponentModel
Public Class TextViewModel
Implements INotifyPropertyChanged
Dim _View As MainWindow
Public Sub New(ByVal View As MainWindow)
_View = View
End Sub
Private Property _MyValue As String
Public Property MyValue As String
Get
Return _MyValue
End Get
Set(value As String)
_MyValue = value
NotifyPropertyChanged("MyValue")
If value = "ABC" Then
MyValue = "PQR"
End If
End Set
End Property
Public Event PropertyChanged(sender As Object, e As System.ComponentModel.PropertyChangedEventArgs) Implements System.ComponentModel.INotifyPropertyChanged.PropertyChanged
Protected Sub NotifyPropertyChanged(info As String)
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(info))
End Sub
End Class
As described if i write ABC and tab then PQR should display in same textbox.
Is it possible?
But there is no need to call the Set recursively
Extra calls to NotifyPropertyChanged is just extra traffic
Set(value As String)
If _MyValue = value then
return
End If
_MyValue = value
If _MyValue = "ABC" Then
_MyValue = "PQR"
End If
NotifyPropertyChanged("MyValue")
End Set
You are Notifying of the property change too early. You first notify that it has changed, then change it. You should change it, then notify. Hope that helps!
My comment was too long so I'm adding it here: I think I understand what you are saying; in your CODE EXAMPLE, you are recursively calling the setter from the setter. But in your WRITTEN COMMENT, you are setting the properties back and forth (likely an infinite loop). THESE ARE TWO DIFFERENT PROBLEMS. In your CODE EXAMPLE, if you move the NotifyPropertyChanged event to the very end of the setter, it will work as you want. It will NotifyPropertyChanged TWICE though AFTER everything has changed (once for the "child" setter call and once for the "parent" setter call). In your WRITTEN example, first, update _ItemRate, then set ItemValue. Within ItemValue, update _ItemValue, then update _ItemRate (NOT ItemRate), and NotifyPropertyChanged for both ItemValue AND ItemRate WITHIN THE SETTER OF ItemValue. This will get you out of your infinite loop.

Cascading Comboboxes WPF mvvm and EF

I'm trying to create cascading comboboxes on my view. I have a table, imported from sql with ADO.NET Entity Data Model:
Partial Public Class tbl_Activities
Public Property MRU As String
Public Property Market As String
Public Property Tower As String
Public Property FirstActivity As String
Public Property SecondActivity As String
First combobox should contain FirstActivity items and the second one SecondActivity items related to the first one.
I'm using method to populate the first one:
Public Sub FillFirstActivity()
Using context As New TimerConn
Dim result = (From act In context.tbl_Activities Where (act.MRU = MRU() And act.Market = MAR() And act.Tower = TOW()) Order By act.FirstActivity).Distinct().ToList()
For Each act In result
_First.Add(act)
Next
End Using
End Sub
Properties:
Public Property First() As ObservableCollection(Of tbl_Activities)
Get
Return _First
End Get
Set(value As ObservableCollection(Of tbl_Activities))
_First = value
End Set
End Property
Public Property Second() As ObservableCollection(Of tbl_Activities)
Get
Return _Second
End Get
Set(value As ObservableCollection(Of tbl_Activities))
_Second = value
End Set
End Property
Public Property SelectedFirst() As tbl_Activities
Get
Return _selectedFirst
End Get
Set(value As tbl_Activities)
_selectedFirst = value
Me.Second.Clear()
Me.Second.Add(_selectedFirst)
End Set
End Property
XAML:
<ComboBox ItemsSource="{Binding EmployeeViewM.First}" SelectedIndex="{Binding EmployeeViewM.SelectedFirst}" DisplayMemberPath="FirstActivity"/>
<ComboBox ItemsSource="{Binding EmployeeViewM.Second}" DisplayMemberPath="SecondActivity"/>
My problem
I'm not able to populate it correctly. In the first combobox I have doubles (Test1, Test2, Test2), and in the second combobox I get only item related to the item chosen from the first combobox:
First one should be distinct and the second one with all items for the current activity.
First Combobox = 'Test1', 'Test2'
Second Combobox = If 'Test1' then 'Test1Add', If 'Test2' then 'Test2Add', 'Test2Add1'
I don't know what I'm doing wrong here. Maybe I should split it into Two tables with PK - FK and then try? If so, how can I bind it to the comboboxes?
My Table view:
Thank you very much for any suggestion.

Resources