Webbrowser control throws NullReferenceException when navigating - vb.net

I'm trying to build my first HTML UI with Webbrowser component in VB.Net. I have found this code example on Microsoft site
https://msdn.microsoft.com/en-us/library/system.windows.forms.webbrowser.document(v=vs.110).aspx :
Private Sub Form1_Load(ByVal sender As Object, ByVal e As EventArgs) _
Handles Me.Load
WebBrowser1.DocumentText =
"<html><body>Please enter your name:<br/>" &
"<input type='text' name='userName'/><br/>" &
"<a href='http://www.microsoft.com'>continue</a>" &
"</body></html>"
End Sub
Private Sub webBrowser1_Navigating(
ByVal sender As Object, ByVal e As WebBrowserNavigatingEventArgs) _
Handles WebBrowser1.Navigating
Dim document As System.Windows.Forms.HtmlDocument =
WebBrowser1.Document
If document IsNot Nothing And
document.All("userName") IsNot Nothing And
String.IsNullOrEmpty(
document.All("userName").GetAttribute("value")) Then
e.Cancel = True
MsgBox("You must enter your name before you can navigate to " &
e.Url.ToString())
End If
End Sub
When I put it on to the test, most of the time throws exception 'System.NullReferenceException' in this part of the code:
If document IsNot Nothing And
document.All("userName") IsNot Nothing And
String.IsNullOrEmpty(
document.All("userName").GetAttribute("value")) Then
Sometimes it works, but mostly it doesn't work at all. Any idea how to fix this? I'm very new to .Net platform and sorry if there is any miss spelling. Any help is appreciated.

If document is nothing then the other clauses of the If statement will generate exceptions because you are attempting to access properties whilst document is Nothing. You need to rewrite the code like this:
Dim document As System.Windows.Forms.HtmlDocument = WebBrowser1.Document
If document IsNot Nothing Then
If document.All("userName") IsNot Nothing Then
If String.IsNullOrEmpty(document.All("userName").GetAttribute("value")) Then
e.Cancel = True
MsgBox("You must enter your name before you can navigate to " &
e.Url.ToString())
End If
End If
End If

Related

Right click on ListBox open ToolStripMenu but doesn't select any item

I have a ListBox containing full path and a ToolStripMenu to choose Open File or Show File in Folder.
The issue is: I need to Left Click on a ListBoxItem before Right Click to select the file I need to show in folder.
If I don't do this I get NullReferenceException because no item is selected.
How can I get selected the item Right Clicked?
Here's my code:
Private Sub ShowInFolderToolStripMenuItem_Click(sender As Object, e As EventArgs) Handles ShowInFolderToolStripMenuItem.Click
Try
If DirectCast(DirectCast(sender, ToolStripMenuItem).GetCurrentParent, _
ContextMenuStrip).SourceControl.GetType Is GetType(ListBox) Then
Shell("explorer /select, " & DirectCast(DirectCast(DirectCast(sender, _
ToolStripMenuItem).GetCurrentParent, ContextMenuStrip).SourceControl, _
ListBox).SelectedItem.ToString, AppWinStyle.NormalFocus)
End If
Catch ex As Exception
MsgBox(ex.ToString)
End Try
End Sub
Just another question... Why the below code doesn't work but doesn't give error and show me document folder?
Process.Start("explorer.exe", "/select" & DirectCast(DirectCast(DirectCast(sender, _
ToolStripMenuItem).GetCurrentParent, ContextMenuStrip).SourceControl, _
ListBox).SelectedItem.ToString)
Solved adding MouseDown event:
Private Sub ListBox1_MouseDown(sender As Object, e As MouseEventArgs) Handles ListBox1.MouseDown
Try
DirectCast(sender, ListBox).SelectedIndex = DirectCast(sender, ListBox).IndexFromPoint(e.X, e.Y)
Catch ex As Exception
End Try
End Sub

vb.net get contextmenustrip applicable to multiple pictureboxes

In my form I have several pictureboxes and one contextmenustrip, the contextmenustrip is supposed to use at all these pictureboxes.
A tool in the contextmenustrip is to open and view the a pdf file.
The current code is:
Private Sub ViewToolStripMenuItem_Click(sender As Object, e As EventArgs) Handles ViewToolStripMenuItem.Click
Process.Start("C:\Program Files (x86)\Adobe\Reader 11.0\Reader\AcroRd32.exe", "C:\vb_test\" + picDrawing(1))
End Sub
I have no idea how the tool can determine which picturebox is focused and open different files.
I am using vb.net.
It seems that ContextMenu.SourceControl returns always Nothing in particular situations. I verified this problem on VS2010 when I put my ToolStripMenuItem inside a ToolStripDropDownMenu. So the answer posted by #Justin Ryan couldn't working.
A workaround could be manually set a variable when opening ContextMenu with its SourceControl.
Public Class Form1
Dim ctrlSourceControl As Control
Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
AddHandler Me.ContextMenuStrip1.Opening, AddressOf setSourceControl
End Sub
Private Sub setSourceControl(sender As Object, e As System.ComponentModel.CancelEventArgs)
Me.ctrlSourceControl = CType(sender, ContextMenuStrip).SourceControl
End Sub
Private Sub Item1ToolStripMenuItem_Click(sender As System.Object, e As System.EventArgs) Handles Item1ToolStripMenuItem.Click
MsgBox(Me.ctrlSourceControl.Name)
End Sub
End Class
From this question, Tim Lentine shows how to use the SourceControl property Of a ContextMenuStrip to determine the control which opened the context menu:
Private Sub mnuWebCopy_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles mnuWebCopy.Click
Dim myItem As ToolStripMenuItem = CType(sender, ToolStripMenuItem)
Dim cms As ContextMenuStrip = CType(myItem.Owner, ContextMenuStrip)
MessageBox.Show(cms.SourceControl.Name)
End Sub
This answer is likely the same as tezzo's. Just used to this
scenario a lot, and wanted to share some security checks among many
others that may help.
Assuming
ONLY PictureBoxes can show your ContextMenu named MyContextMenu :
and you have a ToolStripMenuItem named ViewToolStripMenuItem
Declarations :
Option Strict On
Option Explicit On
Option Infer Off
Imports System.IO
' File.Exist()
Imports System.Diagnostics
' Process.Start()
Public Class Form1
Private p_SelectedPictureB As PictureBox
Private p_AcroRedPath As String = "C:\Program Files (x86)\Adobe\Reader 11.0\Reader\AcroRd32.exe"
Private p_ImageFolderPath As String = "C:\vb_test\"
Private p_TargetFileName As String = ""
' ...
End Class
Handle the Opening Event of your MyContextMenu [ContextMenu]
either by a Handles MyContextMenu.Opening hook
or AddHandler MyContextMenu.Opening, AddressOf MyContextMenu_Opening
Private Sub MyContextMenu_Opening( _
sender As Object, e As System.ComponentModel.CancelEventArgs) _
Handles MyContextMenu.Opening ' Requires Private WithEvents MyContextMenu
'Try
p_SelectedPictureB = DirectCast(MyContextMenu.SourceControl, PictureBox)
If p_SelectedPictureB.Image IsNot Nothing Then
ViewToolStripMenuItem.Enabled = True
Select Case True
Case p_SelectedPictureB Is PictureBox1:
p_TargetFileName = picDrawing(1)
ViewToolStripMenuItem.Text = "Open [" + p_TargetFileName + "]"
Case p_SelectedPictureB Is PictureBox2:
p_TargetFileName = picDrawing(2)
ViewToolStripMenuItem.Text = "Open [" + p_TargetFileName + "]"
' ...
Case Else
ViewToolStripMenuItem.Enabled = False
ViewToolStripMenuItem.Text = "Open [<Wrong PBox>]"
p_TargetFileName = ""
'e.Cancel = True
End Select
Else
ViewToolStripMenuItem.Enabled = False
ViewToolStripMenuItem.Text = "Open [<No Image>]"
p_TargetFileName = ""
'e.Cancel = True
End If
'Catch CurrentException As Exception
' MessageBox.Show(CurrentException.Message)
' ViewToolStripMenuItem.Enabled = False
' p_TargetFileName = ""
' e.Cancel = True
'End Try
' ^^ remove commenting if you're unsure.
End Sub
Prefer the use of top declared variables.
If you write plain file/folder paths inside a method or function, you could loose track of it quickly, and some time later, you don't understand why your application suddenly started to crash (because the file went deleted/application uninstalled, or the folder renamed)
=> Put path to File/Folder in a global variable
However, the best move is to retrieve that path at Runtime, and ensure the existence of the File/Folder before going further...
Private Sub ViewToolStripMenuItem_Click( _
sender As Object, e As EventArgs) _
Handles ViewToolStripMenuItem.Click
Dim TargetFile As String = p_ImageFolderPath + p_TargetFileName
If File.Exists(TargetFile) Then
' (p_AcroRedPath existence checked when application starts)
Process.Start(p_AcroRedPath, TargetFile)
Else
MessageBox.Show("The File [" + TargetFile + "] doesn't exist.")
End If
End Sub

VB.Net How to set an object reference to an instance of an object?

Using VB.NET, trying to write a page title to a text file. I am stumped here:
Private Sub
Dim pagetitle As String
pagetitle = WebBrowser1.Document.Title
My.Computer.FileSystem.WriteAllText("page title.txt", pagetitle, False)
But I get an error saying "Object reference not set to an instance of an object." Please help!
Most likely you are trying to access the Document property when it is still equal to Nothing. Move your code to the DocumentCompleted event of the WebBrowser control, as such:
Private Sub WebBrowser1_DocumentCompleted(sender As System.Object, e As System.Windows.Forms.WebBrowserDocumentCompletedEventArgs) Handles WebBrowser1.DocumentCompleted
If WebBrowser1.Document IsNot Nothing Then
Dim pagetitle As String
pagetitle = WebBrowser1.Document.Title
My.Computer.FileSystem.WriteAllText("page title.txt", pagetitle, False)
End If
End Sub
My Guess is 'WebBrowser1.Documen't is null. I'm not sure what conditions have to exist to make the Document not null, but you should definitely check that first before trying to grab its title.
I stole this from:http://msdn.microsoft.com/en-us/library/system.windows.forms.webbrowser.document.aspx
Private Sub webBrowser1_Navigating( _
ByVal sender As Object, ByVal e As WebBrowserNavigatingEventArgs) _
Handles webBrowser1.Navigating
Dim document As System.Windows.Forms.HtmlDocument = _
webBrowser1.Document
If document IsNot Nothing And _
document.All("userName") IsNot Nothing And _
String.IsNullOrEmpty( _
document.All("userName").GetAttribute("value")) Then
e.Cancel = True
MsgBox("You must enter your name before you can navigate to " & _
e.Url.ToString())
End If
End Sub

Adding text to textbox from a button that supports multiple lines without erasing

So basically what I want to do is click a button and this will put my text into a textbox and add ?xml=1 after it. If someone wants to help me with the entire thing the image is below of what I want it to do
Here is what I mean http://i.stack.imgur.com/2eatj.png
Heres what it looks like http://i.stack.imgur.com/aCoJ0.png but everytime I click ?xml=1 it adds to the bottom this doesnt matter on which line I click it'll just add it to the end
What I am using for the ?xml=1 part is TextBox1.Text &= "?xml=1"
{Public Class Form1
Private Sub TextBox1_TextChanged(sender As Object, e As EventArgs) Handles TextBox1.TextChanged
End Sub
Private Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click
TextBox1.Text &= "?xml=1"
End Sub
End Class}
Your form is incomplete, various pieces of information is needed to generate the Steam64Id number.
Namely, you will need the "Universe", "AccountType", "AccountInstance" and off course "Account Number".
When you put the component values values together into the whole, you end up with the Steam64Id number.
You can see how it breaks down in the image below.
Further information can be found on the steam developers pages
https://developer.valvesoftware.com/wiki/SteamID
Update
If the textbox you enter the account number in is called txtSource and your entered 0123456789 as the number and the textbox you want to write it into after adding "?xml=1" is called txtDestination then the code to transfer it over is
txtDestination.text = txtSource.text & "?xml=1"
and if you want to transfer it over whilst adding the URL then it would be
txtDestination.text = "http://steamcommunity.com/ID/" & txtSource.text & "?xml=1"
or
txtDestination.text = "http://steamcommunity.com/PROFILES/" & txtSource.text & "?xml=1"
There are still some unresolved issues in so much as you have not clarified whether it is an ID or a profile so when you rewrite it as a URL would it be http://steamcommunity.com/ID/0123456789?xml=1 or would it be http://steamcommunity.com/PROFILES/0123456789?xml=1 my guess is that only one is right and the other is wrong.
Once you have got the correct folder wether its ID or Profiles a successful call will return an XML document and you must extract the data from that.
Update II
Well I had some free time today so I managed to knock out this code, it goes with the image further down, I didn't have time to do the web page scraping bit, but i'm sure there will lots of examples on SO of where other users have asked similar questions. Hope this is enough to set you on your way.
Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
Dim Reference As Long
If Trim(TextBox1.Text) <> "" Then
If IsNumeric(TextBox1.Text) Then
Reference = Shell("c:\program files\internet explorer\iexplore.exe http://steamcommunity.com/profiles/" & Trim(TextBox1.Text) & "?xml=1")
Else
Reference = Shell("c:\program files\internet explorer\iexplore.exe http://steamcommunity.com/id/" & Trim(TextBox1.Text) & "?xml=1")
End If
Else
MsgBox("No steam Id entered!", MsgBoxStyle.Critical, "Error")
End If
End Sub
Private Sub Button2_Click(sender As System.Object, e As System.EventArgs) Handles Button2.Click
If Trim(TextBox2.Text) <> "" Then
TextBox3.Text = "http://steamcommunity/friends/add/" & TextBox2.Text
Else
MsgBox("No steam 64 Id specified!", MsgBoxStyle.Critical, "Error")
End If
End Sub
Private Sub Button3_Click(sender As System.Object, e As System.EventArgs) Handles Button3.Click
Dim Reference As Long
If Trim(TextBox3.Text) <> "" Then
Reference = Shell("c:\program files\internet explorer\iexplore.exe " & Trim(TextBox3.Text))
Else
MsgBox("No steam 64 Id specified!", MsgBoxStyle.Critical, "Error")
End If
End Sub

.NET fulltext autocomplete in a combobox. Any performance-positive way of overriding listitems?

I'm struggling to meet a demand from my supervisors. I really hope that someone could give some advice.
Basically there are places in our project where there is a big selection of options. The most concrete example is choosing a city in the world. The items are hundreds of thousands.
Using standard winforms controls and properties, one can search through a list fast.
The problem is that we're using a concatenation of city&district name for all the items. Essentially PREFIX autotomplete works but does not work as needed. The task is to filter and show items by any given string in any part of the item. Essentially a FULL TEXT search in the combobox.
Does anyone have an idea about switching autocomplete sources in runtime relatively qiuckly and handling the suggest/suggestappend event?
Also the project is in VB.NET, though any form of .NET advice will be extremely helpful.
Thanks!
UPDATE: The latest attempt using competent_tech's suggestion with some minor modifications.
Imports System.Data
Public Class Form1
Private _ErrorText As String
Private _CommandExecuted As Boolean
Private m_fOkToUpdateAutoComplete As Boolean
Private m_sLastSearchedFor As String = ""
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Call Me.SetStatusText("Loading...")
Me._ErrorText = ""
Me.Cities.Clear()
Me.BackgroundWorker1.RunWorkerAsync()
End Sub
Private Sub BackgroundWorker1_DoWork(ByVal sender As Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
Try
Me._CommandExecuted = True
Me.Ara_airportsTableAdapter.Fill(Me.Cities.ara_airports)
Catch ex As Exception
_ErrorText = ex.Message
End Try
End Sub
Private Sub BackgroundWorker1_RunWorkerCompleted(ByVal sender As Object, ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles BackgroundWorker1.RunWorkerCompleted
If Me._ErrorText = "" Then
Me.SetStatusText(Me.Cities.ara_airports.Count & " Records loaded")
Else
Me.SetStatusText(Me._ErrorText)
End If
Me.BindingSource.ResetBindings(False)
End Sub
Private Sub SetStatusText(ByVal sText As String)
Me.Text = sText
End Sub
Private Sub cboPort_KeyDown(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyEventArgs) Handles cboPort.KeyDown
Try
If e.KeyCode = Keys.Up OrElse e.KeyCode = Keys.Down Then
m_fOkToUpdateAutoComplete = False
Else
m_fOkToUpdateAutoComplete = True
End If
Catch theException As Exception
' ...
End Try
End Sub
Private Sub cboPort_TextChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles cboPort.KeyUp
Try
If m_fOkToUpdateAutoComplete Then
With cboPort
If .Text.Length >= 2 Then
Dim cSuggestions As IList
Dim sError As String = ""
m_sLastSearchedFor = .Text
cSuggestions = GetSuggestions(m_sLastSearchedFor)
.DataSource = Nothing
If cSuggestions IsNot Nothing Then
.BindingContext = New BindingContext
.DisplayMember = "CName"
.ValueMember = "id"
.DataSource = New BindingSource(cSuggestions, Nothing)
System.Threading.Thread.Sleep(10)
System.Windows.Forms.Application.DoEvents()
.DroppedDown = True
.Text = m_sLastSearchedFor
If .Text.Length > 0 Then .SelectionStart = .Text.Length
End If
End If
End With
End If
Catch theException As Exception
' ...
End Try
End Sub
Private Function GetSuggestions(ByVal searchFor As String) As IList
BindingSource.Filter = "CName LIKE '%" & searchFor & "%'"
Return BindingSource.List
End Function
End Class
The way we address this with very large sets of data (full set of drug information) is:
1) Handle the combo's TextChanged event
2) Within this event, get the list of suggestions that match the user's current input from the database. We leverage the power of database searching to find matches anywhere within the string.
3) When the suggestions are retrieved, bind them to the combobox
4) Wait for a little bit (500ms) to let the UI catch up (we use a combination of System.Threading.Thread.Sleep and System.Windows.Format.Application.DoEvents()).
A couple of notes on this approach:
1) Nothing is bound to the list when the form is first opened
2) We wait until the user has entered at least 4 characters before we start searching to reduce the hit on the DB and improve the user experience (you don't want to show all of the matches for A, for example).
Update with code to show full solution:
Here are some additional notes and code to show the actual process.
The ComboBox should be configured with all of the properties set to their default values with the exception of:
AutoCompleteMode = SuggestAppend
PreferredDropDownSize = 0, 0
Here is the code that we use for our specific situation (searching first four chars) with a placeholder for retrieving and assigning the data:
Private m_fOkToUpdateAutoComplete As Boolean
Private m_sLastSearchedFor As String = ""
Private Sub cboName_KeyDown(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyEventArgs) Handles cboName.KeyDown
Try
' Catch up and down arrows, and don't change text box if these keys are pressed.
If e.KeyCode = Keys.Up OrElse e.KeyCode = Keys.Down Then
m_fOkToUpdateAutoComplete = False
Else
m_fOkToUpdateAutoComplete = True
End If
Catch theException As Exception
' Do something with the error
End Try
End Sub
Private Sub cboName_TextChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles cboName.TextChanged
Try
If m_fOkToUpdateAutoComplete Then
With cboName
If .Text.Length >= 4 Then
' Only do a search when the first 4 characters have changed
If Not .Text.Substring(0, 4).Equals(m_sLastSearchedFor, StringComparison.InvariantCultureIgnoreCase) Then
Dim cSuggestions As IEnumerable
Dim sError As String = ""
' Record the last 4 characters we searched for
m_sLastSearchedFor = .Text.Substring(0, 4)
' And search for those
cSuggestions = GetSomeSuggestions(m_sLastSearchedFor) ' Your code here
.DataSource = Nothing
If cSuggestions IsNot Nothing Then
' Because this can use the same data source as the list, ensure that
' the bindingcontexts are different so that the lists are not tied to each other
.BindingContext = New BindingContext
.DataSource = cSuggestions
' Let the UI process the results
System.Threading.Thread.Sleep(10)
System.Windows.Forms.Application.DoEvents()
End If
End If
Else
If Not String.IsNullOrEmpty(m_sLastSearchedFor) Then
' Clear the last searched for text
m_sLastSearchedFor = ""
cboName.DataSource = Nothing
End If
End If
End With
End If
Catch theException As Exception
' Do something with the error
End Try
End Sub