WFP - odd behaviour when opening new tab - wpf

The user can select from a DataGrid either by double clicking on the row, or selecting the row and clicking a button.
Using the first method the new page is initialised but the loaded event is not fired.
Using the second method the new page is initialised, the old one fires the unloaded event and the new one fires the loaded event and the new tab opens.
As both the click and doubleclick events are firing the same sub I can't figure out why one works and the other doesn't - when not in debug the new tab is formed using the first method and when clicked the loaded event is then fired, but this doesn't show in debug.
Private Sub Reports_BalanceSheets_EditRecord(sender As Object, e As RoutedEventArgs)
Try
NewRecord = False
Dim DGV As CustomControl.DGVx = Reports_BalanceSheets_Grid.FindName("Reports_BalanceSheets_DGV")
If DGV.SelectedItems.Count = 1 Then
Dim row As System.Data.DataRowView = DGV.SelectedItems(0)
FormID = row("ID")
Dim vName As String = row("Name")
Dim vTab As CustomControl.STC_Tabx = Application.Current.MainWindow.FindName("Reports_BalanceSheetTab")
Dim TabControl As CustomControl.STCx = Application.Current.MainWindow.FindName("AccountingReports_TabControl")
Dim vImageSource As String = ReturnImageAsString("Profit_Loss.png", 16)
If vTab Is Nothing Then
Dim ReportsBalanceSheetFrame As New Frame
Dim Tab As New CustomControl.STC_Tabx
With Tab
.Name = "Reports_BalanceSheetTab"
.Header = " Edit " & vName & " "
.CloseButtonVisibility = DevComponents.WpfEditors.eTabCloseButtonVisibility.Visible
.TabToolTip = "Edit " & vName
.ImageSource = vImageSource
.Content = ReportsBalanceSheetFrame
End With
AddHandler Tab.Closing, AddressOf TabControl_TabClosing
Dim vGrid As Grid = Application.Current.MainWindow.FindName("MainGrid_Website")
RegisterControl(vGrid, Tab, Tab.Name.ToString)
TabControl.Items.Add(Tab)
Dim BalanceSheet As New Reports_BalanceSheet_Page
ReportsBalanceSheetFrame.NavigationService.Navigate(BalanceSheet)
TabControl.SelectedItem = Tab
Else
vTab.Close()
Dim ReportsBalanceSheetFrame As New Frame
Dim Tab As New CustomControl.STC_Tabx
With Tab
.Name = "Reports_BalanceSheetTab"
.Header = " Edit " & vName & " "
.CloseButtonVisibility = DevComponents.WpfEditors.eTabCloseButtonVisibility.Visible
.TabToolTip = "Edit " & vName
.ImageSource = vImageSource
.Content = ReportsBalanceSheetFrame
End With
AddHandler Tab.Closing, AddressOf TabControl_TabClosing
Dim vGrid As Grid = Application.Current.MainWindow.FindName("MainGrid_Website")
RegisterControl(vGrid, Tab, Tab.Name.ToString)
TabControl.Items.Add(Tab)
Dim BalanceSheet As New Reports_BalanceSheet_Page
ReportsBalanceSheetFrame.NavigationService.Navigate(BalanceSheet)
TabControl.SelectedItem = Tab
End If
ElseIf DGV.SelectedItems.Count > 1 Then
AppBoxValidation("You can only select one item at a time to edit!")
Else
AppBoxValidation("You must select an item to edit!")
End If
Catch ex As Exception
EmailError(ex)
End Try
End Sub

Adding e.Handled resolved the issue

Related

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

Importing Microsoft.Office.Interop.Word breaks New Frame()

The problem is importing Microsoft.Office.Interop.Word (which I need elsewhere in this class) breaks "New Frame()". The error is
'New' cannot be used on an interface
My guess is that Interop.Word redefines "frame". How do I fix this?
My code:
Imports C1.WPF
Imports Microsoft.Office.Interop.Word
End Sub
Private Sub btn_SendQuote_Click(sender As Object, e As RoutedEventArgs) Handles btn_SendQuote.Click
Dim tab_SendQuote As New C1TabItem()
Dim frame_SendQuote As New Frame()
Dim scroller_SendQuote As New ScrollViewer()
Dim str_Name As String = "Send Quote"
Dim str_NavigationLink As String = "PM_SendQuote.xaml"
createNewTab(tab_SendQuote, frame_SendQuote, scroller_SendQuote, str_Name, str_NavigationLink)
End Sub
Private Sub createNewTab(tab As C1TabItem, frame As Frame, scroller As ScrollViewer, str_TabName As String, str_NavigationLink As String)
'Function to be used for adding tabs
'Add and name new tab
tab.Header = tabcontrol.Items.Count + 1 & ". " & str_TabName
tab.CanUserClose = True
tabcontrol.Items.Add(tab)
'Add frame to the tab and include new job subform page
With frame
.NavigationService.Navigate(New Uri(str_NavigationLink, UriKind.Relative))
.HorizontalAlignment = HorizontalAlignment.Stretch
.VerticalAlignment = VerticalAlignment.Top
.Margin = New Thickness(0, 0, 0, 0)
End With
With scroller
.CanContentScroll = vbTrue
.VerticalScrollBarVisibility = ScrollBarVisibility.Auto
.HorizontalScrollBarVisibility = ScrollBarVisibility.Auto
.Content = frame
End With
tab.Content = scroller
' Set new tab as active tab
tabcontrol.SelectedIndex = tabcontrol.Items.IndexOf(tab)
End Sub

WPF - destroy page after unloaded has run

In a WPF app we have the need to sometimes create a new tab that contains a Page inside a Frame..
Once the page has been opened (initialised once) it still seems to stay in navigation history and attempts to load data that may not be relevant at the time.
I have tried a myriad of methods including NavigationService.RemoveBackEntry, but it still persists :-(
This is an example of how the tab/page are opened
Private Sub CashFlow_Edit(sender As Object, e As RoutedEventArgs)
Try
Dim DGV As DGVx = ReportsCashFlow_Grid.FindName("CashFlow_DGV")
e.Handled = True
IsNewRecord = False
If DGV.SelectedItems.Count = 1 Then
Dim row As System.Data.DataRowView = DGV.SelectedItems(0)
Form_ID = row("ID")
Dim vName As String = row("Name")
Dim vTab As STC_Tabx = Application.Current.MainWindow.FindName(TabName)
Dim TabControl As STCx = Application.Current.MainWindow.FindName("AccountingReports_TabControl")
If Not vTab Is Nothing Then
vTab.Close()
End If
Dim MCFrame As New Frame
Dim MCTab As New STC_Tabx
With MCTab
.Name = TabName
.Header = " " & vName & " "
.ImageSource = ReturnImageAsString("Edit.png", 16)
.CloseButtonVisibility = DevComponents.WpfEditors.eTabCloseButtonVisibility.Visible
.TabToolTip = "View or edit the " & vName & " template"
.Content = MCFrame
End With
RemoveHandler MCTab.Closing, AddressOf TabControl_TabClosing
AddHandler MCTab.Closing, AddressOf TabControl_TabClosing
Dim vGrid As Grid = Application.Current.MainWindow.FindName("MainGrid_Accounting")
RegisterControl(vGrid, MCTab)
TabControl.Items.Add(MCTab)
Dim MCPage As New ReportCashFlow_Page
MCFrame.NavigationService.Navigate(MCPage)
LoadedTabs(TabName)
MCTab.IsSelected = True
End If
Catch ex As Exception
EmailError(ex)
End Try
End Sub
To remove all the back entries do something like:
while(NavigationService.CanGoBack)
{
NavigationService.RemoveBackEntry();
}
It's not the clean bit of code I would like, but it works - create a global Boolean - when the sub that opens the tab/page is called it's set to true and the loading event will only run the loading code if this is true - it's set to false at the end.
Private Sub ReportCashFlow_Page_Loaded(sender As Object, e As RoutedEventArgs) Handles Me.Loaded
Try
If IsNewTab = False Then
Exit Sub
End If
'Run all the loading code here
Catch ex As Exception
EmailError(ex)
Finally
IsNewTab = False
Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.Background, CType(Sub() CashFlow_LoadBudget(), SendOrPostCallback), Nothing)
Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.Background, CType(Sub() ToggleReserve(), SendOrPostCallback), Nothing)
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

WPF ListBox - refresh

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

Resources