Need explaination of BeginInvoke timing

G

Guest

Hi

Found some code that works for me to allow me to highlight text when I
re-enter a textbox.

I was curious if someone could explain how BeginInvoke is working???
I know it causes execution in a separate thread but how is the timing set
to ensure that the bool is reset after after all the window events {enter,
mouseup} that are working on the original bool value are complete ????

Thanks


bool enter = false, needSelect = false;
private void ResetEnterFlag()
{
enter = false;
}
private void txtSearch_Enter(object sender, EventArgs e)
{
enter = true;
BeginInvoke(new MethodInvoker(ResetEnterFlag));
}
private void txtSearch_MouseUp(object sender, MouseEventArgs e)
{
if (needSelect) (sender as TextEdit).SelectAll();
}
private void txtSearch_MouseDown(object sender, MouseEventArgs e)
{
needSelect = enter;
}
 
P

Peter Duniho

sippyuconn said:
Found some code that works for me to allow me to highlight text when I
re-enter a textbox.

That code seems pretty suspicious to me.
I was curious if someone could explain how BeginInvoke is working???

Basically, it just queues the delegate invocation on the regular message
queue for the control's owning thread. As the thread processes the
messages, when that invocation comes to the front of the queue, it's
executed.

There is no specific ordering mechanism involved, though of course if
you have knowledge of what events have already been placed in the queue,
you know that the invocation will be executed after those events.
I know it causes execution in a separate thread but how is the timing set
to ensure that the bool is reset after after all the window events {enter,
mouseup} that are working on the original bool value are complete ????

Actually, while you don't post enough code to be certain, it appears
that the event handlers are just handlers for the regular Control events
Enter, MouseUp, and MouseDown. If so, then none of the code gets
executed "in a separate thread". All of the code you posted is being
executed in the control's owning thread.

So basically, what the code is doing is using the thread's message queue
as a sort of signaling mechanism. It is making the assumption that the
Enter event will be raised before the MouseDown event corresponding to
the mouse action that caused the control to receive focus, and that the
MouseDown event is already in the message queue. The latter assumption
seems reasonable; I'm less sure about the former.

The code is setting the flag, queuing a delegate that resets the flag
which will be executed after all of the messages that are already in the
queue (which in this case is assumed to include the mouse down event),
and then the remaining events are processed, including the MouseDown
event and the delegate invocation that was queued via BeginInvoke. The
flag is automatically reset once all events that were in the queue at
the time the invocation was queued have been processed.

Now, this all may work but I have a couple of issues with it. The first
is that I don't see anywhere that documents the order of the events. I
think it's safe to assume that the MouseDown event is going to happen
before the delegate invocation; after all, it was the underlying mouse
action that presumably caused the Enter event to be raised in the first
plcae. However, I don't see any documentation that guarantees that the
Enter event will be raised before the MouseDown event. Since these both
are a consequence of the same underlying mouse action, it is conceivable
to me that the order could be different in the future.

The second issue is that it seems overly complicated for whatever the
actual goal is. The code appears to be trying to ensure that if you
click on a text control to set the focus, that the text will be
completely highlighted. But it's very fragile (subject to assumptions
regarding the order of events being raised _and_ how the user interacts
with the control), and as you've found it's less-than-intuitive as far
as how it works goes. It may be the minimal amount of code required to
implement the functionality, but it's hardly the most obvious.

I actually have a bit of a third issue with it, and it's the same issue
I have when I run across any code that interferes with the normal UI
response in a standard control: it is a very bad thing to change the UI
response in a standard control. We have standardized UI for a reason,
and that is so that the UI can follow the very important "rule of least
surprise". The edit control already has a well-defined and well-known
way to fully select the text when the user clicks in it (double-click),
and the code you posted will, when it works, prevent another common user
interaction with the control, namely doing a drag-select on the text
when the control isn't already the one with focus.

I'm not sure what's scarier: that even one person would want to
implement this UI, or that enough people have implemented this UI that
it was possible to dig up sample code for the change. :)

Pete
 
J

Jeffrey Tan[MSFT]

Hi,

Peter has provided a detailed reply to you. Yes, I agree with Peter that
Control.BeginInvoke is not a good way to synchronize the events order. It
is usually used to queue a UI control calling from a non-UI worker thread.

For internal work, Control.BeginInvoke() internally calls MarshaledInvoke()
method, which first registers a customized window message and then invoke
PostMessage() API to post this message in the GUI thread message queue.
Below is the source code obtained from Reflector:

private object MarshaledInvoke(Control caller, Delegate method, object[]
args, bool synchronous)
{
int num;
if (!this.IsHandleCreated)
{
throw new
InvalidOperationException(SR.GetString("ErrorNoMarshalingThread"));
}
if (((ActiveXImpl) this.Properties.GetObject(PropActiveXImpl)) != null)
{
IntSecurity.UnmanagedCode.Demand();
}
bool flag = false;
if ((SafeNativeMethods.GetWindowThreadProcessId(new HandleRef(this,
this.Handle), out num) == SafeNativeMethods.GetCurrentThreadId()) &&
synchronous)
{
flag = true;
}
ExecutionContext executionContext = null;
if (!flag)
{
executionContext = ExecutionContext.Capture();
}
ThreadMethodEntry entry = new ThreadMethodEntry(caller, method, args,
synchronous, executionContext);
lock (this)
{
if (this.threadCallbackList == null)
{
this.threadCallbackList = new Queue();
}
}
lock (this.threadCallbackList)
{
if (threadCallbackMessage == 0)
{
threadCallbackMessage =
SafeNativeMethods.RegisterWindowMessage(Application.WindowMessagesVersion +
"_ThreadCallbackMessage");
}
this.threadCallbackList.Enqueue(entry);
}
if (flag)
{
this.InvokeMarshaledCallbacks();
}
else
{
UnsafeNativeMethods.PostMessage(new HandleRef(this, this.Handle),
threadCallbackMessage, IntPtr.Zero, IntPtr.Zero);
}
if (!synchronous)
{
return entry;
}
if (!entry.IsCompleted)
{
this.WaitForWaitHandle(entry.AsyncWaitHandle);
}
if (entry.exception != null)
{
throw entry.exception;
}
return entry.retVal;
}

Hope this helps.

Best regards,
Jeffrey Tan
Microsoft Online Community Support
==================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/subscriptions/managednewsgroups/default.aspx#notif
ications.

Note: The MSDN Managed Newsgroup support offering is for non-urgent issues
where an initial response from the community or a Microsoft Support
Engineer within 1 business day is acceptable. Please note that each follow
up response may take approximately 2 business days as the support
professional working with you may need further investigation to reach the
most efficient resolution. The offering is not appropriate for situations
that require urgent, real-time or phone-based interactions or complex
project analysis and dump analysis issues. Issues of this nature are best
handled working with a dedicated Microsoft Support Engineer by contacting
Microsoft Customer Support Services (CSS) at
http://msdn.microsoft.com/subscriptions/support/default.aspx.
==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.
 
J

Jeffrey Tan[MSFT]

Hi,

Have you reviewed our replies to you? Do they make sense to you? If you
still need any help, please feel free to feedback, thanks.

Best regards,
Jeffrey Tan
Microsoft Online Community Support
==================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/subscriptions/managednewsgroups/default.aspx#notif
ications.

Note: The MSDN Managed Newsgroup support offering is for non-urgent issues
where an initial response from the community or a Microsoft Support
Engineer within 1 business day is acceptable. Please note that each follow
up response may take approximately 2 business days as the support
professional working with you may need further investigation to reach the
most efficient resolution. The offering is not appropriate for situations
that require urgent, real-time or phone-based interactions or complex
project analysis and dump analysis issues. Issues of this nature are best
handled working with a dedicated Microsoft Support Engineer by contacting
Microsoft Customer Support Services (CSS) at
http://msdn.microsoft.com/subscriptions/support/default.aspx.
==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top