Reputation: 23
Just learning WPF so updating an old but useful program. I do programming as a hobby. Most of the learning I do is from the internet and I have searched for the answer to this for some days, so grateful for any help.
I'm using an Observablecollection to see how it works. My issue is that the list view that the Observablecollection is bound to doesn't show the correct data. I added a message box in to debug. After I did that, it worked perfectly, although I had to hit OK every time. After extensive reading, I was expecting the listview to update on every add (no Addrange method) but all it does is show the right number of entries but every row contains the last add.
I've changed the XAML so many times and the code behind but cannot seem to understand what I have done incorrectly or more importantly why it works with the MsgBox. The code below is the final incarnation of all the changes, not that pretty!
'convert from datatable to observable collection
For x1 = 0 To DBdtPW.Rows.Count - 1
PWResultHolder.PWNominalDia = DBdtPW.Rows(x1).Item(0)
PWResultHolder.PWInternalDia = DBdtPW.Rows(x1).Item(1).ToString
PWResultHolder.PWInternalArea = DBdtPW.Rows(x1).Item(2).ToString
PWResultHolder.PWWithin = DBdtPW.Rows(x1).Item(3).ToString
PWResultHolder.PWVelocity = DBdtPW.Rows(x1).Item(4).ToString
PWResultHolder.PWPressureDropPM = DBdtPW.Rows(x1).Item(5).ToString
PWResults.Add(PWResultHolder)
'MsgBox(PWResultHolder.PWNominalDiaValue, MsgBoxStyle.OkOnly, "Invalid Input")
Next
Again, thanks for any help.
Public Class ClsPWSizing
Implements INotifyPropertyChanged
Public PWPipeType As String 'Pipework material
Public PWPipeTypeList As New ObservableCollection(Of String) 'For populating pipe type combo box
Public PWFluidTemperatureList As New ObservableCollection(Of String) 'For populating temperature combo box
Public PWGlycolPerCentList As New ObservableCollection(Of String) 'For populating glycol combo box
Public PWResults As New ObservableCollection(Of clsPWFluidResult) 'For populating result listview
Public PWMinVelvalue As String 'Pipework minimum velocity
Public PWMaxVelvalue As String 'Pipework maximum velocity
Public PWMinPDvalue As String 'Pipework minimum pressure drop
Public PWMaxPDvalue As String 'Pipework maximum pressure drop
Public PWFluidTemperature As String ' Fluid temperature in the pipe
Public PWGlycolPerCent As String 'Percentage of glycol in fluid
Public PWDensity As String 'Density of fluid
Public PWDynVisc As String 'Dynamic viscosity of fluid
Public PWMassFlowRateValue As String 'Mass flow rate of fluid
Public GrdPWSizingVisible As System.Windows.Visibility 'Is the grid visible?
Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged
Private Sub NotifyPropertyChanged(<CallerMemberName()> Optional ByVal propertyName As String = Nothing)
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propertyName))
End Sub
Public Property PWResultListView()
Get
Return PWResults
End Get
Set(ByVal value)
PWResults = value
End Set
End Property
XAML:
<ListView x:Name="lstVwPWResults" HorizontalAlignment="Left" Height="405" Margin="612,53,0,0" VerticalAlignment="Top" Width="637" ItemsSource="{Binding PWResultListView, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}">
<ListView.View>
<GridView>
<GridViewColumn Width="100"
Header="Nom Dia"
DisplayMemberBinding="{Binding PWNominalDia}"/>
<GridViewColumn Width="100"
Header="Int Dia"
DisplayMemberBinding="{Binding PWInternalDia}"/>
<GridViewColumn Width="100"
Header="Area"
DisplayMemberBinding="{Binding PWInternalArea}"/>
<GridViewColumn Width="100"
Header="Within"
DisplayMemberBinding="{Binding PWWithin}"/>
<GridViewColumn Width="100"
Header="Velocity"
DisplayMemberBinding="{Binding PWVelocity}"/>
<GridViewColumn Width="100"
Header="Pressure Drop"
DisplayMemberBinding="{Binding PWPressureDropPM}"/>
</GridView>
</ListView.View>
</ListView>
Upvotes: 2
Views: 2361
Reputation: 3591
Your code still misses necessary parts to reproduce the problem but okay, I can guess. I removed all non-essential parts and add fake method to populate the ObservableCollection.
Item class for ObservableCollection
Public Class clsPWFluidResult
Public Property PWNominalDia As String
Public Property PWInternalDia As String
Public Property PWInternalArea As String
Public Property PWWithin As String
Public Property PWVelocity As String
Public Property PWPressureDropPM As String
End Class
ViewModel class which owns the ObservableCollection.
Imports System.Collections.ObjectModel
Imports System.ComponentModel
Imports System.Runtime.CompilerServices
Public Class clsPWSizing
Implements INotifyPropertyChanged
Public PWResults As New ObservableCollection(Of clsPWFluidResult) 'For populating result listview
Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged
Private Sub NotifyPropertyChanged(<CallerMemberName()> Optional ByVal propertyName As String = Nothing)
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propertyName))
End Sub
Public Property PWResultListView()
Get
Return PWResults
End Get
Set(ByVal value)
PWResults = value
End Set
End Property
Public Sub Pupulate()
For Each indexString In Enumerable.Range(0, 10).Select(Function(x) x.ToString())
Dim PWResultHolder As New clsPWFluidResult()
PWResultHolder.PWNominalDia = "NominalDia" & indexString
PWResultHolder.PWInternalDia = "InternalDia" & indexString
PWResultHolder.PWInternalArea = "InternalArea" & indexString
PWResultHolder.PWWithin = "Within" & indexString
PWResultHolder.PWVelocity = "Velocity" & indexString
PWResultHolder.PWPressureDropPM = "PressureDropPM" & indexString
PWResults.Add(PWResultHolder)
Next
End Sub
End Class
Code behind of View (MainWindow.xaml.vb)
Class MainWindow
Private Sub Window_Loaded(sender As Object, e As RoutedEventArgs)
Dim vm = New clsPWSizing()
Me.DataContext = vm
vm.Pupulate()
End Sub
End Class
XAML of View (MainWindow.xaml)
<Window x:Class="MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="300" Width="500"
Loaded="Window_Loaded">
<Grid>
<ListView ItemsSource="{Binding PWResultListView}">
<ListView.View>
<GridView >
<GridViewColumn Width="100"
Header="Nom Dia"
DisplayMemberBinding="{Binding PWNominalDia}"/>
<GridViewColumn Width="100"
Header="Int Dia"
DisplayMemberBinding="{Binding PWInternalDia}"/>
<GridViewColumn Width="100"
Header="Area"
DisplayMemberBinding="{Binding PWInternalArea}"/>
<GridViewColumn Width="100"
Header="Within"
DisplayMemberBinding="{Binding PWWithin}"/>
<GridViewColumn Width="100"
Header="Velocity"
DisplayMemberBinding="{Binding PWVelocity}"/>
<GridViewColumn Width="100"
Header="Pressure Drop"
DisplayMemberBinding="{Binding PWPressureDropPM}"/>
</GridView>
</ListView.View>
</ListView>
</Grid>
</Window>
This code works as expected. So there should be a problem somewhere you have not posted. Please check the difference between this code and your actual code to narrow down the cause of the problem.
Upvotes: 2
Reputation: 11
If you're using ViewModel(MVVM), implement INotifyPropertyChanged
use this
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string property)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(property));
}
In your Collection's(ItemsSource of ListView) Setter, do this
private ObservableCollection<someType> _pWResults;
public ObservableCollection<someType> PWResults
{
get{ return _pWResults }
set
{
_pWResults = value;
OnPropertyChanged("PWResults");
}
}
Sorry for providing the eg code in c#
Upvotes: 0