Can you raise an event that doesn't block? | | |
I understand that you would normally want to raise an event on the same
thread so that your code blocks until the event has been dealt with...
however i've run into a situation where I have a thread running that
isn't my form thread and I want it to raise a custom event and continue
going without waiting for that event to be handled...
Is this at all possible? | | | | re: Can you raise an event that doesn't block?
Benny,
Sure. Just use the BeginInvoke method on the event, which will spawn off a
thread pool thread to service this call, and your thread will go on its
marry way. Just remember that if there are more than one items in the
invocation list inside of the event (see GetInvocationList of the event)
that you have to iterate through them all and call BeginInvoke on each.
Dave
"Benny Raymond" <benny@pocketrocks.com> wrote in message
news:%23gOvgNx7FHA.4076@tk2msftngp13.phx.gbl...[color=blue]
>I understand that you would normally want to raise an event on the same
>thread so that your code blocks until the event has been dealt with...
>however i've run into a situation where I have a thread running that isn't
>my form thread and I want it to raise a custom event and continue going
>without waiting for that event to be handled...
>
> Is this at all possible?[/color] | | | | re: Can you raise an event that doesn't block?
It seems to be working - but since I don't understand it that much I'd
like for you to look at the code and let me know I did it right... thanks!
// My event thing
#region Delegates and Event Declarations > MessageReceived Event
public delegate void MessageReceivedEventHandler( ServerMessage sMsg );
public event MessageReceivedEventHandler MessageReceived;
private void OnMessageReceived( ServerMessage sMsg )
{
if ( MessageReceived != null )
{
IEnumerator myEnum = MessageReceived.GetInvocationList().GetEnumerator( );
while ( myEnum.MoveNext() )
{
( (MessageReceivedEventHandler) myEnum.Current ).BeginInvoke(sMsg, null,
null);
}
}
}
#endregion
// Inside the thread that loops round and round,
// if a message is recieved in this loop, it runs this line:
OnMessageReceived( message );
D. Yates wrote:[color=blue]
> Benny,
>
> Sure. Just use the BeginInvoke method on the event, which will spawn off a
> thread pool thread to service this call, and your thread will go on its
> marry way. Just remember that if there are more than one items in the
> invocation list inside of the event (see GetInvocationList of the event)
> that you have to iterate through them all and call BeginInvoke on each.
>
> Dave
>
> "Benny Raymond" <benny@pocketrocks.com> wrote in message
> news:%23gOvgNx7FHA.4076@tk2msftngp13.phx.gbl...
>[color=green]
>>I understand that you would normally want to raise an event on the same
>>thread so that your code blocks until the event has been dealt with...
>>however i've run into a situation where I have a thread running that isn't
>>my form thread and I want it to raise a custom event and continue going
>>without waiting for that event to be handled...
>>
>>Is this at all possible?[/color]
>
>
>[/color] | | | | re: Can you raise an event that doesn't block?
>Just remember that if there are more than one items in the[color=blue]
>invocation list inside of the event (see GetInvocationList of the event)
>that you have to iterate through them all and call BeginInvoke on each.[/color]
I think you don't need that unless you want _each_ registered handler
to be run on its own thread. Normally, calling BeginInvoke on the event
is adequate, and all the registered handlers will be invoked
sequecially on a same separate thread.
Thi | | | | re: Can you raise an event that doesn't block?
Sequencially is fine... but now i run into another problem...
inside of the function that gets fired in the main form when the said
event takes place, I have the following line:
if (this.txt_log.Text.Length > 1024*60)
it's checking to see if the text in a rich text box is larger than 60k.
After the event is fired a bunch of times really fast, the program
crashes here and returns just after the
System.Windows.Forms.Application.Run(new frmMain());
inside Main saying that an Object Refrence not set to an instance of an
object... I had to step through my code to find out where it was
crashing... and when I mouse over .Length while stepping through Visual
Studio freezes up for a good 10 seconds and then displays no information
about .Length
Any idea what would be causing this?
Truong Hong Thi wrote:[color=blue][color=green]
>>Just remember that if there are more than one items in the
>>invocation list inside of the event (see GetInvocationList of the event)
>>that you have to iterate through them all and call BeginInvoke on each.[/color]
>
> I think you don't need that unless you want _each_ registered handler
> to be run on its own thread. Normally, calling BeginInvoke on the event
> is adequate, and all the registered handlers will be invoked
> sequecially on a same separate thread.
>
> Thi
>[/color] | | | | re: Can you raise an event that doesn't block?
Here's the full stack trace:
Unhandled Exception: System.NullReferenceException: Object reference not
set to an instance of an object.
at System.Windows.Forms.RichTextBox.EditStreamProc(In tPtr dwCookie,
IntPtr buf, Int32 cb, Int32& transferred)
at System.Windows.Forms.UnsafeNativeMethods.CallWindo wProc(IntPtr
wndProc, IntPtr hWnd, Int32 msg, IntPtr wParam, IntPtr lParam)
at System.Windows.Forms.NativeWindow.DefWndProc(Messa ge& m)
at System.Windows.Forms.Control.DefWndProc(Message& m)
at System.Windows.Forms.Control.WndProc(Message& m)
at System.Windows.Forms.TextBoxBase.WndProc(Message& m)
at System.Windows.Forms.RichTextBox.WndProc(Message& m)
at System.Windows.Forms.ControlNativeWindow.OnMessage (Message& m)
at System.Windows.Forms.ControlNativeWindow.WndProc(M essage& m)
at System.Windows.Forms.NativeWindow.DebuggableCallba ck(IntPtr hWnd,
Int32 msg, IntPtr wparam, IntPtr lparam)
at System.Windows.Forms.UnsafeNativeMethods.PeekMessa ge(MSG& msg,
HandleRef hwnd, Int32 msgMin, Int32 msgMax, Int32 remove)
at SystThe program '[3208] TKSAdmin.exe' has exited with code 0 (0x0).
em.Windows.Forms.ComponentManager.System.Windows.F orms.UnsafeNativeMethods+IMsoComponentManager.FPus hMessageLoop(Int32
dwComponentID, Int32 reason, Int32 pvLoopData)
at System.Windows.Forms.ThreadContext.RunMessageLoopI nner(Int32
reason, ApplicationContext context)
at System.Windows.Forms.ThreadContext.RunMessageLoop( Int32 reason,
ApplicationContext context)
at System.Windows.Forms.Application.Run(Form mainForm)
at TKSAdmin.Globals.Main()
Benny Raymond wrote:[color=blue]
> Sequencially is fine... but now i run into another problem...
>
> inside of the function that gets fired in the main form when the said
> event takes place, I have the following line:
> if (this.txt_log.Text.Length > 1024*60)
>
> it's checking to see if the text in a rich text box is larger than 60k.
> After the event is fired a bunch of times really fast, the program
> crashes here and returns just after the
> System.Windows.Forms.Application.Run(new frmMain());
> inside Main saying that an Object Refrence not set to an instance of an
> object... I had to step through my code to find out where it was
> crashing... and when I mouse over .Length while stepping through Visual
> Studio freezes up for a good 10 seconds and then displays no information
> about .Length
>
> Any idea what would be causing this?
>
> Truong Hong Thi wrote:
>[color=green][color=darkred]
>>> Just remember that if there are more than one items in the
>>> invocation list inside of the event (see GetInvocationList of the event)
>>> that you have to iterate through them all and call BeginInvoke on each.[/color]
>>
>>
>> I think you don't need that unless you want _each_ registered handler
>> to be run on its own thread. Normally, calling BeginInvoke on the event
>> is adequate, and all the registered handlers will be invoked
>> sequecially on a same separate thread.
>>
>> Thi
>>[/color][/color] | | | | re: Can you raise an event that doesn't block?
Looks like it has something to do with modifying the text box in more
than one thread... i put this at the top which stoped the crash except
for when I click in the box while a line up updates is waiting to
happen.... am i doomed?:
private bool processMessage = false;
private void _client_MessageReceived(TaskulonServerCom.ServerMe ssage sMsg)
{
while (processMessage)
{
System.Threading.Thread.Sleep(1);
}
processMessage = true;
// bunch of code to do stuff with the text box
processMessage = false;
}
Benny Raymond wrote:[color=blue]
> Here's the full stack trace:
>
> Unhandled Exception: System.NullReferenceException: Object reference not
> set to an instance of an object.
> at System.Windows.Forms.RichTextBox.EditStreamProc(In tPtr dwCookie,
> IntPtr buf, Int32 cb, Int32& transferred)
> at System.Windows.Forms.UnsafeNativeMethods.CallWindo wProc(IntPtr
> wndProc, IntPtr hWnd, Int32 msg, IntPtr wParam, IntPtr lParam)
> at System.Windows.Forms.NativeWindow.DefWndProc(Messa ge& m)
> at System.Windows.Forms.Control.DefWndProc(Message& m)
> at System.Windows.Forms.Control.WndProc(Message& m)
> at System.Windows.Forms.TextBoxBase.WndProc(Message& m)
> at System.Windows.Forms.RichTextBox.WndProc(Message& m)
> at System.Windows.Forms.ControlNativeWindow.OnMessage (Message& m)
> at System.Windows.Forms.ControlNativeWindow.WndProc(M essage& m)
> at System.Windows.Forms.NativeWindow.DebuggableCallba ck(IntPtr hWnd,
> Int32 msg, IntPtr wparam, IntPtr lparam)
> at System.Windows.Forms.UnsafeNativeMethods.PeekMessa ge(MSG& msg,
> HandleRef hwnd, Int32 msgMin, Int32 msgMax, Int32 remove)
> at SystThe program '[3208] TKSAdmin.exe' has exited with code 0 (0x0).
> em.Windows.Forms.ComponentManager.System.Windows.F orms.UnsafeNativeMethods+IMsoComponentManager.FPus hMessageLoop(Int32
> dwComponentID, Int32 reason, Int32 pvLoopData)
> at System.Windows.Forms.ThreadContext.RunMessageLoopI nner(Int32
> reason, ApplicationContext context)
> at System.Windows.Forms.ThreadContext.RunMessageLoop( Int32 reason,
> ApplicationContext context)
> at System.Windows.Forms.Application.Run(Form mainForm)
> at TKSAdmin.Globals.Main()
>
> Benny Raymond wrote:
>[color=green]
>> Sequencially is fine... but now i run into another problem...
>>
>> inside of the function that gets fired in the main form when the said
>> event takes place, I have the following line:
>> if (this.txt_log.Text.Length > 1024*60)
>>
>> it's checking to see if the text in a rich text box is larger than
>> 60k. After the event is fired a bunch of times really fast, the
>> program crashes here and returns just after the
>> System.Windows.Forms.Application.Run(new frmMain());
>> inside Main saying that an Object Refrence not set to an instance of
>> an object... I had to step through my code to find out where it was
>> crashing... and when I mouse over .Length while stepping through
>> Visual Studio freezes up for a good 10 seconds and then displays no
>> information about .Length
>>
>> Any idea what would be causing this?
>>
>> Truong Hong Thi wrote:
>>[color=darkred]
>>>> Just remember that if there are more than one items in the
>>>> invocation list inside of the event (see GetInvocationList of the
>>>> event)
>>>> that you have to iterate through them all and call BeginInvoke on each.
>>>
>>>
>>>
>>> I think you don't need that unless you want _each_ registered handler
>>> to be run on its own thread. Normally, calling BeginInvoke on the event
>>> is adequate, and all the registered handlers will be invoked
>>> sequecially on a same separate thread.
>>>
>>> Thi
>>>[/color][/color][/color] | | | | re: Can you raise an event that doesn't block?
>Looks like it has something to do with modifying the text box in more[color=blue]
>than one thread[/color]
Yes, might be so. When you update Windows Form UI from other thread,
you need to use Control.Invoke or Control.BeginInvoke to marshall the
call to the thread that created the control. That limitation is due to
STA model of windows system.
I post a sample, note that I did not test it yet, just want to give the
idea.
private int GetTextLength(Control ctrl)
{
if (!ctrl.InvokedRequired)
{
return ctrl.Text.Length;
}
else
{
return (int) ctrl.Invoke(new TextLengthDelegate(GetTextLength),
new object[] {ctrl});
}
} | | | | re: Can you raise an event that doesn't block?
Oh, and you need to declare TextLengthDelegate also:
public delegate int TextLengthDelegate(Control ctrol);
Hope it helps,
Thi | | | | re: Can you raise an event that doesn't block?
I was doing a lot more than just testing textlength... I ended up trying
this line inside of my triggered event instead:
this.txt_log.Invoke( ProcessMessage, new object[] { sMsg } );
Where ProcessMessage was another event, and this line forces the message
to be run on the txt_log thread, making everything ok :)
Thank you both for your help in pointing me in the right direction!
Truong Hong Thi wrote:[color=blue]
> Oh, and you need to declare TextLengthDelegate also:
> public delegate int TextLengthDelegate(Control ctrol);
>
> Hope it helps,
> Thi
>[/color] | | | | re: Can you raise an event that doesn't block?
D. Yates wrote:[color=blue]
> Benny,
>
> Sure. Just use the BeginInvoke method on the event, which will spawn
> off a thread pool thread to service this call, and your thread will
> go on its marry way. Just remember that if there are more than one
> items in the invocation list inside of the event (see
> GetInvocationList of the event) that you have to iterate through them
> all and call BeginInvoke on each.[/color]
Yes, but the documentation does say that you should call EndInvoke at
some point (to do clean up), which means that it is not entirely
fire-and-forget. To have fire-and-forget you must add [OneWay] to the
method that is called through the delegate.
Richard
-- http://www.grimes.demon.co.uk/workshops/fusionWS.htm http://www.grimes.demon.co.uk/workshops/securityWS.htm | | | | re: Can you raise an event that doesn't block?
So where should the [OneWay] go? Here's my delegate/event:
#region Delegates and Event Declarations > MessageReceived Event
public delegate void MessageReceivedEventHandler(ServerMessage sMsg);
public event MessageReceivedEventHandler MessageReceived;
// [OneWay] goes here?
private void OnMessageReceived(ServerMessage sMsg)
{
if (MessageReceived != null)
{
MessageReceived.BeginInvoke(sMsg, null, null);
}
}
#endregion
Richard Grimes wrote:[color=blue]
> D. Yates wrote:
>[color=green]
>>Benny,
>>
>>Sure. Just use the BeginInvoke method on the event, which will spawn
>>off a thread pool thread to service this call, and your thread will
>>go on its marry way. Just remember that if there are more than one
>>items in the invocation list inside of the event (see
>>GetInvocationList of the event) that you have to iterate through them
>>all and call BeginInvoke on each.[/color]
>
>
> Yes, but the documentation does say that you should call EndInvoke at
> some point (to do clean up), which means that it is not entirely
> fire-and-forget. To have fire-and-forget you must add [OneWay] to the
> method that is called through the delegate.
>
> Richard[/color] | | | | re: Can you raise an event that doesn't block?
Benny Raymond wrote:[color=blue]
> So where should the [OneWay] go? Here's my delegate/event:[/color]
[color=blue]
> public delegate void MessageReceivedEventHandler(ServerMessage sMsg);
>
> public event MessageReceivedEventHandler MessageReceived;
> // [OneWay] goes here?
> private void OnMessageReceived(ServerMessage sMsg)
> {
> if (MessageReceived != null)
> {
> MessageReceived.BeginInvoke(sMsg, null, null);[/color]
It should go on whatever method(s) that MessageReceived contain. Yes I
know it is a pain if you don't own that method. The solution there is to
write a wrapper method that calls the method synchronously and put
[OneWay] on the wrapper method and call the wrapper method
asynchronously.
[OneWay] void Wrapper(int param)
{
MethodIDontOwn();
}
delegate void MyDelegate(int param);
MyDelegate del = new MyDelegate(Wrapper);
del.BeginInvoke(param, null, null);
// don't need to call EndInvoke
Richard
-- http://www.grimes.demon.co.uk/workshops/fusionWS.htm http://www.grimes.demon.co.uk/workshops/securityWS.htm |  | Similar C# / C Sharp bytes | | | /bytes/about
We are a network of experts and professionals in IT and software development that help one another with answers to tough questions and share insights.
Get the best answers to your questions from over 226,510 network members.
|