Copy File on Modification FIleSystemWatcher, Visual Basic (VS 2012 V11) - vb.net

After looking through many sites and some tutorial videos, I'm still stumped on this one. I'm finishing up a program and I need to add one last bit of functionality.
The program works this way. The user specifies a file in textbox1 and then specifies a directory in textbox2. The user sets how often they want the file to by copied in textbox3. The user hits run and the program copies the file to the new location, adding a number to the file name each time it is copied (to avoid overwrites). That all works fine, but I want the user to have the choice to either copy the file by time or when the file is modified.
How can I use the FileSystemWatcher to look for modification in the directory (given in textbox1) and then call the statement that copies the specified directory to the target destination (specified in textbox 2)?
Additional Note:
In one tutorial the FileSystemWatcher path was set up by doing this
Dim watched As String = System.IO.Path.Combine(Environment.GetEnvironmentVariable("USERPROFILE"), "Pictures")
Dim fsw As New FileSystemWatcher(watched)
The path that the code directs to is "C:\Users[User Name]\Pictures" .
I can't find a resource online that shows what variables ".GetEnvironmentVariable" accepts or even what the variables mean. This is one of many reasons why I am having trouble with this last bit code.

GetEnvironmentVariable returns the value for the specified environment for the current process.
In the case of your example, USERPROFILE is the path to the folder for the current user. For example, on my laptop USERPROFILE is C:\Users\Tim.
The output of System.IO.Path.Combine(Environment.GetEnvironmentVariable("USERPROFILE"), "Pictures") would be the USERPROFILE path plus "Pictures" - to continue with my example, it would be C:\Users\Tim\Pictures - which is the physical path to the My Pictures folder for my user account.
To get a list of all your environment variables, if you're curious, go to the DOS prompt and type in SET and hit return.
To answer your original question, you need to handle the FileSystemWatcher.Changed Event.
For example:
Private Shared Sub OnChanged(source As Object, e As RenamedEventArgs)
' Do your copy here
End Sub
You can hook the event handler up to your FileWatcher like this:
AddHandler fsw.Changed, AddressOf OnChanged
However, pay attention to this warning from the MSDN docs.
Common file system operations might raise more than one event. For example, when a file is moved from one directory to another, several OnChanged and some OnCreated and OnDeleted events might be raised. Moving a file is a complex operation that consists of multiple simple operations, therefore raising multiple events. Likewise, some applications (for example, antivirus software) might cause additional file system events that are detected by FileSystemWatcher.

This is the code I used it does what I want it to.
Option Explicit On
Option Strict On
Imports System.IO
Imports Microsoft.VisualBasic ' I don't know this one, but the code worked without this.
Imports System.Security.Permissions ' I don't know the exactly what this does but the
' http://msdn.microsoft.com/ site did this, I assume it'f to allow for permission to
' watch files? The code still worked for me without this
Public Class Form1
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Me.Load
Dim directoryPath As String = Path.GetDirectoryName(TextBox1.Text)
Dim varFileSystemWatcher As New FileSystemWatcher()
varFileSystemWatcher.Path = directoryPath
varFileSystemWatcher.NotifyFilter = (NotifyFilters.LastWrite)
varFileSystemWatcher.Filter = Path.GetFileName(TextBox1.Text) ' I know this
' limits what's being watched to one file, but right now this is
' what I want the program to do.
AddHandler varFileSystemWatcher.Changed, AddressOf OnChanged
varFileSystemWatcher.EnableRaisingEvents = True
End Sub
Private Sub OnChanged(source As Object, ByVal e As FileSystemEventArgs)
My.Computer.FileSystem.CopyFile(e.FullPath, TextBox2.Text & "\" & e.Name, True)
End Sub

Related

How to save a changed label when you exit

In my program I have a preview, and edit side.
When you edit using the text boxes on the edit side(right side) and click "save", It should change the label on the right side (preview side). Although when you exit the program and re-open, all the data you entered has disappeared!,
I have tried the below code and had no luck as my result.
Public Class Form1
Private Shared NameBasic As Integer
Public Sub New()
InitializeComponent()
lblNameBasic.Text = Convert.ToString(NameBasic)
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
NameBasic = txtFirstBasic.Text
lblNameBasic.Text = Convert.ToString(NameBasic)
End Sub
End Class
Also my goal is to have it be able to take it on a flashdrive onto any computer and have that data still saved within the exe. Is this even manageable? (I am more of a web based programmer so I am a bit new to this)
You need to write values to a text file at the same location of the exe. and read it. you will need both exe and the textfile.
OR
You will need to write a dll on run-time and write some values while closing the application. this will be more secure then the text file. here you will need both exe and dll to be copied into flash drive
OR
the application setting as spoken by others..

VB 2013 Persistent User Settings

On my form I have a menu with "file-save". When I click save I want to save particular settings to restore when the form is closed and re-opened. I've done this successfully for text in text-boxes and the checked states of check-boxes, but I'm failing when trying to loop through the items in a list-box. Please see below for what I've tried...
When I click save:
Private Sub SaveToolStripMenuItem_Click(sender As Object, e As EventArgs)
Handles SaveToolStripMenuItem.Click
For Each i In ListBox1.Items()
My.Settings.ListBox1.Add(i)
Next
My.Settings.Save()
End Sub
When my form loads:
Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs)
Handles Me.Load
For Each i In My.Settings.ListBox1()
ListBox1.Items.Add(i)
Next
End Sub
I've only been using VB for three days, so apologies if I am missing something simple ha! Thanks for any help!!!
There is one small glitch with the StringCollection in settings. If you do not seed it with a fake variable then it starts out as Nothing and you cannot add to Nothing. in your form load add this:
' if the collection has not been initialized, do so
If My.Settings.ListBox1 Is Nothing Then
My.Settings.ListBox1= New System.Collections.Specialized.StringCollection
End If
' now it is safe to use: load strings from Setting -> form listbox
For Each s As String In My.Settings.ListBox1()
ListBox1.Items.Add(s)
Next
The very first time it runs, there are likely no saved settings, so we have to create the container for them, basically.
Option Strict can be implemented by file, by adding this at the top:
Option Strict On
Or for the project: Project => Properties => Compile: Option Strict is likely to the right (I have 2012). You can also set it as a permanent option (recommended).
Among other things, this will prevent you from plucking variables out of the air and use them without declaring a type (which will lead to errors). For instance:
For Each i In My.Settings.ListBox1()
becomes
For Each s As String In My.Settings.ListBox1() ' tell the compiler the Type

vb.net - redirect output to form textbox

I am trying to read/use the output from a python program in my vb.net project so far I'm not getting any results. What I'd like to see is the python program run (just by itself first) and all of the output get redirected into a textbox.
I've looked at some other posts about this, but I'm either missing something or not understanding something, as all I'm getting is blank output.
Public Class Form1
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Dim PythonPath = "C:\Python27\"
Dim strPath As String = Application.StartupPath
MessageBox.Show(PythonPath & "python.exe """ & strPath & "\Resources\import_logs.py"" ")
Dim start_info As New ProcessStartInfo(TextBox1.Text)
' Make the process and set its start information.
Dim process As New Process()
process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden
process.StartInfo.FileName = PythonPath & "\python.exe"
process.StartInfo.Arguments = """" & strPath & "\resources\import_logs.py"""""
process.StartInfo.UseShellExecute = False
process.StartInfo.CreateNoWindow = True
process.StartInfo.RedirectStandardOutput = True
'process.StartInfo.RedirectStandardError = True
AddHandler process.OutputDataReceived, AddressOf proccess_OutputDataReceived
process.Start()
process.BeginOutputReadLine()
End Sub
Public Sub proccess_OutputDataReceived(ByVal sender As Object, ByVal e As DataReceivedEventArgs)
On Error Resume Next
' output will be in string e.Data
' modify TextBox.Text here
'Server_Logs.Text = e.Data ` Does not display anything in textbox
MsgBox(e.Data) 'It works but I want output in text box field
End Sub
End Class
Eventually I'm going to pass arguments to the python script and I'd like to get feedback that I can then use (insert error into a database, email when it's done, etc), so I'd like it to capture the process while running and not just a data dump at the end.
Any help would be much appreciated.
First things first—it's no wonder you aren't sure what's wrong with your code, you're silencing all errors that could possibly help you to diagnose it. That's the only purpose of On Error Resume Next in VB.NET. That unstructured error handling was included only for backwards compatibility with the pre-.NET versions of VB and it's time to forget that it ever existed. You certainly don't want to use it in code. (I would say "in code that you're debugging", but all code is a potential candidate for debugging and ignoring errors is just dumb.)
Anyway, on to the specific problem. We know that the call to MsgBox works, but it doesn't work right when you start interacting with controls on your form. So something is falling apart there.
It turns out that the OutputDataReceived event is raised on an entirely different thread, a different one than was used to create the process and a different one than is running your application's UI. It actually just retrieves a thread from the system thread pool.
And that's where the problem lies: you cannot manipulate UI objects on a thread other than the one that created those objects (at least not without jumping through some hoops), which is precisely what your code tries to do here. In fact, you're probably swallowing an exception that would have rather obtusely informed you of this situation.
The simple fix is to set the SynchronizingObject property of the Process class to one of your UI components (like the form, or the specific control you want to output to). This forces all event handlers to execute on the same thread that created that component. At that point, your code should work fine, because you're not trying to do any cross-thread UI access. (Message boxes are not vulnerable to this because any thread can display a message box. You're not trying to access an existing UI object that is bound to another thread.)
Alternatively, you could handle the marshalling yourself in the event handler method through the use of delegates and the BeginInvoke method, but this seems like unnecessary work to me.

Looping Until A File Exists

Ok, the following codes shows how I am enterting a value into a textbox, adding that value to the listbox, updating a picturebox next to it and blanking out the textbox so the user can add additional values to the listbox.
ListBox1.Items.Add(TextBoxTicketID.Text)
If CStr(ListBox1.Items(0)) = TextBoxTicketID.Text Then
PictureBoxStatus1.Image = My.Resources.Orange_Information
End If
TextBoxTicketID.Text = ""
I have another process not shown here that will create a PDF based on the value that was entered into the listbox.
I'm having trouble with a loop to check a specific directory if the PDF exists or not. When the PDF exists, I'll change the picturebox to another image.
Here is the loop that I was using, but the issue I ran into was that the user couldn't enter a second value unless the first value was present.
Loop Until My.Computer.FileSystem.FileExists("c:\Temp\" + ListBox1.Items(0) + ".pdf")
PictureBoxStatus1.Image = My.Resources.Green_Checkmark
So in theory, I need to be able to enter X amount of values into the listbox and keep checking to see if the file exists and if it does, change those images that needed.
EDIT
Here's what I ended up doing...seems to be working fine though...
ListBox1.Items.Add(TextBoxTicketID.Text)
If CStr(ListBox1.Items(0)) = TextBoxTicketID.Text Then
PictureBoxStatus1.Image = My.Resources.Orange_Information
End If
TextBoxTicketID.Text = ""
Call CheckFiles()
Added a public sub
Public Sub CheckSpooling()
Dim Watcher As New FileSystemWatcher()
Watcher.Path = "C:\Temp\"
Watcher.Filter = ListBox1.Items(0) + ".pdf"
AddHandler Watcher.Created, AddressOf OnChanged
Watcher.EnableRaisingEvents = True
End Sub
Then the sub to run whatever is needed if the file was added. I used a msgbox for testing.
Private Shared Sub OnChanged(source As Object, e As FileSystemEventArgs)
' Specify what is done when a file is created.
MsgBox("File has been created!")
End Sub
Check out the FileSystemWatcher
The reason the user can't enter anything while you are looping is because the WinForm framework is essentially single threaded. Everything in the UI occurs on the same thread, including the event handler. So, if you are sitting in a loop for a long time in a button click event handler, then the UI will be locked up and unresponsive until the code exits the loop. The way to get around this is to start a new thread to perform whatever work needs to be done. That worker thread can take as long as it needs to complete and it won't interfere with the UI thread so the UI remains responsive. This is made easier by the BackgroundWorker component which you can drop onto your forms in the form designer.
However, the FileSystemWatcher, as Dan-o has recommended is probably a better solution than creating your own worker thread that keeps checking if the file exists. Not only does it avoid re-inventing the wheel, but it also will be more efficient. Instead of constantly asking the file system if a file exists, it just listens to messages from the file system to find out when changes occur.

Converting C# to VB.net is not working

I have translated some code from C# to VB.net for the purpose of getting Folder Browser functionality. The link to the code is here.....
http://www.codeproject.com/KB/aspnet/DirectoryBrowsing.aspx
My issue is that I have not been able to correcly translate these two lines of code to VB.net.
TreeView1.TreeNodeExpanded +=new TreeNodeEventHandler(TreeView1_TreeNodeExpanded);
TreeView1.SelectedNodeChanged += new EventHandler(TreeView1_SelectedNodeChanged);
Every translator I have used has simply dropped the semicolon from the end of each line. But the editor still does not like them.
I could some help with this as it seems this effects the refresh of the selected folder in the tree view control.
I don't get to see the C drive folder unless I type the path in the text box, and the folder will still not expand.
thank you,
Use this:
AddHandler TreeView1.TreeNodeExpanded, AddressOf TreeView1_TreeNodeExpanded
AddHandler TreeView1.SelectedNodeChanged, AddressOf TreeView1_SelectedNodeChanged
Edit:
A different way to do this would be to apply it at the method level:
Protected Sub TreeView1_TreeNodeExpanded(ByVal sender as Object, ByVal e as TreeNodeEventArgs) Handles TreeView1.TreeNodeExpanded
' Some code
End Sub
Protected Sub TreeView1_SelectedNodeChanged(ByVal sender as Object, ByVal e as EventArgs) Handles TreeView1.SelectedNodeChanged
' Some code
End Sub
You should run this in debug to find out what exactly is going on. I find a lot of times when events of this nature are run in asp.net, you have a conflicting event that "resets" the controls you are attempting to change.