Doing navigation in App.xaml.cs within resume handler - c#

I have a C#/XAML Windows Store App and I need to be able to perform some network/RESTful API tests in the resume handler to make sure that a token/session is still valid. If it isn't, the app needs to direct the user back to the login page.
I've tried a number of solutions on SO and for one reason or another, they won't work from within App.xaml.cs. The overarching issue seems to be my inability to get to Frame.Navigate from within the resume handler.
public App()
{
this.InitializeComponent();
this.Suspending += OnSuspending;
Application.Current.Resuming += new EventHandler<object>(OnResuming);
}
private async void OnResuming(object sender, object e)
{
bool success = true;
// some tests are performed here
if (!success) { /* what do I use here? */ }
}
I've tried solutions on the following pages:
Run code on UI thread in WinRT
http://social.msdn.microsoft.com/Forums/windowsapps/en-US/6228490a-0fd8-46ce-adc6-b8d161eeec68/update-ui-when-using-threadpool?forum=winappswithcsharp
Request UI navigation using PRISM 4 on an asynchronous WCF response thread
WPF/C# Don't block the UI

In your example your handling the Resuming event from within your Application class as opposed to somewhere else. You can attach a resuming handler anywhere even within your application pages.
This example from MSDN (How to resume an app) binds the resume handler directly on the MainPage class where you should have no problem accessing the Frame.Navigate method. You could even create a PageBase class which adds this resume handler automatically so all of your pages can take advantage of this functionality.
Another solution is to just grab the root frame. The default WinRT sample app uses the following:
Frame rootFrame = Window.Current.Content as Frame;
So you should be pretty safe doing the same thing. Though you said that you were unable to get to Frame.Navigate for some reason so I'm not user if this is something you've already tried.
The main thing is to make sure that you're not blocking the UI thread at all. The Resuming event is not called on the UI thread so it won't block it by default but make sure you take advantage of async/await anyway, and use the Dispatcher to update any of the UI.

Related

Cross Thread event receiver

For my project I'm using a combination of C# UI and C++ DLL as "worker".
My Application uses the Irrlicht Engine for rendering. A panel in my C# window is used as Container for the Scene.
Currently I'm implementing an event receiver for mouse interactions. My Problem, the C++ Code don't receive events.
I worked out the core problem: It's necessary, that I'm using a rende loop, that the C++ Code have the chance to catch the event. For this loop I must use a Thread, otherwise my C# window gets freezed. Now the issue, the events don't gets send to my receiver, because the events are from another thread.
Irrlicht System Messages Handler
if (msg.hwnd == HWnd) //My issue msg.hwnd = Main Thread HWnd = Render Thread
{
WndProc(HWnd, msg.message, msg.wParam, msg.lParam); //On this way my event receiver would get the event.
}
else
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
Now I must found a solution, how I can contiously render and forwarding events from main Thread to render Thread.
My current work around is the dirty way:
C# Code
while (!RenderStop) //bool to stop this loop
{
MyDll.RenderScene(); // Calculate and redraw changes
Application.DoEvents();
}
It's no good way but with this I'm getting an fake parallelism and the events reachs my DLL.
Ps. All events are just simple MouseMove or Click events.
I would try to do as follows:
Define additional method in your worker that would be responsible for handling events, for example: HandleMouseEvent.
Run worker in the separate thread.
Subscribe mouse events in the main UI thread.
When a new event is raised call MyDll.HandleMouseEvent.
I don't know what RenderScene actually does. However, please note that HandleMouseEvent and RenderScene methods would be called in different threads. It means that you may need to synchronize access to data structures used by your worker (MyDll).
Another solution might be to use some .NET wrapper for Irrlicht Engine instead of writing it on your own. For example, I've found Irrlicht Lime. However, I have to admit I didn't use it.

Invoke a javascript function in WebBrowser and wait until javascript event fires

I'm working in .NET, C# to be specific, creating a Win Forms UserControl, which contains a WebBrowser control. The WebBrowser control hosts a page, which in turn uses a third-party javascript component. The problem I'm having is with invoking a javascript function to initialize the third-party javascript component and block the UI in the Windows Forms application until the component has been initialized, which the component notifies you of through an internal javascript event that it has.
Part of the problem is that the only way to change any configuration parameter of the third-party javascript component is to re-initialize it with the new configuration. So for example, if you want to make it read-only you have to re-initialize it with the read-only parameter.
I've got everything working in terms of being able to call the Document.InvokeScript and then in the web page call the UserControl method using window.external but the problem I'm having is how to block the UserControl code that makes the call to initialize the javascript component so that it waits and doesn't return control to the user until the initialization of the javascript component has been completed.
The reason I need it to work this way is because if I have a "Read-Only" checkbox on the form that changes the the ReadOnly property of the UserControl to control whether the javascript component shows the data as read-only and the user clicks that checkbox really quickly you will either get a javascript error or the checkbox will get out of sync with the actual read-only state of the javascript component. This seems to happen because the control hasn't re-initialized yet after it's configuration has changed and you're already trying to change it again.
I've spent hours and hours trying work out a way to make it work using everything from AutoResetEvent to Application.DoEvents and so on, but don't seem to be able to get it working.
The closest I've found is Invoke a script in WebBrowser, and wait for it to finish running (synchronized) but that uses features introduced in VS2012 (and I'm using VS2010) and I don't think it would work anyway as it's a bit different in that you're not waiting for a javascript event to fire.
Any help would be greatly appreciated.
The problem in the first place is the requirement to "block" the UI thread until some event has been fired. It's usually possible to re-factor the application to use asynchronous event handlers (with or without async/await), to yield execution control back to the message loop and avoid any blocking.
Now let's say, for some reason you cannot re-factor your code. In this case, you'd need a secondary modal message loop. You'd also need to disable the main UI while you're waiting for the event, to avoid nasty re-entrancy scenarios. The waiting itself should to be user-friendly (e.g., use the wait cursor or progress animation) and non-busy (avoid burning CPU cycles on a tight loop with DoEvents).
One way to do this is to use a modal dialog with a user-friendly message, which gets automatically dismissed when the desired JavaScript event/callback has occured. Here's a complete example:
using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace WbTest
{
[ComVisible(true)]
[ClassInterface(ClassInterfaceType.None)]
[ComDefaultInterface(typeof(IScripting))]
public partial class MainForm : Form, IScripting
{
WebBrowser _webBrowser;
Action _onScriptInitialized;
public MainForm()
{
InitializeComponent();
_webBrowser = new WebBrowser();
_webBrowser.Dock = DockStyle.Fill;
_webBrowser.ObjectForScripting = this;
this.Controls.Add(_webBrowser);
this.Shown += MainForm_Shown;
}
void MainForm_Shown(object sender, EventArgs e)
{
var dialog = new Form
{
Width = 100,
Height = 50,
StartPosition = FormStartPosition.CenterParent,
ShowIcon = false,
ShowInTaskbar = false,
ControlBox = false,
FormBorderStyle = FormBorderStyle.FixedSingle
};
dialog.Controls.Add(new Label { Text = "Please wait..." });
dialog.Load += (_, __) => _webBrowser.DocumentText =
"<script>setTimeout(function() { window.external.OnScriptInitialized}, 2000)</script>";
var canClose = false;
dialog.FormClosing += (_, args) =>
args.Cancel = !canClose;
_onScriptInitialized = () => { canClose = true; dialog.Close(); };
Application.UseWaitCursor = true;
try
{
dialog.ShowDialog();
}
finally
{
Application.UseWaitCursor = false;
}
MessageBox.Show("Initialized!");
}
// IScripting
public void OnScriptInitialized()
{
_onScriptInitialized();
}
}
[ComVisible(true)]
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
public interface IScripting
{
void OnScriptInitialized();
}
}
Which looks like this:
Another option (a less user-friendly one) is to use something like WaitOneAndPump from here. You'd still need to take care about disabling the main UI and showing some kind of waiting feedback to the user.
Updated to address the comment. Is your WebBrowser actually a part of the UI and visible to the user? Should the user be able to interact with it? If so, you cannot use a secondary thread to execute JavaScript. You need to do it on the main thread and keep pumping messages, but WaitOne doesn't pump most of Windows messages (it only pumps a small fraction of them, related to COM). You might be able to use WaitOneAndPump which I mentioned above. You'd still need to disable the UI while waiting, to avoid re-entrancy.
Anyhow, that'd still be a kludge. You really shouldn't be blocking the execution just to keep the linear code flow. If you can't use async/await, you can always implement a simple state machine class and use callbacks to continue from where it was left. That's how it used to be before async/await.

Error loading custom user controls from different threads

I have a WPF project and from the main window i am creating and loading some bunch of user controls, there is some large data i am loading in background and then updating a built-in control throw the dispatcher, that works fine, the problem is that some of the user controls loads a lot of data, for example the very first thing i load in the main area of my main window, what i want is to put a loading label instead, load the main window as fast as possible so the user see this label and run in background the creation of that user control and when is done add it as a child of my main container area on my main window while i remove the loading label, if i follow the same philosophy i run into the same error like when i run a task and then try to update the window without using the dispatcher. i want to be able of create the user control asynchronous then update the main window.
Code:
User Control:
public partial class CustomUserControlGallery : UserControl
{
public CustomUserControlGallery()
{
InitializeComponent();
}
...
}
On the backend class of the main window:
public partial class MainWindow : Window
{
CustomUserControlGallery _customUserControlGallery;
public MainWindow()
{
InitializeComponent();
Task t = new Task({
//Can't use the _customUserControlGallery's Dispatcher because object is uninitialized and this.Dispatcher not working either.
_customUserControlGallery = new CustomUserControlGallery(); //Error Here.
_gridContainer.Dispatcher.Invoke(new Action(() => _gridContainer.Children.Add(_customUserControlGallery)));
_loadingLabel.Visbility = Visibility.Collapse;
});
t.Start();
}
...
}
I don't know how to handle this situation with the thread associated to the user control and the main thread.
Error:
{"The calling thread must be STA, because many UI components require this."}
You're doing this wrong. All controls must be created & operate on the UI Thread. That said, you can use the BackgroundWorker class to load the data.
You typically do this by disabling the control whose data is being loaded in the background or hiding it & displaying a progress indicator in its place. Then, you start your BackgroundWorker. That can communicate how far along it is using the ReportProgress method. Finally, when it's finished running, the RunWorkerCompleted event is fired, and you use that to either enable the control, or to hide the progress indicator & show the control.
Some quick & dirty (untested) code:
Place this in your Initialize() or control constructor:
private BackgroundWorker loadData = new BackgroundWorker();
loadData.DoWork += loadData_DoWork;
loadData.ProgressChanged += loadData_ProgressChanged; // Only do this if you are going to report progress
loadData.WorkerReportsProgress = true;
loadData.WorkerSupportsCancellation = false; // You can set this to true if you provide a Cancel button
loadData.RunWorkerCompleted += loadData_RunWorkerCompleted;
private void DoWork( object sender, DoWorkEventArgs e ) {
BackgroundWorker worker = sender as BackgroundWorker;
bool done = false;
while ( !done ) {
// If you want to check for cancellation, include this if statement
if ( worker.CancellationPending ) {
e.Cancel = true;
return;
}
// Your code to load the data goes here.
// If you wish to display progress updates, compute how far along you are and call ReportProgress here.
}
}
private void loadData_ProgressChanged( object sender, ProgressChangedEventArgs e ) {
// You code to report the progress goes here.
}
private void loadData_RunWorkerCompleted( object sender, RunWorkerCompletedEventArgs e ) {
// Your code to do whatever is necessary to put the UI into the completed state goes here.
}
What you are essentially saying (I think) is that Your app becomes sluggish while your control renders a large amount of data.
This is a problem that needs to be solved via virtualisation. You cannot create a control on a background thread, have it render its data behind the scenes and then pop it into existence. You can create controls on separate dispatchers, but they cannot share the same visual and logical tree, so you will not be able to have one as a child of the other.
Virtualisation is what you need to focus on. Depending on the control you can use a variety of virtualisation settings. Try googleing the subject as there is a lot of information on how to achieve this effectively. Most likely you will want to use things like virtualizing stackpanels and container recycling.
You cannot create UI controls with different Dispatchers and use them with each other. It's just not allowed. What you want to do is on your Task you do the heavy lifting work without UI updates and when it is done you push it back to the Dispatcher to update the UI.
In your case, I wouldn't even use Dispatcher.Invoke. Since you are using Task, it has a TaskScheduler.FromCurrentSynchronizationContext() that you can pass in the constructor.
What is the purpose of instantiating controls in a different thread if you're just going to put it back to the Main dispatcher? It's not expensive to do that.

Ensuring that child controls are created in main UI thread

I'm modifying existing WinForms project. The project has UserControl.
This UserControl has DataSet variable which is set from another part of the program in different thread.
What I want to do is to dynamically add another controls to this control depending on the DataSet.
So, after DataSet is loaded, I'm calling RefreshChildControl function and trying to add my new ChildUserControls to flowLayoutPanel. And that's where the problems begin:). I get the "Cross-thread operation not valid: Control 'ChildUserControl' accessed from a thread other than the thread it was created on" exception. I tried to use if(this.InvokeRequired) and Invoke this method, but it does not help. InvokeRequired on MyUserControl is false.
So, is there any good way of performing such task? Or am I missing something important?
EDIT:
I tried to skip InvokeRequired test and just call this.FindForm().Invoke on this method. I've got "Invoke or BeginInvoke cannot be called on a control until the window handle has been created." exception. And, by the way, when I open another form with this control everything worked fine.
First. The simplest solution is to perform Invoke everytime. Nothing bad will happen.
Second, use SynchronizationContext.
using System.Threading;
public class YourForm
{
SynchronizationContext sync;
public YourForm()
{
sync = SynchronizationContext.Current;
// Any time you need to update controls, call it like this:
sync.Send(UpdateControls);
}
public void UpdateControls()
{
// Access your controls.
}
}
SynchronizationContext will manage all threading issues for you. It checks, whether you call from the same or from the other thread. If from same it will just immediately execute your code. Otherwise it will do Invoke through form's message loop.
If your user control is not immediately visible after you construct it, the handle will not be created on the thread that you think it is created on. It's not the C# object whose thread parent is important, it is the Windows Handle object whose parent is important.
To force a control to be immediately created on the thread that you thought you created it on, then
read out the control.Handle which will force the control to actually be made and assigned a handle.
MyUserControl uc = new MyUserControl(); // the handle is not created here
uc.Visible = false;
IntPtr dummy = uc.Handle; // The control is immediately given a real handle
You can also try to fiddle around with uc.CreateControl, but this won't create the handle if the control is not visible.
Now you can have another thread update your user control even if the user control is not visible.
uc.BeginInvoke((Action)(() => uc.Text = "ha ha"));
If you leave out the dummy = uc.Handle line, you will get an exception that you can't call BeginInvoke on a control that does not have a handle.
http://msdn.microsoft.com/en-us/library/system.windows.forms.control.createcontrol(v=vs.90).aspx

How can you tell if you're on the Main UI thread? (In CF)

Now unfortunately due to the fact that WinCE Usb Device Arrival / Removal exposes itself via WindowsMessages I have to ensure that a certain (non-UI) component is not created on a background thread. I would like to assert this via an exception but am lacking the code for the assertion.
This component creates a MessageWindow* and uses it to receive usb arrived/removed messages. The issue is if someone creates this component on a background thread (not necessarily; IsBackground = true) when the thread exits the window will be destroyed.
Any ideas?
*as an aside I still don't know why Form doesn't inherit from this class
Update
I think my version 1 wasn't very clear. So this is v2.
When you create a MessageWindow or a Form for that matter on a thread, when that thread exits the Window/Form is destroyed.
My component is creating a "hidden" message window to intercept some important events, ergo I do not wish for it to be destroyed. Therefore I must somehow ensure that the code that creates the form is running on the "Main UI" thread.
If possible i'd like to avoid passing down a reference to the "main" form to this component as it is (architecturally speaking) supposed to be miles away from the UI.
Update
Moving logging question to a separate Q.
Ok, I understand that you don't want for your component to "know" about the main window -- makes sense.
How about this: How about if you make sure that you always instance your component on the main thread? You component will create it's listener window on the constructor's thread.
If you do that, then you just need to make sure that you call the constructor from the main thread. I'm making some assumptions about your code, but I'm guessing that you must have some class in your architecture that knows about both the UI and your component. Create your component there, using a callback, and the main form's InvokeRequired/Invoke methods.
In forms, you use the InvokeRequired property.
Why not create the non-UI component on a background thread and when you go to update any UI component just look to see if invokeRequired then get back on the main thread to actually do the update.
You should have nothing really tying up the main event thread, IMO.
You can use it in this way:
void MyCallback()
{
if (form1.InvokeRequired) { // form1 is any existing gui control
form1.Invoke(new Action<>(MyCallBack));
return;
}
// your logic here
}
Hey there: I had an idea about your problem. This is just a random thought, and I don't know for sure whether it will work (I have not tested, nor even compiled this -- it just hit me):
What if you get the window handle of the main window of your app, then build a Control around it (I'm assuming that you have a gdi-based app, like Winforms)?
this code might not compile, but it's close (it would go into your component -- note that it would make your component require a gdi windows/winform app, as opposed to a console or WPF app).
If you do try it, I'd love to hear whether it worked for you.
using System.Diagnostics;
using System.Windows.Forms;
void Init()
{
// get handle to the main window
intPtr mainWindowHandle = Process.GetCurrentProcess().MainWindowHandle;
Control mainWindow = Control.FromHandle(mainWindowHandle);
if(mainWindow.InvokeRequired)
mainWindow.Invoke(SetupMessageWindow);
else
SetupMessageWindow();
}
void SetupMessageWindow()
{
// do your thing...
}

Categories