Getting started with VB.Net
Introduction
C# and VB.Net
are the main languages used to write applications with the .Net
framework.
Most assemblies, ie. .Net libraries, live in a directory called the Global
assembly cache (GAC), eg. C:\WINDOWS\assembly. The Intermediate Language Disassembler
utility (ildasm.exe) and Reflector
provide information about any assembly.
Setup
.Net = big library
SDK = compiler (vbc.exe)
Visual Studio, Visual Basic Express, or SharpDevelop
= IDE
The SDK, which includes the .Net framework, is installed when you install Visual Studio.
If you decide to use the SharpDevelop IDE instead, you'll have to install the
SDK manually.
How to reduce cold startup time
Applications written in managed code will always take longer to start since
they require loading big libraries and compiling the opcode with the JIT at
runtime. To improve performance, after it's been compiled by the JIT on the
fly, the machine code version is kept in Windows' disk cache. This explains
why the application starts much faster if it's restarted shortly.
To view which DLLs an application uses and whether the .Net DLL's are currently
loaded, use Process
Explorer.
Machine code generated manually by Ngen.exe is named following the pattern
<app name>.ni.exe, is not directly executable, and is saved in subdirectories
C:\Windows\Assembly\NativeImages_X. Note that Windows Explorer hides those sub-directories,
so you'll have to use another file manager or open a DOS box to see them. Ngen
lives in C:\WINDOWS\Microsoft.NET\Framework\<version number>\.
Here are ways to reduce the time it takes to load an application:
- Don't use an antivirus. Alternatively, either only use it to check a
file manually, or mark the application + the .Net framework as safe applications
so that they are ignored by the AV application
- Make sure the host has enough RAM so that Windows can keep as many files
as possible in its file system cache
- If the application is on the bigger side, try and use Ngen to compile the opcode into machine code, so that the
JIT is no longer needed. If you notice that this doesn't improve startup
time, this means that the main issue is the time required to load the .Net
assemblies. It might be possible to keep Ngen-compiled applications in Windows' file system cache
- Load only the minimum number of modules in the main application, and
differ loading other modules when they are really needed
- POSSIBLE? Place the DLLs ("assemblies") in the file system
cache
- CHECK Preload the CLR when the computer starts (sneaky, but...)
- Replace hard-disks with SSDs
Improving
Managed Code Performance (Ngen.exe)
Native
Image Generator (NGen)
How
I Improved Execution Speed By 100 Times in 5 Minutes
.NET Framework
Client Profile
VMWare ThinApp (ex-ThinInstall?)
CacheSet
v1.0
Gacutil.exe
Global Assembly Cache Tool
Improving
Application Startup Performance
AnalogX
CacheBooster
Increase
Or Decrease Your Hard Drive Cache Memory With CacheBooster
How
to increase the cache on your hard disk?
Pre-compile
(pre-JIT) your assembly on the fly, or trigger JIT compilation ahead-of-time
How to distribute without the .Net framework
Remotesoft Salamander .NET Linker,
Native Compiler and Mini-Deployment Tool ("Deploy .NET w/o Framework")
Not a good idea, but YMMV.
Coding
Starting with no form
Here's how to do it in Visual Basic Express:
- Project > MyApp Properties > Application, uncheck "Enable
application framework"
- Next, in Startup object, choose "Sub Main"
- Finally, copy/paste this code:
Public Shared Sub Main()
MessageBox.Show("Main")
End
Sub
Here's how to do it in SharpDevelop:
(Build a Notification project instead, and figure out where to put your code).
Copying a string to the clipboard
Clipboard.SetText("Some text")
Pasting a string from the clipboard
Clipboard.GetText
Starting a second application
Based on this
article.
If you just want to start an application, use this:
- System.Diagnostics.Process.Start ("c:\windows\notepad.exe")
If you want to have access to a bit of information, use this:
- Dim myProcess As Process = System.Diagnostics.Process.Start("c:\windows\notepad.exe")
- MessageBox.Show(myProcess.ProcessName)
Yet more control with...
- Dim psInfo As New System.Diagnostics.ProcessStartInfo("c:\windows\notepad.exe")
-
- psInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Normal
-
- Dim myProcess As Process = System.Diagnostics.Process.Start(psInfo)
... or this:
- Dim myProcess As System.Diagnostics.Process = new System.Diagnostics.Process()
-
- myProcess.StartInfo.FileName = "c:\windows\notepad.exe"
- myProcess.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Normal
-
- myProcess.Start
Alternatively, you can add a Process component to your project and configure
its settings at design-time.
Here's how to launch a process with no window showing:
- Dim myProcess As Process = New Process()
- Dim s As String
- Dim outfile As String = Application.StartupPath & _
- "\dirOutput.txt"
-
- ' get the System path
- Dim sysFolder As String = System.Environment.GetFolderPath(Environment.SpecialFolder.System)
-
- ' set the file name and the command line args
- myProcess.StartInfo.FileName = "cmd.exe"
- myProcess.StartInfo.Arguments = "/C cd " & _
- sysFolder & " && dir *.com >> "
& Chr(34) & _
- outfile & Chr(34) & " && exit"
-
- ' start the process in a hidden window
- myProcess.StartInfo.WindowStyle = ProcessWindowStyle.Hidden
- myProcess.StartInfo.CreateNoWindow = True
- myProcess.Start()
-
- ' if the process doesn't complete within 1 second, kill it
- myProcess.WaitForExit(1000)
- If Not myProcess.HasExited Then
- myProcess.Kill()
- End If
-
- ' display exit time and exit code
- MessageBox.Show("The 'dir' command window was " & _]
- "closed at: " & myProcess.ExitTime & "."
& _
- System.Environment.NewLine & "Exit Code: "
& _
- myProcess.ExitCode)
- myProcess.Close()
Here's how to wait until the process has ended:
- 'One potential problem with both of these methods is that if the launched
process hangs or never exits, your application is stuck. One solution is
to add a timer that fires periodically, and checks to see if the launched
application is still responding.
-
- ' allow the process to raise events
- myProcess.EnableRaisingEvents = True
-
- ' add an Exited event handler
- AddHandler myProcess.Exited, AddressOf Me.ProcessExited
-
- ' event handler
- Friend Sub ProcessExited(ByVal sender As Object, ByVal e As System.EventArgs)
-
- Dim myProcess As Process
= DirectCast(sender, Process)
-
- MessageBox.Show("The
process exited, raising " & _
- "the Exited event
at: " & myProcess.ExitTime & _
- "." &
System.Environment.NewLine & _
- "Exit Code: "
& myProcess.ExitCode)
-
- myProcess.Close()
- End Sub
Formating strings
MessageBox.Show(String.Format("Some {0} {1}", "Dummy", "data"))
Using the Registry
- Const Key="HKEY_CURRENT_USER"
- Const Value="Ez Voice Mail"
- Const KeyValue = Key & "\" & Value
- Const SubKey="MySubKey"
-
- If My.Computer.Registry.GetValue(KeyValue, SubKey, Nothing) Is Nothing
Then
- My.Computer.Registry.CurrentUser.CreateSubKey(Value)
- My.Computer.Registry.SetValue(KeyValue, SubKey,
"Dummy data")
- Else
- Dim readValue As String
- readValue = My.Computer.Registry.GetValue(KeyValue,
SubKey, Nothing)
- MsgBox("The value is " & readValue)
- End If
-
- My.Computer.Registry.CurrentUser.DeleteSubKey(Value)
Reading for a text file line by line
Here's a first way:
- If System.IO.File.Exists(FILE_NAME) = True Then
- Dim srFileReader As System.IO.StreamReader
- Dim sInputLine As String
-
- srFileReader = System.IO.File.OpenText("myfile.txt)
- sInputLine = srFileReader.ReadLine()
- Do Until sInputLine Is Nothing
- 'Do something
- sInputLine = srFileReader.ReadLine()
- Loop
- End If
Alternatively:
- Dim objReader As New System.IO.StreamReader("myfile.txt")
- Dim Line As String
-
- Do While objReader.Peek() <> -1
- Line = objReader.ReadLine
- 'Do something
- Loop
Writing to a text file
- Dim objWriter As New System.IO.StreamWriter("myfile.txt")
- objWriter.Write(RichTextBox1.Text)
- objWriter.Close()
Running lengthy process without freezing UI
Here's an example downloading a web page. On a form, add a Button and a BackgroundWorker object:
Public Class Form1
Private Sub Button1_Click(ByVal sender As System.Object,
ByVal e As System.EventArgs) Handles Button1.Click
BackgroundWorker1.WorkerReportsProgress
= True
BackgroundWorker1.RunWorkerAsync()
End Sub
Private Sub BackgroundWorker1_DoWork(ByVal sender
As System.Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles
BackgroundWorker1.DoWork
Try
Dim
webClient As New System.Net.WebClient
e.Result
= webClient.DownloadString("http://192.168.0.10/")
Catch ex As Exception
'Note:
WebClient has no TimeOut property. HttpWebRequest is more solid
End Try
End Sub
Private Sub BackgroundWorker1_RunWorkerCompleted(ByVal
sender As System.Object, ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs)
Handles BackgroundWorker1.RunWorkerCompleted
Me.RichTextBox1.AppendText(e.Result)
End Sub
End Class
Tell Express to save files at the root of a project directory
BAD File > Save All: MyTest (default: WindowsApplication1)
BAD Project > Properties > Application: Empty "Root namespace"
Run a lenghty process
While (True)
Try
'perform
some lenghty process here
Exit While
Catch ex As Exception
'BackgroundWorker1.ReportProgress(100,
ex.Message)
MessageBox.Show(ex.Message)
End Try
System.Threading.Thread.Sleep(2000)
End While
Use regex to read part of a block of text
- Imports System.Text.RegularExpressions
-
- Public Class Form1
- Private Sub Button1_Click(ByVal sender As System.Object,
ByVal e As System.EventArgs) Handles Button1.Click
- Dim data as String =
"dummy <title>my title</title> dummy"
- Dim title As Regex = New Regex("<title>(.+?)</title>")
- Dim m As Match
-
- m = title.Match(data)
- If m.Success Then
- MsgBox(m.Groups(1).Value)
- End If
- End Sub
- End Class
Note: Options such as SingleLine are available:
- Dim title As Regex = New Regex("<title>(.+?)</title>",
RegexOptions.Singleline)
More information: www.regular-expressions.info/dotnet.html
Recurse through directory
Here's how to start from a directory and get all the files and sub-directories
it contains:
- Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles Button1.Click
- Dim filelist As Collections.ObjectModel.ReadOnlyCollection(Of
String) = My.Computer.FileSystem.GetFiles("C:\MyFiles\", FileIO.SearchOption.SearchAllSubDirectories)
-
- For Each path As String In filelist
- ListBox1.Items.Add(path)
- Next
- End Sub
Actually, FileSystem.GetFiles() is not a good solution if you might try to
enter a protected sub-directory, as it stops searching if it
tries to enter an off-limit directory.
A dirty solution is to just ignore the error:
- For Each fileitem In dir.GetFiles("C:\", "MyFiles.*")
- Try
- Dim fileDetail
As IO.FileInfo
- fileDetail =
My.Computer.FileSystem.GetFileInfo(fileitem.FullName)
- Dim str As String
= fileDetail.FullName
- BackgroundWorker1.ReportProgress(0,
str)
- Catch err As UnauthorizedAccessException
- 'Just ignore
and resume search
- End Try
- Next
Here
is a recursive solution, but as it uses GetFiles(), it doesn't display files as it finds them so it's
no possible to update the UI so the user knows how far the search is :-/
Having ListBox scroll to end automatically
ListBox1.SelectedIndex = ListBox1.Items.Count - 1
Get Current Time
- ListBox1.Items.Add("Before GetResponse @ " + DateTime.Now)
- ListBox1.Refresh()
Get double-clicked item in ListBox
MsgBox(ListBox1.SelectedItem.ToString)
Timer
After adding a Timer component to a form, here's how to enable the timer
and execute code with every tick:
- Imports System.IO
- Imports System.Text
- Imports System.Text.RegularExpressions
- Imports System.Threading.Thread
- Imports System.Windows.Forms
-
- Public Class Form1
- Dim TimerBusy As Boolean = False
-
- Private Sub Button1_Click(ByVal sender As System.Object,
ByVal e As System.EventArgs) Handles Button1.Click
- ListBox1.Items.Clear()
-
- 'Check every minute
- 'Force timer to tick right away
instead of waiting for event trigger
- Timer1.Interval = 60000
- Timer1.Enabled = True
- Timer1_Tick(Nothing, Nothing)
- Timer1.Start()
- End Sub
-
- Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal
e As System.EventArgs) Handles Timer1.Tick
- 'Check if routine still running
previous tick
- If TimerBusy Then
- Exit Sub
- Else
- TimerBusy
= True
- End If
-
- 'Do stuff
- End Sub
- End Class
SQLite
There are a few solutions to connect VB.Net applications to an SQLite database
file. One of them is the open-source System.Data.SQLite.
Besides choosing the right CPU architecture (32- or 64-bits) and .Net framework
version (2.0 SP2, 3.5 SP1, 4.0, or 4.5), you must choose between...
- "bundle" contains System.Data.SQLite.dll, a single, mixed-mode assembly
(SQLite + .Net wrapper). "The mixed-mode assembly contains native code
for one platform as well as the managed code. This prevents the same
application from being easily deployed on both x86 and x64. I suppose if
you only ever deal with one processor architecture on all the target machines,
it's just fine to use the bundled packages. Also, mixed-mode assemblies
are not supported by Mono or the .NET Compact Framework."
- "no bundle" contains two binaries: SQLite.Interop.dll contains
the native code for SQLite; System.Data.SQLite.dll contains the managed
code for the ADO.NET provider and loads the other file at runtime
Use the bundle package if you need to support
legacy applications by having it installed in the Global Assembly Cache
(GAC)
... and different packages:
- Precompiled binaries : requires Visual C++ 2005 SP1 runtime. This is
the solution for most developers and users
- Setups : includes Visual C++ 2012 RTM runtime. Only use this on a developer
host, and only if you need the design-time component
- Precompiled static : Visual C++ 2005 SP1 runtime for x86 is statically
linked. Only required if the user can't install the VC++ runtime. This
is the recommended version
When using the non-static versions, make sure the VC++ runtime is installed,
or ou might get the following errors: "Unable to load DLL 'SQLite.Interop.dll"
or "Could not load file or
assembly 'System.Data.SQLite.dll' or one of its dependencies. The specified
module could not be found." This is due to the fact that the (no-)bundle versions rely on MSVCR110.DLL,
which is part of the Visual
C++ Redistributable for Visual Studio 2012 Update 1. Once the runtime is
installed, the error should go away.
Since the SQLite DLL is available in a statically version ("Precompiled Statically-Linked Binaries"),
I fail to see the added value of the other two versions. Maybe it's so the dynamic-linked
libraries take advantage of upgrades to the VC++ runtime.
Once you know which package to download...
- Download
the latest and greatest package. If using Precompiled, just unzip the file
anywhere
- Create and save a new Windows Form VB.Net project
- Add a reference to this DLL: Project > Add Reference > System.Data.SQLite.dll
- In the code, add "Imports System.Data.SQLite"
Note:
- If using the bundle (ie. single file, managed System.Data.SQLite.dll)
add this:
Imports System.Data.SQLite
- If using the non-bundle (ie. two files, including an unmanaged DLL),
put the two files in the application's directory, or you'll get "SQLite.Interop.dll
: The specified module could not be found"
Questions:
- Why does the Setups use the 2012 VC++ runtime while the Precompiled
binaries use the 2005 runtime?
- What does the design-time component offer?
More Infos:
Test on brand new W7 host:
- Installed Visual Studio Express 2012 for Windows Desktop
- Installed Setups for 32-bit Windows (.Net Framework 4.5) bundle 1.0.84.0
:
Two options can be checked:
(default: Checked) "Generate
native images for the assemblies and install the images in the native image
cache"
"Install the assemblied into the global assembly
cache" + "Install the designer components for Visual Studio 2012"
Note:
The design-time component is no longer supported for Express editions
- Created new Forms project, tried to add reference to SQLite:
Project
> Add Reference: No trace of SQLite in Assemblies > Framework/Extension
Ran
Installer.exe: "Cannot continue, the "confirm" option is
not enabled"
In Project > Add Reference, hit "Browse",
and pointed to "System.Data.SQLite.DLL": Seems OK
- Next, tried this:
Imports System.Data.SQLite
Dim
SQLconnect As New SQLite.SQLiteConnection()
Dim SQLcommand As SQLiteCommand
'Note:
Non-admin app cannot write to c:\
SQLconnect.ConnectionString = "Data
Source=c:\users\fred\test.sqlite;"
SQLconnect.Open()
SQLcommand
= SQLconnect.CreateCommand
SQLcommand.CommandText = "CREATE TABLE IF NOT EXISTS Item (type)"
SQLcommand.ExecuteNonQuery()
SQLcommand.CommandText
= "INSERT INTO Item (type) VALUES ('something')"
SQLcommand.ExecuteNonQuery()
SQLcommand.Dispose()
SQLconnect.Close()
- Next, uninstalled SQLite: Application still runs, since VS copied System.Data.SQLite.dll
into the project's \Debug sub-directory
- Next, installed fresh Windows7 setup, installed Visual Studio Express
2012 for Windows Desktop
- Unzipped Precompiled Binaries no bundle ZIP, without installing required
VC++ 2012 RTM runtime, and without running Installer.exe, added reference:
"SQLite.Interop.dll : The specified module could not be found".
Installed VC++ 2012 RTM
runtime: no change. Copied SQLite.Interop.dll into \debug: OK!
- Heres' how to read the data:
SQLcommand.CommandText = "SELECT
* FROM Item"
Dim SQLreader As SQLiteDataReader = SQLcommand.ExecuteReader()
lst_records.Items.Clear()
While
SQLreader.Read()
lst_records.Items.Add(String.Format("ID
= {0}, type = {1}", SQLreader(0), SQLreader(1)))
'Alternative
'lst_records.Items.Add(String.Format("ID
= {0}, Title = {1}", SQLreader("id"), SQLreader("type")))
End
While
Test: Copy SQLite.Interop.dll in .\x86 where System.Data.SQLite.DLL is located
in .\. The native library pre-loading feature in System.Data.SQLite.dll will
check .\x86 or .\x64.
DataGridView
This is an unbound grid object. Here's how to create some columns, and add
a couple of rows:
- Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles Button1.Click
- With DataGridView1
- 'Hide ugly, left-most
column
- .RowHeadersVisible =
False
-
- .ReadOnly = False
-
- 'Prevents adding rows
when editing cell
- .AllowUserToAddRows
= False
-
- 'Name + Label
- .Columns.Add("Key",
"Key")
- .Columns.Add("Value",
"Value")
-
- .Rows.Add(2)
-
- '.Item(0, 0).Value =
"Key1"
- '.Item(0, 1).Value =
"Value1"
- .Rows(0).Cells("Key").Value
= "key1"
- .Rows(0).Cells("Value").Value
= "value1"
-
- .BackgroundColor = SystemColors.Control
- .AutoSizeColumnsMode
= DataGridViewAutoSizeColumnsMode.Fill
- End With
- End Sub
Apparently, it's not possible to add rows and contents to an unbound control
at design time.
Any way to use names for rows instead of index number?
.Rows("myrow").Cells("mykey").Value = "myvalue"
Alternative, open-source grids:
- "SourceGrid is a
.NET Windows Forms grid control written entirely in C# with managed code"
- Lamegrid
More information:
Downloading a web page with WebClient
WebClient doesn't have a lot of features, but it's good enough to download
a web page, synchronously or asynchronously, the latter being a better option
since it prevents the UI from freezing while we're waiting for the web page
to be downloaded:
- 'Add Button + RichTextBox to form
-
- Imports System.Net
- Imports System.IO
-
- Public Class Form1
- Private Sub AlertStringDownloaded(ByVal
sender As Object, ByVal e As DownloadStringCompletedEventArgs)
- If e.Cancelled = False
AndAlso e.Error Is Nothing Then
- RichTextBox1.Text
= CStr(e.Result)
RichTextBox1.Refresh()
Button1.Enabled = True
- End If
- End Sub
-
- Private Sub Button1_Click(ByVal sender As System.Object,
ByVal e As System.EventArgs) Handles Button1.Click
- Button1.Enabled = False
-
- Dim URL As String =
"http://www.google.com"
-
- Dim theaters As New
Dictionary(Of String, String) theaters.Add("Theater
#1", "http://www.theaters.com/1.html") theaters.Add("Theater
#2", "http://www.theaters.com/2.html")
-
- For Each kvp As KeyValuePair(Of
String, String) In theaters
- 'Synchronous
DownloadString freezes UI while waiting for web page
-
- Dim
webClient As New WebClient
- AddHandler
webClient.DownloadStringCompleted, AddressOf AlertStringDownloaded
-
- ListBox1.Items.Add(kvp.Key)
-
- webClient.DownloadStringAsync(New
Uri(kvp.Value))
- Next
-
- End Sub
- End Class
Note: When downloading multiple web pages as above, you can't tell WebClient
to download them in order. You could save each page into a database, and sort
them later.
POSTing variables to a web server and receiving data with WebClient
Here's how to connect to a web server, send variables with the POST method,
and receive data:
- Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles Button1.Click
- Dim client As New WebClient()
-
- Dim collect As New Specialized.NameValueCollection
- collect.Add("param1", "john")
- collect.Add("param2", "doe")
-
- client.Headers.Add("Content-Type",
"application/x-www-form-urlencoded")
-
- 'Turn bytes into a string
- RichTextBox1.Text = Encoding.ASCII.GetString(client.UploadValues("localhost",
"POST", collect))
- End Sub
Downloading a web page with HttpWebResponse
Although System.Net.WebClient is easier to use, System.Net.HttpWebRequest
(and HttpWebResponse) offers more features.
- Imports System.Net
- Imports System.IO
-
- Public Class Form1
- Const URL = "http://www.google.com"
-
- Private Sub Button1_Click(ByVal sender As System.Object,
ByVal e As System.EventArgs) Handles Button1.Click
- Dim Request As HttpWebRequest
- Dim Response As HttpWebResponse
- Dim ResponseStream As
StreamReader
- Dim Result As String
-
- Try
- Request
= HttpWebRequest.Create(URL)
-
- Response
= Request.GetResponse()
-
- ResponseStream
= New StreamReader(Response.GetResponseStream())
- Result
= ResponseStream.ReadToEnd()
- Response.Close()
-
- RichTextBox1.Text
= Result
- Catch ex As Exception
- MsgBox(ex.Message)
- End Try
- End Sub
- End Class
Enhanced use of HttpWebRequest + HttpWebResponse
Here's how to enable cookies, connect out through a web proxy, and POST a
login + password to log on to a web server:
Uploading a file to an FTP server
Using System.Net.WebClient
WebClient can upload (and download) as Data/File/String/Values ("Values"
is to send metadata in the HTTP header), synchronously or asynchronously, in
HTTP or FTP.
Imports System.Net
Try
Const File as String = "dummy.txt"
Dim filename As String = "ftp://www.acme.com/"
& File
Dim client As New WebClient
client.Credentials = New NetworkCredential("myself",
"mypasswd")
client.Proxy = Nothing
client.UploadFile(filename, "C:\" &
File)
MsgBox("File uploaded!")
Catch ex As Exception
MsgBox(ex.ToString)
End Try
Using System.Net.WebRequest/WebResponse
Those are abstract classes that derive into HttpWebRequest and FileWebRequest/FTPWebRequest.
Extracting filename from fully-qualified path
Dim dirName As String = IO.Path.GetFileName(fullPath)
or
System.IO.Path.GetFileNameWithoutExtension(FullPath)
Dictionary
Dim
keys As New List(Of String)()
Dim
storedValues As New Dictionary(Of String, String)()
keys.Add("server")
keys.Add("login")
keys.Add("password")
keys.Add("url")
For
Each mykey In keys
storedValues.Add(mykey,
CStr(My.Computer.Registry.GetValue(KeyValue, mykey, String.Empty)))
Next
Dim dict As New Dictionary(Of
String, String)
dict.Add("server",
Nothing)
dict.Add("login",
Nothing)
dict.Add("password",
Nothing)
dict.Add("url",
Nothing)
'For Each kvp As KeyValuePair(Of
String, String) In dict
' 'Property
"Value" is read-only
' kvp.Value
= My.Computer.Registry.GetValue(KeyValue, kvp.Key, Nothing)
' MessageBox.Show("Key:
" + kvp.Key + " Value: " + kvp.Value)
'Next
For Each MyKey In dict.Keys
dict(MyKey)
= My.Computer.Registry.GetValue(KeyValue, MyKey, Nothing)
MessageBox.Show("Key:
" + MyKey + " Value: " + dict(MyKey))
'Collection
was modified; enumeration operation may not execute.
Next
Two-column, unbound grid?
When you need to enter a bunch of key/value tuples:
datagridview
propertygrid
http://www.vbnettutorial.net/?Id=125&Desc=VB.Net-DataGridView
http://vb.net-informations.com/datagridview/vb.net_datagridview_tutorial.htm
http://www.dotnetperls.com/datagridview-vbnet
Generate a unique filename
System.IO.Path.GetTempFileName()
Dim sTempFileName As String = System.IO.Path.GetTempFileName()
Guid.NewGuid()
Dim FileName As String
FileName = Guid.NewGuid().ToString().GetHashCode().ToString("x")
FileName = String.Format("c:\{0}.txt", FileName)
Storing key,value in a Dictionary
DataGridView
propertygrid
Checking that a node exists in the Registry
Dim regKey As RegistryKey
Try
regKey = Registry.CurrentUser.OpenSubKey("My
node", False)
If regKey Is Nothing Then
MessageBox.Show("Node
doesn't exist")
End If
Catch ex As Exception
MessageBox.Show(ex.Message, "Error: Reading
Registry Value", MessageBoxButtons.OK, MessageBoxIcon.Error)
End Try
Checking that a file exists
Imports System.IO
...
Const MYAPP = "myapp.exe"
If File.Exists(MYAPP) = False Then
MessageBox.Show(MYAPP & " not found. Exiting.")
End
End If
Enhancements
Charts
Grid
All Windows Forms > DataGridView
Deployment
ClickOnce
Language/IDE Peeves
In a Release version of a program, does it end with Catch?
... or must I add an End?
[Express 2008] No support for bookmarking/navigating with F2/CTRL-F2
[Express 2008] No support for in-place scrolling through CTRL+up/down
[Express 2008] No support for code block (un)folding
Only available for whole routine, not if/endif, select/endselect, etc.
Can't disable automatic indenting for the following case
In VB.Net Express 2008 at least, it's an either/or, ie. you can't disable
auto-indenting only in certain cases such as this one:
- 'Comment about what following block does
- If A Then
-
- 'This comment not lined up with Else block that
follows
- Else
- 'Stuff happens
No support for in-place scrolling with CTRL-up/down arrow
No support for whole-block out-commenting
Must still prepend each line with an apostrophe, instead of C's /*...*/
Q&A
In Visual Studio Express, how to hide debugging windows?
Ie. "Memory", "Watch", "Locals", etc.
Tools > Options > Debugging > General: Uncheck "Enable address-level
debugging".
What files must be checked in the source control manager?
- *.sln
- *.resx
- *.vb
- *.vbproj
- *.settings
- CHECK *.myapp and *.user might be user-specific and possibly should
be stripped when shipping code to someone else
IOW, ignore \bin and \obj.
Why should I install the .Net SDK in addition to the SharpDevelop IDE?
http://community.sharpdevelop.net/forums/p/14362/38239.aspx#38239
Ngen: I can't find where it saved the machine code of an application
It seems to sometime name the file under a different name than the opcode
version.
ngen display > display.txt
Why does this code report success although the file isn't actually uploaded?
Sub WebClientUploadFileCompleted(ByVal
sender As Object, ByVal e As UploadFileCompletedEventArgs)
MessageBox.Show("Done!")
End Sub
Private Sub Button1_Click(ByVal sender
As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim client
As New WebClient()
AddHandler
client.UploadFileCompleted, AddressOf WebClientUploadFileCompleted
Try
With
client
.Credentials
= New NetworkCredential("jdoe", "mypasswd")
.UploadFileAsync(New
Uri("ftp://ftp.acme.com"), "c:\test.txt")
End
With
Catch ex As
Exception
MessageBox.Show(ex.Message)
End Try
End Sub
How to check that the user has the right .Net framework?
How to check code that requires the app to run as Administrator?
How to investigate why an app doesn't start?
In case an application refuses to start on a test host while it works fine
on your develop host, add the following code to the form:
Edit: In case another newbie stumbles on this issue: It was due to a missing
dependency. To catch this type of error, add the following to Form1:
- Public Sub New()
- AddHandler Application.ThreadException,
AddressOf OnThreadException
- AddHandler AppDomain.CurrentDomain.UnhandledException,
AddressOf UnhandledExceptionEventRaised
-
- InitializeComponent()
- End Sub
-
- Private Sub UnhandledExceptionEventRaised(ByVal sender As Object, ByVal
e As UnhandledExceptionEventArgs)
- If e.IsTerminating Then
- Dim
o As Object = e.ExceptionObject
- MessageBox.Show(o.ToString)
' use EventLog instead
- End If
- End Sub
-
- Private Sub OnThreadException(ByVal sender As Object, _
- ByVal
e As ThreadExceptionEventArgs)
- ' This is where you
handle the exception
- MessageBox.Show(e.Exception.Message)
- End Sub
How to check which .Net framework a program needs to run?
[DataGridView] Any way to name a row?
... so that we can refer to rows with names just like we do for columns?
.Rows(0).Cells("Key").Value = "key1"
Why does BeginGetResponse() wait for a couple of seconds?
To resolve the hostname. Just use an IP address instead, and BeginGetResponse()
won't block.
How to create an installer with InnoSetup?
How to easily comment a whole block of code?
Don't want to prepend each line with '
Which IDE should I use?
MS'VisualStudio? SharpDevelop? Other?
How to check if the user has the right version of the .Net framework and
any needed ServicePack?
Manually: Through the "Add or remove Programs" applet in Control
Panel (look for "Microsoft .Net Framework").
Programmatically:
Is .Net downward-compatible?
ie. can an application compiled for 2.0 run on 3.5?
What happens if the user isn't logged with enough admin rights to install
.Net and/or any needed ServicePack?
What makes Mono better than .Net for Windows apps?
VisualStudio vs. VisualStudio Express?
http://en.wikipedia.org/wiki/Microsoft_Visual_Studio_Express
Why import System and System.Drawing?
- Imports System
- Imports System.Drawing
.Net for Macintosh?
Is there a difference between the code created by SharpDevelop and Visual
Studio?
Resources
Books
- Pro VB 2008 and the.NET 3.5 Platform, Third Edition.pdf
- Wrox - Professional Visual Basic 2008 (Programmer to Programmer) (2009).pdf
Sites
Forums