WPF ListBox - refresh - wpf

I have a ListBox populated by a DataTable - adding items, moving items all work but delete doesn't - it reflects in the DataTable but clears all items from the ListBox unless it is reloaded as part of a SelectionChanged event.
I have tried Listbox.Items.Refresh and setting the ItemsSource to Nothing and re-assigning back to the DataTable.
Any ideas?
Thanks
Private Sub Reports_BalanceSheet_NominalListBox_Delete(NomLB As String, DT As DataTable)
Try
Dim LB As ListBox = Reports_BalanceSheet_Grid.FindName(NomLB)
If LB.SelectedIndex = -1 Then
AppBoxValidation("No item has been selected for deletion!")
Exit Sub
End If
Dim FR() As DataRow = DT.Select("ID = " & LB.SelectedValue, Nothing)
Dim CatID As Integer = 0
For Each row As DataRow In FR
CatID = row("CatID")
row.Delete()
Next
DT.AcceptChanges()
Dim vDV As New DataView(DT)
vDV.RowFilter = "FormID = " & FormID & " AND CatID = " & CatID
vDV.Sort = "Position"
DT = vDV.ToTable
vDV = Nothing
Dim i As Integer = 0
For Each row As DataRow In DT.Rows
row("Position") = i
i += 1
Next
With LB
.ItemsSource = DT.DefaultView
.DisplayMemberPath = "Name"
.SelectedValuePath = "ID"
End With
Catch ex As Exception
EmailError(ex)
End Try
End Sub

Turns out the clue was 'unless it is reloaded as part of the SelectionChanged event'
added this to the end and it all works perfectly :-)
Have you ever noticed that you can spend hours going round in circles and the moment you post the problem you figure it out?
Dim MainLB As String = NomLB.Replace("Nominal", "")
Reports_BalanceSheet_ListBox_IndexChanged(MainLB, NomLB, DT)
and that runs
Private Sub Reports_BalanceSheet_ListBox_IndexChanged(ByVal MainLB As String, ByVal NominalLB As String, ByVal NomDT As DataTable)
Try
Dim LB As ListBox = Reports_BalanceSheet_Grid.FindName(MainLB)
If LB.SelectedIndex = -1 Then
Exit Sub
End If
Dim NomLB As ListBox = Reports_BalanceSheet_Grid.FindName(NominalLB)
If NomLB Is Nothing Then
Exit Sub
End If
If LB.SelectedValue Is Nothing Then
Exit Sub
End If
If LB.SelectedValue.GetType.Name Is Nothing Then
Exit Sub
End If
If LB.SelectedValue.GetType.Name <> "DataRowView" Then
Dim CatID As Integer = LB.SelectedValue
Dim DT As DataTable = NomDT.Copy()
Dim vDV As New DataView(DT)
vDV.RowFilter = "CatID = " & CatID & " AND FormID = " & FormID
vDV.Sort = "Position"
DT = vDV.ToTable
vDV = Nothing
With NomLB
.ItemsSource = DT.DefaultView
.SelectedValuePath = "ID"
.DisplayMemberPath = "NomName"
.Items.Refresh()
End With
End If
Catch ex As Exception
EmailError(ex)
End Try
End Sub

Related

How to implement lazy loading in listview wpf VB.net

I'm newbie, I've a XAML file and code behind's, its load all data but I will lazy loading. I binding data in listview. I tried searching but did not produce the expected results, so there is no way that can be done.
code behind:
Public Sub MappingThumbnailSearchResult(thumbSearchResult As VI_ThumbnailSearchResultResponse, token As CancellationToken, ByRef dataDic As Dictionary(Of String, ObservableCollection(Of Object)))
Dim data As List(Of Object) = New List(Of Object)
Try
If thumbSearchResult.result_body Is Nothing OrElse thumbSearchResult.result_body.search_result Is Nothing Then Exit Sub
For Each item In thumbSearchResult.result_body.search_result
Try
If token.IsCancellationRequested Then Exit Sub
Dim thumbnailKey As String = ""
If Not item.thumbnail_key.Contains("\\") Then
thumbnailKey = item.thumbnail_key.ToString().Replace("\", "\\")
Else
thumbnailKey = item.thumbnail_key
End If
Dim imageResult = RequestAPI.GetInstance.GetThumbnailBase64(New VI_ThumbnailRequest With {.ThumbnailKey = thumbnailKey})
Dim hasThumb As Boolean = False
If imageResult IsNot Nothing Then
If imageResult.result_body.thumbnail IsNot Nothing Then
hasThumb = True
Dim base64Str As String = imageResult.result_body.thumbnail
item.thumbnail_base64 = imageResult.result_body.thumbnail
item.thumbnail_bitmap = BaseViewModel.BitmapFromSource(BaseViewModel.Base64ToImage(base64Str))
End If
End If
If Not hasThumb Then
'default image if have error when get thumbnail image
If item.system_type.Equals(EnumType.SystemType.face.ToString()) Then
item.thumbnail_base64 = BaseViewModel.ConvertBitmapToBase64(My.Resources.gender_unknown_2)
item.thumbnail_bitmap = My.Resources.gender_unknown_2
ElseIf item.system_type.Equals(EnumType.SystemType.people.ToString()) Then
item.thumbnail_base64 = BaseViewModel.ConvertBitmapToBase64(My.Resources.People)
item.thumbnail_bitmap = My.Resources.People
End If
End If
Dim tmpDate As DateTime
Dim shotDate As Date
If DateTime.TryParseExact(item.shot_date_time, RESPONSE_DATE_FORMAT2, Nothing, DateTimeStyles.AssumeLocal, tmpDate) Then
shotDate = tmpDate
Else
shotDate = DateTime.Now
End If
Dim dateKey As String = shotDate.ToString(PRIVATE_DATE_FORMAT)
If Not dataDic.ContainsKey(dateKey) Then
Dim thumbList = New ObservableCollection(Of Object)
Dim objThumb As Object = MappingVIThumbnailFromResponse(item, shotDate)
thumbList.Add(objThumb)
dataDic.Add(dateKey, thumbList)
Else
Dim objThumb As Object = MappingVIThumbnailFromResponse(item, shotDate)
dataDic.Item(dateKey).Add(objThumb)
End If
Catch ex As Exception
Dim b As Integer = 0
End Try
Next
Catch ex As Exception
Dim c As Integer = 0
End Try
End Sub
After, I binding data as below
Dim result As ObservableCollection(Of ListViewThumbnailViewModel) = New ObservableCollection(Of ListViewThumbnailViewModel)
If dataDic.Count > 0 Then
If token.IsCancellationRequested Then Return data
For Each pair As KeyValuePair(Of String, ObservableCollection(Of Object)) In dataDic
Dim _date As DateTime = DateTime.ParseExact(pair.Key, PRIVATE_DATE_FORMAT, CultureInfo.InvariantCulture)
result.Add(New ListViewThumbnailViewModel() With {.DateItem = _date, .ListThumbnail = pair.Value})
_viewModel.ResultSearch.TotalData += pair.Value.Count
Next
_viewModel.ResultSearch.ListResult = result
_viewModel.ResultSearch.ListResultActual = result
_viewModel.ResultSearch.PageSize = PageHelper.GetPageSizeWithZoom(_viewModel.ResultSearch.ZoomImage * 10, _viewModel.ResultSearch.PageSizeStart, _viewModel.ResultSearch.NumberChange)
_viewModel.ResultSearch.PageCurrent = 0
_viewModel.ResultSearch.TotalPage = PageHelper.GetTotalPageByPageSize(result.Count, _viewModel.ResultSearch.PageSize)
Else
_viewModel.ResultSearch.ListResult = Nothing
_viewModel.ResultSearch.ListResultActual = Nothing
End If
Catch ex As Exception
Throw New AIMatchingException(ex)
End Try
Return data
What should I do? please help me, thanks!!!

Manipulating custom combo box drop down in datagridview with special condition in display and updating Database?

I'm having a hard time in DataGridView ComboBox DropDown. Can someone enlighten me on how i bind data in a custom ComboBox with a special condition in a datagridview?
something like, If the database table was read and then in a particular column "Status" was populated with 0 or 1. And then in datagridview combobox drop down it should display unattended instead of 0 and currently attended instead of 1 and then in running the program when i click attended it should be updated in database as 1.
Any advice, recommendation or tips will be greatly appreciated.
Here is my code:
Private Sub loadDataGrid()
Try
Dim TQry As String
TQry = "Select TQ.Que_No, TS.Step_Remarks, T.Trans_Name, TS.Step_No, O.Office_Name, TQ.Date_Arrive, TQ.Time_Arrive, TQ.STATUS FROM TRANS_QUEUE TQ LEFT JOIN TRANS_STEP TS ON TQ.Trans_Step_ID = TS.Trans_STep_ID LEFT JOIN TRANSACTIONS T ON TQ.Trans_ID = T.Trans_ID LEFT JOIN OFFICE O ON TQ.Office_ID = O.Office_ID"
Dim TCmd As New SqlCommand(TQry, MysqlConn)
TCmd.CommandType = CommandType.Text
Dim TDa As New SqlDataAdapter(TCmd)
Dim TDt As New DataTable
TDa.Fill(TDt)
Dim TBs As New BindingSource
TBs.DataSource = TDt
Dim comboboxColumn As New DataGridViewComboBoxColumn
Dim Status_Data() As String = New String() {"Attended", "Unattended"}
comboboxColumn.Items.AddRange(Status_Data)
comboboxColumn.Name = "Status"
comboboxColumn.MaxDropDownItems = 2
comboboxColumn.FlatStyle = ComboBoxStyle.DropDown
comboboxColumn.Resizable = DataGridViewTriState.True
DataGridView1.DataSource = TBs
DataGridView1.Columns.Remove("Status")
DataGridView1.Columns.Insert(7, comboboxColumn)
Dim CountCols As Integer
CountCols = DataGridView1.ColumnCount - 2
For index As Integer = 0 To CountCols
DataGridView1.Columns(index).ReadOnly = True
Next
Me.DataGridView1.ColumnHeadersDefaultCellStyle.Alignment = DataGridViewContentAlignment.BottomCenter
Me.DataGridView1.DefaultCellStyle.Alignment = DataGridViewContentAlignment.BottomCenter
Catch ex As Exception
MessageBox.Show(ex.Message + " #Function GetTD()", _
"Important Note", _
MessageBoxButtons.OK, _
MessageBoxIcon.Exclamation, _
MessageBoxDefaultButton.Button1)
Me.Close()
End Try
End Sub
Screenshots:
Output
Database Table
i come up on this kind of sol. I discard the combobox dropdown idea and switch to normal button to make the function works and tweak the query.
in query
TQry = "Select TQ.Que_No as Queue, TS.Step_Remarks as Remarks, T.Trans_Name as Transactions, TS.Step_No as Steps, O.Office_Name as Office, TQ.Date_Arrive as Date, TQ.Time_Arrive as Time, case TQ.STATUS when 0 then 'unattended' else 'attended' end as Status FROM TRANS_QUEUE TQ LEFT JOIN TRANS_STEP TS ON TQ.Trans_Step_ID = TS.Trans_STep_ID LEFT JOIN TRANSACTIONS T ON TQ.Trans_ID = T.Trans_ID LEFT JOIN OFFICE O ON TQ.Office_ID = O.Office_ID"
in Start button
Private Sub Start_Btn_Click(sender As Object, e As EventArgs) Handles Start_Btn.Click
Dim RowSelected As Integer = Me.DataGridView1.CurrentRow.Cells(0).Value
MsgBox(RowSelected)
SelectedRow("SELECT * FROM TRANS_QUEUE WHERE Que_No like '%" & RowSelected & "%'") 'kwaon ang Que ID sa selected col
UpQuery("Update TRANS_QUEUE set Status = 1 WHERE Que_No = " & RowSelected & "") 'I update ang status sa selected col
End Sub
Public Sub SelectedRow(ByVal SQCommand As String)
MysqlConn.ConnectionString = "server=BOSS;user=sa;password=pass2017;database=DB_CFSys"
MysqlConn.Open()
Dim Cmpr_EMPLogIn As String = Login.UIDTextBox.Text
Dim SQCmd As New SqlCommand(SQCommand, MysqlConn)
Dim SQDr As SqlDataReader
SQDr = SQCmd.ExecuteReader()
SQDr.Read()
If SQDr.HasRows Then
MsgBox(SQDr.Item("Date_Arrive"))
MsgBox(SQDr.Item("Time_Arrive").ToString)
End If
MysqlConn.Close()
End Sub
Public Sub UpQuery(ByVal SQCommand As String)
MysqlConn.ConnectionString = "server=BOSS;user=sa;password=pass2017;database=DB_CFSys"
Dim SQLCMD As New SqlCommand(SQCommand, MysqlConn)
MysqlConn.Open()
SQLCMD.ExecuteNonQuery()
MsgBox("Successfully Updated")
MysqlConn.Close()
End Sub
In a switch(unattended/attended) button
Private Sub Status_Btn_Click(sender As Object, e As EventArgs) Handles Status_Btn.Click
If count_click = 1 Then
count_click = 2
Me.Status_Btn.Text = "Unattended"
loadDataGridAttended()
ElseIf count_click = 2 Then
count_click = 1
Me.Status_Btn.Text = "Attended"
loadDataGrid()
End If
End Sub

WPF ListBox values from another selected ListBox item then move up and down

We have a series of ListBoxes - when an item in the main ListBox is selected the relevant values are displayed in the sub ListBox. This works as intended...
We also have the ability to move items up or down, and this works as intended...
When the main ListBox has the SelectionChanged event wired up the ability to move items up and down in the sub list box stops working. Comment that out and up/down works again in the sub ListBox... I must have overlooked something glaringly obvious but after numerous changes still can't get it to work
Main ListBox SelectionChanged
Private Sub Reports_CashFlow_ListBox_IndexChanged(ByVal MainLB As String, ByVal NominalLB As String, ByVal NomDT As DataTable)
Try
Dim LB As LBx = ReportCashFlow_Grid.FindName(MainLB)
If LB.SelectedIndex = -1 Then
Exit Sub
End If
Dim NomLB As LBx = ReportCashFlow_Grid.FindName(NominalLB)
If NomLB Is Nothing Then
Exit Sub
End If
If LB.SelectedValue Is Nothing Then
Exit Sub
End If
If LB.SelectedValue.GetType.Name Is Nothing Then
Exit Sub
End If
If LB.SelectedValue.GetType.Name <> "DataRowView" Then
Dim CatID As Integer = LB.SelectedValue
Dim DV As New DataView(NomDT)
DV.RowFilter = "CatID = " & CatID & " AND FormID = " & Form_ID
DV.Sort = "Position"
With NomLB
.ItemsSource = DV
.Items.Refresh()
End With
LB.ScrollIntoView(LB.SelectedItem)
End If
Catch ex As Exception
EmailError(ex)
End Try
End Sub
Move items up
Private Sub Reports_BalanceSheet_ListBoxMoveUp(LB As ListBox, DT As DataTable, DisplayName As String, Optional MasterListBox As ListBox = Nothing)
Try
Dim StartIndex As Integer = LB.SelectedIndex
If StartIndex = -1 Then
AppBoxValidation("You have not selected an item to move up!")
Exit Sub
End If
If Not StartIndex = 0 Then
Dim CatID As Integer = 0
If DisplayName = "NomName" Then
CatID = MasterListBox.SelectedValue
End If
Dim vSelected As DataRow = DT.Rows(StartIndex)
Dim vNew As DataRow = DT.NewRow()
vNew.ItemArray = vSelected.ItemArray
DT.Rows.Remove(vSelected)
DT.Rows.InsertAt(vNew, StartIndex - 1)
DT.AcceptChanges()
LB.SelectedIndex = StartIndex - 1
Dim vPos As Integer = 0
For Each Row As DataRow In DT.Rows
If Not CatID = 0 Then
If Row("CatID") = CatID Then
Row("Position") = vPos
vPos += 1
End If
Else
Row("Position") = vPos
vPos += 1
End If
Next
LB.Items.Refresh()
End If
Catch ex As Exception
EmailError(ex)
End Try
End Sub
Turns out the issue related to subsets of data in the DataView - so needed to find the correct index for the selected item and the replacement index in the entire back-end table
Private Sub Reports_BalanceSheet_ListBoxMoveUp(LB As ListBox, DT As DataTable, DisplayName As String, Optional MasterListBox As ListBox = Nothing)
Try
Dim StartIndex As Integer = LB.SelectedIndex
If StartIndex = -1 Then
AppBoxValidation("You have not selected an item to move up!")
Exit Sub
End If
If Not StartIndex = 0 Then
Dim CatID As Integer = 0
If DisplayName = "NomName" Then
CatID = MasterListBox.SelectedValue
'As the view could be a subset of data we need to find the actual back end DB index
Dim SelectedID As Integer = LB.SelectedValue
Dim DR() As DataRow = DT.Select("ID = " & SelectedID, Nothing)
Dim vIndex As Integer = DT.Rows.IndexOf(DR(0))
Dim vCurrentPos As Integer = DR(0)("Position")
'Find the index of the one above in the grid
Dim DR2() As DataRow = DT.Select("CatID = " & CatID & " AND Position = " & vCurrentPos - 1, Nothing)
Dim vIndex2 As Integer = DT.Rows.IndexOf(DR2(0))
Dim vSelected As DataRow = DT.Rows(vIndex)
Dim vNew As DataRow = DT.NewRow()
vNew.ItemArray = vSelected.ItemArray
DT.Rows.Remove(vSelected)
DT.Rows.InsertAt(vNew, vIndex2)
DT.AcceptChanges()
Else
Dim vSelected As DataRow = DT.Rows(StartIndex)
Dim vNew As DataRow = DT.NewRow()
vNew.ItemArray = vSelected.ItemArray
DT.Rows.Remove(vSelected)
DT.Rows.InsertAt(vNew, StartIndex - 1)
DT.AcceptChanges()
End If
Dim vPos As Integer = 0
For Each Row As DataRow In DT.Rows
If Not CatID = 0 Then
If Row("CatID") = CatID Then
Row("Position") = vPos
vPos += 1
End If
Else
Row("Position") = vPos
vPos += 1
End If
Next
LB.SelectedIndex = StartIndex - 1
End If
Catch ex As Exception
EmailError(ex)
End Try
End Sub

WPF Set SelectedValue for ComboBox on page reload

I have a ComboBox that is created when the page is initialised
Dim CategoryCombo As New CustomControl.ComboCBx
With CategoryCombo
.Name = "MaintTypes_CatCombo"
End With
RegisterControl(MaintenanceTypes_Grid, CategoryCombo)
vToolBar.Items.Add(CategoryCombo)
vToolBar.Items.Add(TS_Separator)
and added to the toolbar
It is populated in the load event
Dim CatCombo As CustomControl.ComboCBx = MaintenanceTypes_Grid.FindName("MaintTypes_CatCombo")
With CatCombo
.IsNewRecord = False
.Width = 200
.ItemsSource = ReturnCategories.DefaultView
.SelectedValuePath = "ID"
.DisplayMemberPath = "Name"
.SelectedIndex = 0
End With
If the user navigates to another page and returns the selected value is returned to the selected index of 0. I can grab the last selected value before leaving the page but cannot find a way to set .SelectedValue when the page reloads
Data comes from
Private Function ReturnCategories() As DataTable
Try
CatDT = New DataTable
With CatDT.Columns
.Add("ID", GetType(Integer))
.Add("Name", GetType(String))
End With
With CatDT.Rows
.Add(0, "Select Category")
End With
Using vService As New Service1Client
strSQL = "SELECT Category_ID as 'ID', Category_Name as 'Name' FROM Maintenance_Categories "
strSQL += "WHERE Management_ID = " & Management_ID
strSQL += " ORDER BY Category_Name"
Dim DS As DataSet = vService.ReturnDataSetHAS(strSQL)
For Each Row As DataRow In DS.Tables(0).Rows
With CatDT.Rows
.Add(Row("ID"), ReturnText(Row("Name")))
End With
Next
End Using
Return CatDT
Catch ex As Exception
EmailError(ex)
Return Nothing
End Try
End Function
Any ideas?
Thanks
Found a workaround - return the index from the DataTable and set the .SelectedIndex of the ComboBox with that
In case someone has deleted the selected item prior to returning to the page check the row exists first
Dim vIndex As Integer = 0
If Not CurrentCategory = 0 Then
Dim vRow As DataRow = CatDT.Select("ID = '" & CurrentCategory & "'").FirstOrDefault()
If Not vRow Is Nothing Then
vIndex = CatDT.Rows.IndexOf(vRow)
End If
End If
With CatCombo
.IsNewRecord = False
.Width = 200
.ItemsSource = ReturnCategories.DefaultView
.SelectedValuePath = "ID"
.DisplayMemberPath = "Name"
.SelectedIndex = vIndex
End With

OleDbDataAdapter Fill creating duplicate rows

I'm experiencing an issue where I use a data adapter to update and then refill a datatable. After calling the fill method, the row gets duplicated. One ID has the correct (new) ID and the other shows -1 for the ID. The code below works perfect and is the simpler form of what I want my more complex code to do. Cosider the following:
Imports WindowsApplication1.testDataSet
Imports WindowsApplication1.testDataSetTableAdapters
Imports System.Data.OleDb
Public Class Form1
Private Sub Button1_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles Button1.Click
Dim DA As New testTableAdapter
Dim DT As New testDataTable
DA.Fill(DT)
Dim NR As testRow = DT.Rows.Add
NR.SomeText = "Test"
Dim DA2 As New OleDbDataAdapter("SELECT * FROM test", _
DA.Connection.ConnectionString)
Dim CB As New OleDbCommandBuilder(DA2)
DA2.Update(DT)
DA.Fill(DT)
For Each R As testRow In DT.Rows
Debug.Print(R.ID)
Next
End Sub
End Class
The code above works perfect. They key column doesn't show -1, there are no duplicates. Now consider the code below from my application which causes a duplicate row with the key column resulting in -1 right after the last LoadLoadNumbers().
Dim AccountLoans As IEnumerable(Of LoanNumbersRow) = _
From L As LoanNumbersRow In LoanNumbers _
Select L Where L.AccountID = ID
If Not frmFindLoans.IsDisposed AndAlso _
frmFindLoans.DialogResult = Windows.Forms.DialogResult.OK Then
For Each L As LoanNumbersRow In AccountLoans
If (From R As DataGridViewRow In frmFindLoans.dgvLoans.Rows _
Select R Where R.Cells("LoanNumber").Value = L.LoanNumber).Count = 0 Then
If L.IsWhenDeletedNull Then
L.WhenDeleted = Now
L.DeletedBy = UserName()
End If
End If
Next
Dim NewLoan As LoanNumbersRow
Dim FindLoan As IEnumerable(Of LoanNumbersRow)
For Each R As DataGridViewRow In frmFindLoans.dgvLoans.Rows
FindLoan = From L As LoanNumbersRow In LoanNumbers.Rows _
Select L Where L.LoanNumber = R.Cells("LoanNumber").Value And _
L.AccountID = ID
If FindLoan.Count = 0 Then
NewLoan = LoanNumbers.Rows.Add
NewLoan.AccountID = Acc.AccountID
NewLoan.LoanNumber = R.Cells("LoanNumber").Value
NewLoan.LoanBusinessName = R.Cells("LoanBusiness").Value
NewLoan.LoanBorrower = R.Cells("LoanBorrower").Value
NewLoan.AddedBy = UserName()
NewLoan.WhenAdded = Now
End If
Next
Try
Dim CB As New OleDbCommandBuilder(LoanNumbersAdapter)
LoanNumbersAdapter.Update(LoanNumbers)
Catch ex As Exception
MsgBox(ex.Message, MsgBoxStyle.Critical, "Error saving loan number data")
Exit Sub
End Try
If Not LoadLoanNumbers() Then Exit Sub
End If
Other variables and such from a module:
Public LoanNumbersAdapter As OleDbDataAdapter
Public LoanNumbers As New LoanNumbersDataTable
Public Sub InitializeAdapters()
LoanNumbersAdapter = New OleDbDataAdapter( _
"SELECT * FROM LoanNumbers WHERE WhenDeleted IS NULL ORDER BY WhenAdded DESC", AccountingConn)
End Sub
Public Function LoadData(ByVal DA As OleDbDataAdapter, ByVal DT As DataTable) As Boolean
Try
DA.Fill(DT)
Return True
Catch ex As Exception
MsgBox(ex.Message, MsgBoxStyle.Critical, "Error loading the " & DT.TableName & " table")
Return False
End Try
End Function
Public Function LoadLoanNumbers() As Boolean
Return LoadData(LoanNumbersAdapter, LoanNumbers)
End Function
Why does the simple test at the top work fine, but my actual application create the duplicate row with -1 on the key column? I suppose I could clear the datatable before filling after the update but wouldn't that bog it down once it starts becoming a large table?
*BTW: The DB is MS access and it's .NET 3.5
This is my duct tape solution :(
''' <summary>
''' Removes any rows where the ID/key column is less than zero
''' </summary>
<Extension()> Public Sub DeleteRelics(ByVal DT As DataTable)
If DT.PrimaryKey.Count = 0 Then Exit Sub
For Each R As DataRow In _
(From Rows As DataRow In DT.Rows _
Select Rows Where Rows(DT.PrimaryKey.First.ColumnName) < 0)
R.Delete()
Next
DT.AcceptChanges()
End Sub

Resources