Transfering a textbox value to an EventHandler Process

Keags

New member
Joined
Dec 8, 2011
Messages
4
Programming Experience
Beginner
Good day,

I am a complete newbie to VB.NET and have been plugging around with a few ideas for a tool.

I am using Visual Studio express 2008 to load a form, perform a task at a given interval.
My problem is:

1) I am able to populate a textbox with the desired text (a pathname);
2) I can get the timer event to work perfectly;
3) The problem arises when the timer conditions are met and I need to perform a task based on the value of the text box.
4) The value from the textbox becomes lost and when i hold my mouse cursor over the textbox:


I get an error:
"An exception 'Microsoft.VisualStudio.Debugger.Runtime.CrossThreadMessagingException' occurred"
and it is tracked to:
StackTrace = " at Microsoft.VisualStudio.Debugger.Runtime.Main.ThrowCrossThreadMessageException(String formatString) at System.Windows.Forms.SafeNativeMethods.GetWindowTextLength(HandleRef hWnd) at System.Windows.Forms.Control.get_WindowText() at System.Windo...

The script doesnt stop it just keeps running but doesnt do anything.
Being VERY unfamiliar with this type of work
I am stumped.

Any help / advice will be greatly appreciated!
On a side note, the script runs perfectly when i hard code in the pathname, but this doesnt suit the work i would like this script to do.

Thank you!
 
It is hard to figure it out without the code, but it seems the problem is related to the place where the timer is instantiated, and its event is handled, whether from your form or your timer, for they might be running in different threads. Perhaps if you try to create a new timer inside your form's class (ie Private WithEvents MyTimer as Timer on Form's declarations, and MyTimer = New Timer etc. on your routine when you want to start it up) and an event handler sub for the tick also in your form's class, the you might avoid these threading issues. Hope it helps. Kind regards!
 
Hi,

Thank you for your response.
I was able to get a solution to my problem.
I am not sure if it was the right way but basically, instead of having the button_click call the module with the timer, I kept the timer and all the related processes within the form itself.
I did have one or two issues but fumbled my way through it.

I think that is what you have posted above :)

Thanks again for taking the time to respond, was sure this thread was dead.

Cheers,
K
 
You're obviously doing something involving multiple threads, whether intentional or not. If I had to guess I would say that you were using a Timers.Timer, which raises its Elapsed event on a secondary thread, and trying to access the TextBox from the Elapsed event handler. That's just a guess though. If, as VBobCat suggests, you were to show us the relevant code, then we might be able to help you write better code.
 
Hi,
Below please find the code which sits in the form:

Public Class frmTest1
<STAThread()> _
Public Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

If CheckBox1.Checked = True Then
Dim saveFile As New System.Windows.Forms.SaveFileDialog
Dim txtArcmap As String
Dim spath As String
saveFile.Title = "Save As"
''''Save file dialog
saveFile.DefaultExt = "mxd"
saveFile.Filter = "ArcMap Document (*.mxd)|*.mxd"
saveFile.OverwritePrompt = True
saveFile.ShowDialog()
txtArcmap = saveFile.FileName
TextBox1.Text = txtArcmap
Me.Hide()



TextBox1.Update()


Dim Timer As New System.Timers.Timer
Timer = New System.Timers.Timer(30000)
Timer.Start()


spath = TextBox1.Text
Timer = New System.Timers.Timer(30000)
AddHandler Timer.Elapsed, New Timers.ElapsedEventHandler(AddressOf handler)
Timer.Enabled = True

''''If the user presses cancel, exit out
If saveFile.FileName = "" Then
Exit Sub
End If

ElseIf CheckBox2.Checked = True Then
Me.Close()
Exit Sub
End If

End Sub

Public Function handler(ByVal sender As Object, ByVal e As Timers.ElapsedEventArgs)

Dim sPath As String

sPath = TextBox1.Text
Dim editorUID As ESRI.ArcGIS.esriSystem.UID
editorUID = New ESRI.ArcGIS.esriSystem.UID
editorUID.Value = "esriEditor.Editor"
Dim editor As IEditor

editor = My.ArcMap.Application.FindExtensionByCLSID(editorUID)
If editor.EditState = esriEditState.esriStateNotEditing Then

My.ArcMap.Application.SaveDocument(sPath)
ElseIf editor.EditState = esriEditState.esriStateEditing Then
End If
End Function

Public Sub CheckBox1_CheckedChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles CheckBox1.CheckedChanged
CheckBox1.Checked = True
CheckBox2.Checked = False
End Sub

Public Sub CheckBox2_CheckedChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles CheckBox2.CheckedChanged
CheckBox1.Checked = False
CheckBox2.Checked = True
End Sub
End Class


Basically it is a form, with two checkboxes, where the user chooses if they want to run the process or not.

Before, I changed the code, I had a "Module1.Save" in the Checkbox1 part of the script, this then called the Timer and was where I was trying to get the timer and process to to run.

This code now works, not sure if it is the cleanest, but...it was my first attempt at designing a solution to fit my needs.
Any crits / comments are welome!

thanks
K
 
First up, your CheckedChanged event handlers don't make sense. Why are you setting CheckedBox1.Checked to True in the CheckedChanged event handler of CheckBox1. For that event to be raised, the Checked property must have just changed. If it has just changed to True then obviously setting it to True is pointless, while if it has just changed to False then setting it to True is undesirable. It looks to me like you want to have just one of two CheckBoxes checked at a time. That's exactly what RadioButtons are for, so you should almost certainly be using them instead. Then you need no code at all.

As for the issue, it appears to be as a I suggested. You are using a Timers.Timer and handling its Elapsed event, which is raised in a secondary thread by default. You should almost certainly be using a Windows.Forms.Timer, which raises its Tick event on the UI thread, allowing you to access controls directly.

Also, do you really want to create a new Timer every time the user clicks that Button?
 
Awesome!
Thanks!

The reasoning (in my mind) for using the CheckBox1 and 2 true and false was to ensure that one couldnt have the both check boxes active at the same time.
I see what you mean wrt to the pointlessness of having it set to true when clicking it would make it true to start off with.

I think I understand the second thread issue, I will test it again using the windows.Forms.Timer and see if that fixes the threading issues.

Thanks!

WRT to the new timer, I do need the timer to be restarted.

Essentially what happens is this form is called by a button click which operates like a toggle.
While the document is open it saves every 30 seconds, however, if the document is changed (through opening a new document from within this document) then the saving function is killed and will need to be turned on again (hence the new timer)...I think that makes sense :)

Anyways thanks for your insight, it is always good to get someone to look at your work, as I said I am teaching myself and getting the opinion of someone who is experienced helps me understand where I may not be doing things as efficiently as they can be done.

Thanks again!
K
 
Yes, I think when you kept the timer and all the related processes within the form itself, you kept everything together in a single thread.
I'm aware VB.NET allows mutithreading and that involves the use of "Invoke" command, but I have not learned how to manage this yet. So what I told you was the very way I myself avoided errors in my own projects. I hope to learn more abot multithreading in the future. Kind regards!
 
If you need to restart the Timer then just restart the Timer, don't create a new one. If you only ever have one Timer running at a time then yu only need one Timer. You can add it to your form in the designer and create a Tick event handler just as you would crreate a Click event handler for a Button. You then just call Start and Stop on that Timer or set the Enabled property.
 
Back
Top