Even though the datagrid performs like it should, I'm wondering if my code is not optimal. When I put breakpoints in the code to follow what it does, I see some repetition that I'm not sure should happen. It appears to be a very expensive repetition as far as system resources.
Sample data:
Image may be NSFW.
Clik here to view.
Xaml:
<Window x:Class="DentalDB.PartBBilling_Window" x:Name="Window" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Part B Billing" Height="300" Width="805" ResizeMode="NoResize" WindowStartupLocation="CenterScreen" Background="#FF336B7B"><Grid Width="743" Height="259"><Grid.RowDefinitions><RowDefinition Height="139*" /><RowDefinition Height="122*" /></Grid.RowDefinitions><DataGrid ItemsSource="{Binding PartB}" AutoGenerateColumns="False" Height="237" HorizontalAlignment="Left" Margin="12,12,0,0" Name="dgPartBBilling" VerticalAlignment="Top" Width="731" AlternationCount="2" AlternatingRowBackground="LightBlue" Grid.RowSpan="2"><DataGrid.Columns><DataGridTemplateColumn x:Name="dPartBBilling_Date" Width="100" Header="Billing Date"><DataGridTemplateColumn.CellTemplate><DataTemplate><TextBlock Text="{Binding Path=PartBBilling_Date, StringFormat=\{0:d\}}" Width="75"/></DataTemplate></DataGridTemplateColumn.CellTemplate><DataGridTemplateColumn.CellEditingTemplate><DataTemplate><Grid FocusManager.FocusedElement="{Binding ElementName= dPartBBilling_Date}" ><DatePicker x:Name="dPartBBilling_Date" SelectedDate="{Binding Path=PartBBilling_Date}" /> </Grid></DataTemplate></DataGridTemplateColumn.CellEditingTemplate></DataGridTemplateColumn><DataGridTemplateColumn Header="CPT Code" Width="75"><DataGridTemplateColumn.CellTemplate><DataTemplate><ComboBox ItemsSource="{Binding PartBCombo, RelativeSource={RelativeSource AncestorType=Window}}" DisplayMemberPath="PartBLookup_CPTCode" SelectedValuePath="PartBLookup_ProcedureDescription" SelectedValue="{Binding PartBBilling_ProcedureName, UpdateSourceTrigger=PropertyChanged}" SelectedItem="{Binding PartBBilling_CPT}"/></DataTemplate></DataGridTemplateColumn.CellTemplate></DataGridTemplateColumn><DataGridTextColumn Header="Procedure Name" Width="250" Binding="{Binding PartBBilling_ProcedureName}" IsReadOnly="True"/><DataGridTextColumn Header="Tooth #" Width="120" Binding="{Binding PartBBilling_Tooth}" /><DataGridTextColumn Header="Quantity" Width="75" Binding="{Binding PartBBilling_Quantity}" /><DataGridTextColumn Header="Total" Width="75" Binding="{Binding PartBBilling_Total, StringFormat=N2}" IsReadOnly="True"/></DataGrid.Columns></DataGrid></Grid></Window>
Code behind:
Imports System.Collections.ObjectModel Imports System.ComponentModel Namespace DentalDB Partial Public Class PartBBilling_Window Inherits Window Implements INotifyPropertyChanged Private Sub RaisePropertyChanged(prop As String) RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(prop)) End Sub Public Sub New() ' This call is required by the designer. InitializeComponent() ' Add any initialization after the InitializeComponent() call. 'fill combobox with items If conn.State = ConnectionState.Closed Then conn.Open() End If cmd = New SqlCommand() cmd.Connection = conn cmd.CommandText = "SELECT CPT, ProcedureName FROM tlkpProcedures_PartB ORDER BY CPT" Dim Reader As SqlDataReader = cmd.ExecuteReader() PartBCombo = New List(Of PartBBilling_Combobox) If Reader.HasRows Then While Reader.Read() PartBCombo.Add( _ New PartBBilling_Combobox() With { _ .PartBLookup_CPTCode = Reader("CPT").ToString, .PartBLookup_ProcedureDescription = Reader("ProcedureName").ToString }) End While End If Reader.Close() conn.Close() 'fill datagrid PartB = New List(Of PartBBilling) If conn.State = ConnectionState.Closed Then conn.Open() End If cmd = New SqlCommand() cmd.Connection = conn sSQL = "SELECT " & _"tblBilling_PartB.RW, " & _"tblBilling_PartB.BillingDate, " & _"tblBilling_PartB.CPT, " & _"ISNULL(tlkpProcedures_PartB.ProcedureName, '') AS ProcedureName, " & _"tblBilling_PartB.Tooth, " & _"tblBilling_PartB.Quantity, " & _"ISNULL(tlkpProcedures_PartB.BillingAmount * tblBilling_PartB.Quantity, '') AS Total, " & _"tblBilling_PartB.UniqueID " & _"FROM tblBilling_PartB " & _"LEFT JOIN tlkpProcedures_PartB ON tblBilling_PartB.CPT = tlkpProcedures_PartB.CPT " & _"WHERE RW = " & CInt(RW) & " " & _"ORDER BY tblBilling_PartB.BillingDate DESC" cmd.CommandText = sSQL Reader = cmd.ExecuteReader() If Reader.HasRows Then 'bolCheckDate = False While Reader.Read() PartB.Add( _ New PartBBilling() With { _ .PartBBilling_RW = Reader("RW").ToString, .PartBBilling_Date = Reader("BillingDate"), .PartBBilling_CPT = Reader("CPT").ToString, .PartBBilling_ProcedureName = Reader("ProcedureName").ToString, .PartBBilling_Tooth = Reader("Tooth").ToString, .PartBBilling_Quantity = Reader("Quantity") }) End While End If conn.Close() DataContext = Me End Sub Public Property PartBCombo As List(Of PartBBilling_Combobox) Get Return _PartBCombo End Get Set(value As List(Of PartBBilling_Combobox)) _PartBCombo = value End Set End Property Private _PartBCombo As List(Of PartBBilling_Combobox) Public Property PartB As List(Of PartBBilling) Get Return _PartB End Get Set(value As List(Of PartBBilling)) _PartB = value End Set End Property Private _PartB As List(Of PartBBilling) Public Event PropertyChanged(sender As Object, e As System.ComponentModel.PropertyChangedEventArgs) Implements System.ComponentModel.INotifyPropertyChanged.PropertyChanged End Class End Namespace
Class for combobox items:
Imports System Namespace DentalDB Public Class PartBBilling_Combobox Private _PartBLookup_CPTCode As String Public Property PartBLookup_CPTCode As String Get Return _PartBLookup_CPTCode End Get Set(value As String) _PartBLookup_CPTCode = value End Set End Property Private _PartBLookup_ProcedureDescription As String Public Property PartBLookup_ProcedureDescription As String Get Return _PartBLookup_ProcedureDescription End Get Set(value As String) _PartBLookup_ProcedureDescription = value End Set End Property End Class End Namespace
The combobox class code above is executed 45 times, one for each item. This is what I would expect.
Then it's executed multiple times again while, I presume, the datagrid is loading with data. But I can't pinpoint down where this happens. Using the sample data, for the first row "Bitewing-Single Film", this class will execute 55 times, 45 times to go thru the combo items, then another 10 times to get to "Bitewing-Single Film" which is the 10th item in the list (a breakpoint in the Get for the ProcedureName confirms this).
For the next row "Limited Oral Exam/Problem focused", the code will execute 56 times, 45 for each item in the combo, the 11 more times because "Limited Oral..." is the 11th item.
"Panoramic Film" is the 15th item. Code is executed 45 + 15 times.
I think the combo is trying to match the CPT with the Procedure Name but this constant looping seems to be overkill.
Is this just its nature or is there something that can be done to make this more streamlined?
Thanks.