|
Greatings !!! I have a simple (I think) problem.
I need a thread that executes some part of a code and
during that time i want to suspent or pause the main application thread.
This way the application do not appear (Not Responding) or is the same? Do you have another solution?
How can i do this?
Sorry for my English !!!
thanks.
Bruno Conde.
|
|
|
|
|
Arg, please don't abuse threading like this.
If you want to execute something in another thread yet suspend the main thread why bother seperating the two things into two threads?? You are not gaining anything using threading like this. Just do all of the work in the single main thread.
|
|
|
|
|
In most cases I would totally agree with you.
There are cases, however, when you may want to execute something in another thread and eventually have your application block until it's finished. This is quite possible with the asynchronous pattern, when you first call Begin* , do something else, then block on End* . I would add, however, that's more common to use an AsyncCallback so that you don't have to block, but you could.
An example might be downloading a file via HttpWebRequest.BeginGetResponse . You could update the UI and then call HttpWebREquest.EndGetResponse to block until the HttpWebResponse is returned.
I'm not disagreeing that - if the original poster needs no functionality like what I descrbied - it is an abuse of threads. There may be a purpose, however (of which we would know since the original post mentioned nothing of this sort).
This posting is provided "AS IS" with no warranties, and confers no rights.
Software Design Engineer
Developer Division Sustained Engineering
Microsoft
[My Articles] [My Blog]
|
|
|
|
|
Agreed, there are cases where you really need to use multi-threaded behavior and the example is a perfect example (begin/end process pipelines are classic MT fodder). Without more information however it sounds like the described problem can be fixed simply by avoiding MT all together.
Sometimes the vague nature of the questions makes me suspicious which is why I asked the question. If they can come up with the answer on why their app relies on MT behavior that requires going against MT behavior then we can actually go forward and get a better solution than vaguely throwing code around.
|
|
|
|
|
And I completely agree with you. I added a response to yours mainly for the original poster's benefit, since he/she might have a valid reason that falls under the scenario I mentioned.
Turns out, though, that he/she is using Control.Invoke , apparently thinking that it will invoke the method on a different thread. Further proof that reading documentation is always beneficial.
This posting is provided "AS IS" with no warranties, and confers no rights.
Software Design Engineer
Developer Division Sustained Engineering
Microsoft
[My Articles] [My Blog]
|
|
|
|
|
There's a couple ways of doing that. You can use Thread.Join in your main application thread. You would do something like this:
Thread t = new Thread(new ThreadStart(SomeMethod));
t.Start();
t.Join() Now your main application thread (or in whichever thread you called Join will block until the thread terminates.
Another way is through asynchronous processing and gives you added functionality, like callbacks. Many objects define asynchronous methods already (the Begin* and End* method pairs), but you execute any method (including property getters and setters, which are just methods) asynchronously like so:
using System;
using System.Threading;
delegate void VoidCallback();
class Test
{
static void Main()
{
Test t = new Test();
VoidCallback callback = new VoidCallback(t.DoSomething);
IAsyncResult result = callback.BeginInvoke(null, null);
Thread.Sleep(1000);
Console.WriteLine("Still in Main() on main thread");
callback.EndInvoke(result);
Console.WriteLine("Done");
}
void DoSomething()
{
Console.WriteLine("Waiting for 3 seconds in new thread...");
Thread.Sleep(3000);
}
} While this is possible, however, an application should never appear hung (which is what you're doing). If you don't want the user to be able to interact with the application while still allowing the control thread (the thread on which the controls were created) to paint the controls (so the application doesn't appear hung), then simply set the wait cursor by doing Cursor.Current = Cursors.WaitCursor; . You can do this for a particular control (including the form, which extends Control ) by setting Control.Cursor or for the entire application by using Cursor.Current . Be sure to restore the original cursor, however, or the user won't be able to interact (i.e., give intput) with your application.
For example:
Cursor orig = Cursor.Current;
try
{
Cursor.Current = Cursors.WaitCursor;
}
finall
{
Cursor.Current = orig;
}
This posting is provided "AS IS" with no warranties, and confers no rights.
Software Design Engineer
Developer Division Sustained Engineering
Microsoft
[My Articles] [My Blog]
|
|
|
|
|
When I set Cursor.Current to the WaitCursor then start a thread to do a long process the Cursor doesn't remain as the WaitCursor it almost immediately changes back to the default cursor.
My long process fires an event to say it has started and I handle that on the GUI thread (yes I am using invoke required and delegates) - this sets the Cursor.Current to the WaitCursor then when the long process has completed it fires another event which is handled on the GUI thread which sets the Cursor.Current to the default cursor. I would like the Cursor to remain as the WaitCursor until the long process has completed but no amount of jiggery pokery seems to enable me to do that - I have had to resort to disabling huge amounts of the GUI so the user can't mess up - a WaitCursor would be nice but it just isn't happening.
I know the following is in VB but I haven't had much joy on the VB forum.
The long running process fires off an event every 1000 records or so which is handled on the GU thread thus:
Private Delegate Sub xxxDelegate(ByVal sender As Object, ByVal e As xxxEventArgs)<br />
<br />
Private Sub xxx(ByVal sender As Object, ByVal e As xxxEventArgs) Handles LongProcess.xxx<br />
<br />
If button.InvokeRequired = False Then<br />
Console.WriteLine("A - " & Cursor.Current.ToString())<br />
...<br />
Else<br />
Console.WriteLine("B - " & Cursor.Current.ToString())<br />
Dim del As New xxxDelegate(AddressOf xxx)<br />
Me.BeginInvoke(del, New Object() {sender, e})<br />
End If<br />
End Sub
When run the following is written to the console:
B - [Cursor: WaitCursor]
A - [Cursor: Default]
B - [Cursor: WaitCursor]
A - [Cursor: Default]
B - [Cursor: WaitCursor]
A - [Cursor: Default]
|
|
|
|
|
You wouldn't be calling Application.DoEvents would you? If not, you might run your application through a profiler (available from MSDN[^] even) to see if it's getting called automatically be something else.
From the .NET Framework SDK for the Cursor.Current property:Note If you call Application.DoEvents before resetting the Current property back to the Cursors.Default cursor, the application will resume listening for mouse events and will resume displaying the appropriate Cursor for each control in the application.
This posting is provided "AS IS" with no warranties, and confers no rights.
Software Design Engineer
Developer Division Sustained Engineering
Microsoft
[My Articles] [My Blog]
|
|
|
|
|
The app does call DoEvents but not anywhere touched by the long process - I usually call DoEvents after closing down a Dialog. I have run it under a profiler and DoEvents doesn't come into it.
I am kicking off the long process using BeginInvoke - if that helps.
|
|
|
|
|
Where do you actually set Cursor.Current ? Can you show me the rest of the code minus your application-specific implementation?
This posting is provided "AS IS" with no warranties, and confers no rights.
Software Design Engineer
Developer Division Sustained Engineering
Microsoft
[My Articles] [My Blog]
|
|
|
|
|
Hope this makes sense
Private Delegate Sub RunCrosstabDelegate(ByVal rowVar As String, ByVal colVar As String, ByVal thirdVar As String)
Private Sub RunCrosstab()
Dim crosstab As New RunCrosstabDelegate(AddressOf _Counter.RunCrossTab)
crosstab.BeginInvoke(LkCrossTab1.RowVariable, LkCrossTab1.ColVariable, LkCrossTab1.ThirdVariable, Nothing, Nothing)
End Sub
Private Sub _Counter_CrossTabStart(ByVal sender As Object, ByVal e As EventArgs) Handles _Counter.CrossTabStart
If LkCrossTab1.InvokeRequired = False Then
Cursor.Current = System.Windows.Forms.Cursors.WaitCursor
Else
Dim del As New CrossTabStartDelegate(AddressOf _Counter_CrossTabStart)
Me.BeginInvoke(del, New Object() {sender, e})
End If
End Sub
Private Delegate Sub CrossTabFinishedDelegate(ByVal sender As Object, ByVal e As EventArgs)
Private Sub _Counter_CrossTabFinished(ByVal sender As Object, ByVal e As EventArgs) Handles _Counter.CrossTabFinished
If LkCrossTab1.InvokeRequired = False Then
Cursor.Current = System.Windows.Forms.Cursors.Default
'
Else
Dim del As New CrossTabFinishedDelegate(AddressOf _Counter_CrossTabFinished)
Me.BeginInvoke(del, New Object() {sender, e})
End If
End Sub
|
|
|
|
|
In your previous post you made it sounds like there was also an event that fired intermitently while the long process was running. Is that true? If so, do you set the wait cursor at all in that loop?
When you profiled your application, no Application.DoEvents ran at all while processing the crosstab? From the code above I don't see a problem. It would seem another thread is either setting the cursor or dispatching queued messages (in the application pump). Since you're running asynchronously, this is entirely possible and most likely the case.
Try running this synchronously and you should find that it works because the application (or dialog) message pump is run (which Application.DoEvents forces). If that does work, I'm really not sure what to do to work around it, since this is expected behavior.
One thing you could try is setting a Control 's Cursor property instead of the application's. Hopefully that will "stick".
This posting is provided "AS IS" with no warranties, and confers no rights.
Software Design Engineer
Developer Division Sustained Engineering
Microsoft
[My Articles] [My Blog]
|
|
|
|
|
DoEvents isn't called at all during the processing. The WaitCursor just won't stick - I have tried setting the cursor on every single control to the WaitCursor - which kind of works although it doesn't stop mouseinput - the user can still click on things, drag stuff around, press buttons etc. So the WaitCursor doesn't seem to do much - is that what is supposed to happen? Is there a way to disable mouseinput without disabling every single control?
|
|
|
|
|
What are you using to profile the execution of your application? On other thing you might try is to override OnCursorChanged and set a breakpoint to see if anything else is setting it. Note that this event handler is not called if a native call changes it.
You could set Form.KeyPreview on the container form and disable keys effectively, but to disable mouse events for all child controls you'll need override WndProc on the form and handle the WM_PARENTNOTIFY (0x0210) message, where the low order (second half) of the Message.LParam is set to WM_LBUTTONDOWN (0x0201) or WM_RBUTTONDOWN (0x0204), and conditionally handle the message (allow it to be processed by calling base.WndProc(ref Message) ). Your code must be fully trusted to override WndProc .
This posting is provided "AS IS" with no warranties, and confers no rights.
Software Design Engineer
Developer Division Sustained Engineering
Microsoft
[My Articles] [My Blog]
|
|
|
|
|
use <threadobject>.Join()
this way this thread (whose instance is mentioned above) would wait for all child threads to "die" first before proceeding.
|
|
|
|
|
Thanks for the tip. If after i create the thread t and then do t.Join() the application don't stay "Not Responding" but it stays stopped until the thread t stopps. I think that the application stay's in "Not Responding" because in ApplicationTick1() i refer a recursive method. This method takes a while to do it's job and in that while the application stays "Not Responding". Here is a sample of the code in ApplicationTick1:
// preenche a arvore
MyDelegate d = new MyDelegate(LDAPLibrary.Class1.FillTreeView);
this.Invoke(d,new object[] {conn,tv.Nodes,p2,true});
|
|
|
|
|
That won't start a new thread. Control.Invoke actually executes the method on the thread on which the control was created. That's useful when you're doing something in a different thread and need to update the UI. As I said in my reply, you must always update the UI on the thread on which the control was created. That's why the Control class implements ISynchronizeInvoke .
This posting is provided "AS IS" with no warranties, and confers no rights.
Software Design Engineer
Developer Division Sustained Engineering
Microsoft
[My Articles] [My Blog]
|
|
|
|
|
I want to implement a telephone answering machine. Have searched for the resources but all of them are for MFC. Can anyone who have done it in C# help me in this regard ?
|
|
|
|
|
TAPI and C# don't play well together, you have to do a lot of P/Invoke and Interop work. My prefered solution is to build a COM wrapper in C++ for the telephony functionality and then use it via COM interop in C#.
However Helen Warn has produced this C# wrapper[^] that will get you started.
Michael
CP Blog [^]
|
|
|
|
|
You beat me to it
Paul Watson wrote:
"At the end of the day it is what you produce that counts, not how many doctorates you have on the wall."
George Carlin wrote:
"Don't sweat the petty things, and don't pet the sweaty things."
Jörgen Sigvardsson wrote:
If the physicists find a universal theory describing the laws of universe, I'm sure the a**hole constant will be an integral part of that theory.
|
|
|
|
|
Try here:
http://www.gotdotnet.com/community/usersamples/Default.aspx?query=Tapi[^]
Paul Watson wrote:
"At the end of the day it is what you produce that counts, not how many doctorates you have on the wall."
George Carlin wrote:
"Don't sweat the petty things, and don't pet the sweaty things."
Jörgen Sigvardsson wrote:
If the physicists find a universal theory describing the laws of universe, I'm sure the a**hole constant will be an integral part of that theory.
|
|
|
|
|
thanks for the help
|
|
|
|
|
I have a typical many-to-many relationship between three tables; Apps, AppsToReports, Reports. I am finding it hard to figure how to add DataRelation objects to a DataSet to cover the relationship between Apps and Reports. I saw the DataRelation constructor .add(rel. name, parent table name, child table name, parent columns[], child columns[], bool nested) but can not find any examples of its use or if it would solve my need. As you might assume, I am trying NOT to write large amounts of code. All DataRelation objects I create must have the parent as a unique value which is not true in a many-to-many relationship from the center table to its details. If I must code around this issue then I must but am hoping for a more simplistic solution. Any help would be appreciated.
Bill
|
|
|
|
|
Have you checked out the documentation at MSDN[^]? It shows a quick example on how to do this. For reference, check out this article on CP that talks about Data binding for many-to-many.[^]
~Javier Lozano
(blog)
|
|
|
|
|
Let me first preface this question with a disclaimer. I've never used regular expressions before so I am admittedly clueless!
I'm trying to validate the entry of a TextBox using regular expressions. The entered value should only pass the validation if it contains contiguous alpha characters. The code below breaks if something like "ABC 1" is entered. Any occurance of a space in the string seems be ignored...
Regex re = new Regex(@"[a-z|A-Z]");
return re.IsMatch(TextBox1.Text.ToString(), 0);
What can I add to the pattern to test for the occurence of a " " within the string that will cause the validation to fail?
p.s. Is there a Regular Expressions for Dummies book?
Paul Lyons, CCPL Certified Code Project Lurker
|
|
|
|