So i went back to the drawing board and i tried to figure out what i'm
missing, using the Expert .Net Micro Framework book from Jens Kuhner.
I can't quite wrap my mind around the following concept, maybe someone can
explain my obvious misconception, so here goes my kinda newbie-question:
Consider the following example, somewhat modified, but in basically the
'Modal Window' example from page 360 (2nd edition):
============= BEGIN CODE ================
public static void Main()
{
Program myApplication = new Program();
Window mainWindow = myApplication.CreateWindow();
// Create the object that configures the GPIO pins to buttons.
GPIOButtonInputProvider inputProvider = new
GPIOButtonInputProvider(null);
// Start the application
myApplication.Run(mainWindow);
}
private Window mainWindow;
private Window window2;
public Window CreateWindow()
{
// Create a window object and set its size to the
// size of the display.
mainWindow = new Window();
mainWindow.Height = SystemMetrics.ScreenHeight;
mainWindow.Width = SystemMetrics.ScreenWidth;
// Create a single text control.
Text text = new Text();
text.Font = Resources.GetFont(Resources.FontResources.small);
text.TextContent =
Resources.GetString(Resources.StringResources.String1);
text.HorizontalAlignment =
Microsoft.SPOT.Presentation.HorizontalAlignment.Center;
text.VerticalAlignment =
Microsoft.SPOT.Presentation.VerticalAlignment.Center;
// Add the text control to the window.
mainWindow.Child = text;
// Connect the button handler to all of the buttons.
mainWindow.AddHandler(Buttons.ButtonUpEvent, new
ButtonEventHandler(OnButtonUp), false);
// Set the window visibility to visible.
mainWindow.Visibility = Visibility.Visible;
// Attach the button focus to the window.
Buttons.Focus(mainWindow);
return mainWindow;
}
private void OnButtonUp(object sender, ButtonEventArgs e)
{
// Print the button code to the Visual Studio output window.
Debug.Print(e.Button.ToString());
Debug.Print("EVENT FOR MAINWINDOW?: " + (sender ==
mainWindow).ToString());
Debug.Print("EVENT FOR 2NDWINDOW ?: " + (sender ==
window2).ToString());
if (sender == mainWindow && e.Button ==
Microsoft.SPOT.Hardware.Button.VK_SELECT)
{
//OK Button pressed in main window. Now open second window
window2 = new Window();
window2.Visibility = Visibility.Visible;
window2.Background = new
Microsoft.SPOT.Presentation.Media.SolidColorBrush(Microsoft.SPOT.Presentation.Media.Colors.Red);
window2.AddHandler(Buttons.ButtonUpEvent, new
ButtonEventHandler(OnButtonUp), false);
window2.Topmost = true;
// Buttons go to second window now
Buttons.Focus(window2);
DispatcherFrame modalFrame = new DispatcherFrame();
PropertyChangedEventHandler handler =
delegate
{
if (window2.Visibility != Visibility.Visible)
modalFrame.Continue = false;
};
window2.IsVisibleChanged += handler;
Dispatcher.PushFrame(modalFrame);
window2.IsVisibleChanged -= handler;
}
else if (sender == window2 && e.Button ==
Microsoft.SPOT.Hardware.Button.VK_CANCEL)
{
// Cancel button pressed in second window
window2.Visibility = Visibility.Hidden;
window2.Close();
//Buttons go to mainwindow again
Buttons.Focus(mainWindow);
}
}
============= END CODE ================
What this code does is show the mainwindow with the text hello world. When i
press the OK button, it shows a new window with red background.
There i have to press the Cancel button to close it again, and the
mainwindow is visible again. I can keep doing this forever.
Now, what i don't get is:
On the line where it says Dispather.PushFrame(modalFrame); i actually block
the thread i'm currently in, until the the frame is discontinued. However,
the thread i'm in IS the dispatcher thread.
So how can i still get a new button event for the second window, when the
dispatcher was actually blocked???
I know this is the way it is supposed to work, because of the examples in
the book, but i don't get it ! :)
According to the visual studio debugger, everything is happening in the
mainthread (green color), so how does it really work?
(I noticed an extra worker thread that was running, but there is no program
counter there, so no idea what that does)
And another question:
When i set a breakpoint on the first Debug.Print line, and i enter the
expression sender==mainWindow in the Immediate Window of Visual Studio, it is
always false, whilst the debug statement will result in TRUE... Does this
have something to do with the immediate window running in yet another thread
and which doesn't have access to the dispatcher? Shouldn't i get an Invalid
Operation exception then instead of false?
There are some important things:
1. Dispatcher blocked != thread blocked
2. It is not a dispatcher what is blocked, it is the frame.
I would recommend reading through
http://msdn.microsoft.com/en-us/library/ms741870.aspx, I found this page to
be very useful in understanding the process.
In short:
- The dispatcher processes operations, which are queued in a standard
System.Collections.Queue.
- The PushFrame method is a standard while cycle, which takes an operation
from the queue and executes it synchronously.
- If there are no operations in the queue, the thread is blocked and waits
for an operation in the queue.
So, in the button up event handler, you are inside a while loop of the
dispatcher. When you call PushFrame inside the loop, a new while loop is
started synchronously, so the thread is not blocked, it is just in some kind
of operation.execute call.
That of course means, that if you would call PushFrame enough times, you
would eventually get a stack overflow exception, creating too many recursive
(better say nested) calls.
If you cause an event to be fired in the second window, it just gets added
to the queue. There is only a single queue per dispatcher, so the innermost
loop just picks it up and executes it. The loop is exited when you set
frame.Continue = false, and the thread continues to run after the first
operation.execute call.
- that is at least how I understand it. If I am wrong, let me anybody know.
Hopefully I put it in some understandable way.
Jan
Jan
"Kevin" <Ke...@discussions.microsoft.com> wrote in message
news:61D0E0FA-03AF-4054...@microsoft.com...
Thanks for your answer. It is a bit more clear to me now.
I'm thinking of redesigning some of the UI in our application the
'right' way.
The main problem i find myself running into here, is separating the
business logic from the UI logic and i'm not sure what the best
approach is here.
The application consists of a mainwindow, which is actually just a
large hierarchical menu with submenu's and such. Most of the items in
the menu, will result in opening a specific task in a specific new
window. This window must be modal, and only when closed must return to
the menu window again.
I think i can do all this with the WPF framework and dispatcher.
However, i have some 'background' processes that interact with the
hardware, and need to update icons on the active window (battery
status, network status, time, usb status etc.). I can do this with two
approaches: have the active window poll for those values every x
period, which is not a very clean thing i guess, because i also have
to stop the polling of windows not currently visible. The second
approach is have the processes signal the active window of a change in
value, but then i have to make those non-UI processes WPF aware.
What would you suggest? Is there a thrid approach?
"Jan Kučera" wrote:
> .
>