VB.et FileSystemWatcher Event Handler - Calls of Handler Repeats (Unwanted) - vb.net

I'm trying to log file activity in a directory with the FileSystemWatch class by adding the file to a custom class within a list, unfortunately, it seems that when copying a file or adding a new file to the target directory, it's running 4 times instead of once.
When adding a file to the directory, the AddressOf Sub will write 3 to 4 times instead of just once. I'm not sure why.
Here's the code snippet.
Public fileTypefilter As String = "*.xlsx"
Public DesDir As String = "C:\"
Public EventLog As List(Of FileEvent)
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim watchDir As String = DesDir
Dim watch As New FileSystemWatcher(watchDir)
Me.Text = "Monitoring " & watch.Path
watch.IncludeSubdirectories = false
watch.Filter = "*.xlsx"
AddHandler watch.Changed, AddressOf watch_Changed
watch.EnableRaisingEvents = True
End Sub
Private Sub watch_Changed(ByVal sender As Object, ByVal e As FileSystemEventArgs)
Try
EventLog.Add(New FileEvent(e.FullPath))
Exit Sub
Catch ex As NullReferenceException
EventLog = New List(Of FileEvent)({New FileEvent(e.FullPath)})
Exit Sub
End Try
End Sub

The Changed event handler is executed multiple times because multiple changes occur. As is ALWAYS the case, you should have read the relevant documentation for yourself first, which says:
The change of a file or folder. The types of changes include: changes to size, attributes, security settings, last write, and last access time.
If you don't want to log each individual change then you need to filter them somehow. For instance, you might want to record the time a change occurred for a particular path and then not log a change if some minimum time has not elapsed since the last change for the same path.
There would also be the option of using a HashSet instead of a List. That could be configured to use an appropriate equality comparer and then you could call Add as many times as you like for the same path and it will only be added once. That would mean that, were a set of changes to occur later for the same path, those would not be logged. I'm not sure whether that would be an issue for you or not.

Related

location of recent files list vb.net

I am looking to add a recent files list to an application I am writing.
I was thinking of adding the recent files to an xml file.
Where should this file be stored?
And how should it be called from the code?
I would imagine the xml would be stored in the same folder that the application is installed in, but not everybody will install the application in the same directory.
Is there a way to code it in such a manner that it will always be stored in the same folder as the application will be installed in?
much thanks in advance!
Here is an example using My.Settings. It requires you to open the Settings page of the project properties and add a setting of type StringCollection named RecentFiles as well as a ToolStripMenuItem with the text "Recent".
Imports System.Collections.Specialized
Public Class Form1
Private Const MAX_RECENT_FILES As Integer = 10
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
LoadRecentFiles()
End Sub
Private Sub LoadRecentFiles()
Dim recentFiles = My.Settings.RecentFiles
'A StringCollection setting will be Nothing by default, unless you edit it in the Settings designer.
If recentFiles Is Nothing Then
My.Settings.RecentFiles = New StringCollection()
recentFiles = My.Settings.RecentFiles
End If
'Get rid of any existing menu items.
RecentToolStripMenuItem.DropDownItems.Clear()
'Add a menu item for each recent file.
If recentFiles.Count > 0 Then
RecentToolStripMenuItem.DropDownItems.AddRange(recentFiles.Cast(Of String)().
Select(Function(filePath) New ToolStripMenuItem(filePath,
Nothing,
AddressOf RecentFileMenuItems_Click)).
ToArray())
End If
End Sub
Private Sub UpdateRecentFiles(filePath As String)
Dim recentFiles = My.Settings.RecentFiles
'If the specified file is already in the list, remove it from its old position.
If recentFiles.Contains(filePath) Then
recentFiles.Remove(filePath)
End If
'Add the new file at the top of the list.
recentFiles.Insert(0, filePath)
'Trim the list if it is too long.
While recentFiles.Count > MAX_RECENT_FILES
recentFiles.RemoveAt(MAX_RECENT_FILES)
End While
LoadRecentFiles()
End Sub
Private Sub RecentFileMenuItems_Click(sender As Object, e As EventArgs)
Dim menuItem = DirectCast(sender, ToolStripMenuItem)
Dim filePath = menuItem.Text
'Open the file using filePath here.
End Sub
End Class
Note that the Load event handler includes a bit of code to allow for the fact that a setting of type StringCollection will be Nothing until you assign something to it. If you want to avoid having to do that in code, do the following.
After adding the setting, click the Value field and click the button with the ellipsis (...) to edit.
Add any text to the editor and click OK. Notice that some XML has been added that includes the item(s) you added.
Click the edit button (...) again and delete the added item(s). Notice that the XML remains but your item(s) is gone.
That XML code will cause a StringCollection object to be created when the settings are first loaded, so there's no need for you to create one in code.
EDIT:
I tested that by adding the following code:
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Using dialogue As New OpenFileDialog
If dialogue.ShowDialog() = DialogResult.OK Then
UpdateRecentFiles(dialogue.FileName)
End If
End Using
End Sub
I was able to add ten files to the list via that Button and then they started dropping off the end of the list as I added more. If I re-added one that was already in the list, it moved to the top. If I closed the app and ran it again, the list persisted.

vb.net datetimepicker not taking value from my.setting

I have this code to save value from datetimepicker1:
Private Sub DateTimePicker1_Validating(sender As Object, e As EventArgs) _
Handles DateTimePicker1.Validating
My.Settings.dt1value= DateTimePicker1.Value.ToString
MsgBox("before save")
My.Settings.Save()
MsgBox("after save")
End Sub
It look that it saves value in My.Settings (From Message box 1,2)
Then when closing the app and running it again; it is not loading the My.Settings.dt1value into DateTimePicker1
The code for loading is:
Private Sub main_Shown(sender As Object, e As EventArgs) Handles Me.Shown
DateTimePicker1.Value = Convert.ToDateTime(My.Settings.dt1value)
End Sub
Other controls like Textbox1 is saving and loading properly but only for DateTimePicker is not working.
I tried to change from Handles Me.Shown to Handles Me.Load but same problem.
I have another problem,
When I deploy the application and setup in windows, My.Setting.Save() not working for all controls.
I had read other similar posts and try to follow them but nothing helps.
Any tip appreciated,
Thanks in advance.
First check whether the value is getting saved. Use
MsgBox(My.Settings.dt1value)
instead of
MsgBox("after save").
This will ensure the value is getting saved.
MsgBox("before save") & MsgBox("after save") does NOTHING useful here
But as from your code snippet, It seems the value is getting saved.
In the form Load event write the below mentioned code and check for the output:
string DatePattern = "dd/MM/yyyy HH:mm:ss";
DateTime ConvertedDateTime;
DateTimePicker1.Value = DateTime.TryParseExact(My.Settings.dt1value, DatePattern , null, DateTimeStyles.None, out ConvertedDateTime))
Edit : About your second problem
That is because whenever you update or modify the application in any way, the My.Settings(built-in settings file) gets flushed and a new one is generated. I would suggest you to save your config file in a separate external file. NOT in My.Settings

VB.net program hangs when asked to read .txt

I am attempting to read a .txt file that I successfully wrote with a separate program, but I keep getting the program stalling (aka no input/output at all, like it had an infinite loop or something). I get the message "A", but no others.
I've seen a lot of threads on sites like this one that list all sorts of creative ways to read from a file, but every guide I have found wants me to change the code between Msgbox A and Msgbox D. None of them change the result, so I'm beginning to think that the issue is actually with how I'm pointing out the file's location. There was one code (had something to do with Dim objReader As New System.IO.TextReader(FileLoc)), but when I asked for a read of the file I got the file's address instead. That's why I suspect I'm pointing to the .txt wrong. There is one issue...
I have absolutely no idea how to do this, if what I've done is wrong.
I've attached at the end the snippet of code (with every single line of extraneous data ripped out of it).
If it matters, the location of the actual program is in the "G01-Cartography" folder.
Private Sub GameMain_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
LoadMap("Map_Cygnus.txt")
End Sub
Private Sub LoadMap(FileLoc As String)
FileLoc = "C:\Users\Adam\Documents\Visual Studio 2013\Projects\G01-Cartography\Maps\" + FileLoc
MsgBox("A")
Using File As New StreamReader(FileLoc)
MsgBox("B")
Dim WholeMap = File.ReadLine()
MsgBox("C")
End Using
MsgBox("D")
End Sub
What does running this show you in the debugger? Can you open the Map_Cygnus.txt file in Notepad? Set a breakpoint on the first line and run the program to see what is going on.
Private BaseDirectory As String = "C:\Users\Adam\Documents\Visual Studio 2013\Projects\G01-Cartography\Maps\"
Private Sub GameMain_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
Dim WholeMap = File.ReadAllText(Path.Combine(BaseDirectory, "Map_Cygnus.txt"))
Debug.Print("Size Of Map: {0}", WholeMap.Length)
End Sub
It looks like you're using the correct methods/objects according to MSDN.
Your code runs for me in an new VB console app(.net 4.5)
A different approach then MSGBOXs would be to use Debug.WriteLine or Console.WriteLine.
If MSGBOX A shows but not B, then the problem is in constructing the stream reader.
Probably you are watching the application for output but the debugger(visual studio) has stopped the application on that line, with an exception. eg File not found, No Permission, using a http uri...
If MSGBOX C doesn't show then problem is probably that the file has problems being read.
Permissions?
Does it have a Line of Text?
Is the folder 'online'
If MSGBOX D shows, but nothing happens then you are doing nothing with WholeMap
See what is displayed if you rewite MsgBox("C") to Debug.WriteLine("Read " + WholeMap)
I have a few suggestions. Firstly, use Option Strict On, it will help you to avoid headaches down the road.
The code to open the file is correct. In addition to avoiding using MsgBox() to debug and instead setting breakpoints or using Debug.WriteLine(), wrap the subroutine in a Try...Catch exception.
Private Sub GameMain_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
LoadMap("Map_Cygnus.txt")
End Sub
Private Sub LoadMap(FileLoc As String)
Try
FileLoc = "C:\Users\Adam\Documents\Visual Studio 2013\Projects\G01-Cartography\Maps\" + FileLoc
MsgBox("A")
Using File As New StreamReader(FileLoc)
MsgBox("B")
Dim WholeMap = File.ReadLine() 'dimming a variable inside a block like this means the variable only has scope while inside the block
MsgBox("C")
End Using
MsgBox("D")
Catch ex As Exception
MsgBox(ex.ToString)
End Try
End Sub
Note that you normally should only catch whatever exceptions you expect, but I generally catch everything while debugging things like this.
I would also like to point out that you are only reading one line out of the file into the variable WholeMap. That variable loses scope as soon as the End Using line is hit, thereby losing the line you just read from the file. I'm assuming that you have the code in this way because it seems to be giving you trouble reading from it, but thought I would point it out anyway.
Public Class GameMain
Private WholeMap As String = ""
Private Sub GameMain_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
LoadMap("Map_Cygnus.txt")
End Sub
Private Sub LoadMap(FileLoc As String)
Try
FileLoc = "C:\Users\Adam\Documents\Visual Studio 2013\Projects\G01-Cartography\Maps\" + FileLoc
Using File As New StreamReader(FileLoc)
WholeMap = File.ReadLine() 'dimming the variable above will give all of your subs inside class Form1 access to the contents of it (note that I've removed the Dim command here)
End Using
Catch ex As Exception
MsgBox(ex.ToString)
End Try
End Sub
End Class

How do i link Visual Studio applications over LAN

I have created a VS application , I have installed a copy on another computer and I wish to link them via LAN so that if settings are canged in one , the others setings will also be saved .
for example this setting
i created a new name in the sttings are and call it "AdminIn" and set its type it integer , its scope to user and set its value to 0
Dim AI As New My .MySettings
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
AI.AdminIn = AI.AdminIn + 1
Ai.SAve()
End Sub
now how can AI also be updated in the other application on the other computer .
How do I connect via LAN and accomplish this ?
I found this link that provides some example code to modify application-scoped variables from My.Settings that might be useful. I've tested it out with a simple form with a timer and a label showing me the current value of the AdminIn setting, and it seems to work. The timer updates the label on every instance of the form by checking the reloaded My.Settings value. The variable would need to be application scoped in order to be accessible to all users on any machine that may run the executable.
http://www.codeproject.com/Articles/19211/Changing-application-scoped-settings-at-run-time
Here's the form code that I put together to keep the current admin count up-to-date. Very simplistic, but it seems to do the job neatly.
Public Class Form1
Private Sub Form1_FormClosing(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing
'Decrement the AdminIn count when the current instance of the form is closed.
Me.tmrAdminCheck.Stop()
ChangeMyAppScopedSetting((My.Settings.AdminIn - 1).ToString)
'Reload the .exe.config file to synchronize the current AdminIn count.
My.Settings.Reload()
My.Settings.Save()
End Sub
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
'Increment the current AdminIn count when a new instance of the form is loaded
ChangeMyAppScopedSetting((My.Settings.AdminIn + 1).ToString)
'Reload the .exe.config file to synchronize the current AdminIn count.
My.Settings.Reload()
My.Settings.Save()
Me.lblAdminsIn.Text = "Current Admins In: " & My.Settings.AdminIn.ToString
'Start the timer to periodically check the AdminIn count from My.Settings
Me.tmrAdminCheck.Enabled = True
Me.tmrAdminCheck.Interval = 100
Me.tmrAdminCheck.Start()
Me.Refresh()
Application.DoEvents()
End Sub
Private Sub tmrAdminCheck_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles tmrAdminCheck.Tick
'Reload the .exe.config file to synchronize the current AdminIn count.
My.Settings.Reload()
Me.lblAdminsIn.Text = "Current Admins In: " & My.Settings.AdminIn.ToString
Me.Refresh()
Application.DoEvents()
End Sub
End Class
I've found a couple of things with this method, and they relate to what others have already mentioned in their comments:
The application's .exe.config file must be in an accessible location (the CodeProject example defaults to the application's executable directory). Of course, you could save the settings to an INI file or some other configuration file in another shared directory and accomplish a similar thing, but this method uses the My.Settings.
You'll may want to do some additional checking for the possibility
of two people attempting to get in at exactly the same time. If
that happens, the configuration file will still be open and locked,
and the new AdminIn value won't be saved. The CodeProject example
doesn't have any exception handling, but you could easily work this
functionality into the exception handling by making a recursive call
to the Sub.
Otherwise, this seems to be a totally viable method of accomplishing what you're talking about.

Release file\folder lock when using drag\drop onto control

I'm trying to loop through a list of files to get the path and filename.
These files are dragged onto a datagrid:
Private Sub DataGridView1_DragDrop(ByVal sender As System.Object,
ByVal e As System.Windows.Forms.DragEventArgs) Handles DataGridView1.DragDrop
Dim filenames As String() = DirectCast(e.Data.GetData(DataFormats.FileDrop), String())
For Each File In filenames
If Array.IndexOf(SupportedFormats, System.IO.Path.GetExtension(File)) <> -1 Then
Frm = New FormRestore(ServerName, File)
Frm.Show()
While Frm.Visible
Application.DoEvents()
End While
End If
Next
End Sub
A child form is created that processes an action based on the path and file name.
until the loop is complete, the folder the files were dragged from is locked.
How would I get a list of the path and file names AND process each one without locking out the source folder?
(I'm using the while loop to process the file names sequentially, pausing between each one while maintaining UI response)
Thanks.
Try processing the files after the drag&drop event by calling BeginInvoke in the handler.