I have this
public Result SomeMethod()
{
Popup popup = new Popup();
popup.Closed += PopupClosedHandler;
popup.ShowPopup();
// have to return the result from handler.
}
void PopupClosedHandler(EventArgs<PopupEventArgs> args)
{
Result result = args.Result;
}
I have to block SomeMethod() call until popup is called and return the Result from args in the handler. I have no idea how to do this or even how to look for it. Can anyone put me in the right direction? Thanks
You want to use an EventWaitHandle.
public Result SomeMethod()
{
_doneHandler = new EventWaitHandle(false, EventResetMode.ManualReset);
Popup popup = new Popup();
popup.Closed += PopupClosedHandler;
popup.ShowPopup();
// This will wait until it is SET. You can pass a TimeSpan
// so that you do not wait forever.
_doneHandler.WaitOne();
// Other stuff after the 'block'
}
private EventWaitHandle _doneHandler;
void PopupClosedHandler(EventArgs<PopupEventArgs> args)
{
Result result = args.Result;
_doneHandler.Set();
}
This is crude, but should give the general idea
public Result SomeMethod()
{
Popup popup = new Popup();
bool called = false;
Result result = null;
popup.Closed += (args) => {
called = true;
result = args.Result;
}
while(!called) ;
return result;
}
Related
Hi All: I want to run a function to check internet connection and update the UI content, so i'm using a Dispatchtimer in the WPF loaded, during the intenet check if the ping is blocked by the local server or for some x reasons the UI is blocking.
How can i call the function continuosly without blocking the UI & update the User interface? thanks.
private DispatcherTimer BackgroundAsyncTasksTimer;
private void Window_Loaded(object sender, RoutedEventArgs e)
{
BackgroundAsyncTasksTimer = new DispatcherTimer();
BackgroundAsyncTasksTimer.Interval = TimeSpan.FromMilliseconds(2000);
BackgroundAsyncTasksTimer.Tick += BackgroundAsyncTasksTimer_Tick;
BackgroundAsyncTasksTimer.Start();
}
private async void BackgroundAsyncTasksTimer_Tick(object sender, object e)
{
if(CanConnectToTheInternet())
{
Dispatcher.Invoke((Action)delegate () {
einternetcoxn.Fill = (SolidColorBrush)new BrushConverter().ConvertFromString("#00ff00"); //Eclipse
checkNewversion();
bUpdatesoftware.IsEnabled = true;//button
});
}
else
{
Dispatcher.Invoke((Action)delegate () {
einternetcoxn.Fill = (SolidColorBrush)new BrushConverter().ConvertFromString("#841c34");
clearfields();
});
}
}
private static bool CanConnectToTheInternet()
{
try
{
string[] strArray = new string[5]
{
"8.8.8.8",
"https://www.google.com",
"https://www.microsoft.com",
"https://www.facebook.com",
};
if (((IEnumerable<string>)strArray).AsParallel<string>().Any<string>((Func<string, bool>)(url =>
{
try
{
Ping ping = new Ping();
byte[] buffer = new byte[32];
PingOptions options = new PingOptions();
if (ping.Send(url, 500, buffer, options).Status == IPStatus.Success)
return true;
}
catch
{
}
return false;
})))
return true;
if (((IEnumerable<string>)strArray).AsParallel<string>().Any<string>((Func<string, bool>)(url =>
{
try
{
HttpWebRequest httpWebRequest = (HttpWebRequest)WebRequest.Create(url);
httpWebRequest.KeepAlive = false;
httpWebRequest.Timeout = 5000;
using ((HttpWebResponse)httpWebRequest.GetResponse())
return true;
}
catch
{
}
return false;
})))
return true;
}
catch
{
return false;
}
return false;
}
A DispatcherTimeris not running the tick event on a background thread, at least not by default in a UI application.
But this should be fine if you change your CanConnectToTheInternetmethod to use Ping.SendAsync and WebRequest.GetResponseAsync. That will require you to follow the async await pattern, but this is an good example of the kind of task this pattern is meant for. In this case you should get rid of all the Dispatcher.Invoke-stuff, since all of your code would run on the UI thread.
The alternative would be to use a timer that runs the tick-event on a threadpool thread, like Timers.Timer. See also timer comparison
I have code that gets executed when a ListView item is selected. Since this code can take a noticeable amount of time to execute I want to display an ActivityIndicator while it is running.
I have read through a lot of posts about the ActivityIndicator and I believe I have it setup correctly. I'm pretty sure my problem is due to the running code blocking the UI thread since the UI freezes completely during the process.
I've worked through every variation I have been able to find for using async/await with no luck so I'm assuming that I am still doing something incorrectly.
Here is my code:
private ListItem selectedList;
public ListItem SelectedList
{
get
{
return selectedList;
}
set
{
if (selectedList != value)
{
var oldValue = selectedList;
selectedList = value;
buildThisList();
}
}
}
private async void buildThisList()
{
StatusBarIsVisibile = true;
ThisList = Task.Run(async () =>
{
return await buildBnBList(SelectedList, selectedLocation,
thisYearList.ListId)
.ConfigureAwait(false);
}).Result; // 1.8 seconds
StatusBarIsVisibile = false;
ThisList.MainVM = this;
ThisList.BuildView();
PIShowListHeaderText = SelectedList.Title.Trim();
}
private async Task<BnBList> buildBnBList(ListItem pSelectedList, State pselectedLocation, int pListId)
{
BnBList newList = new BnBList(pSelectedList, pselectedLocation, pListId);
List<BirdsnBflysMaster> bbfList =
App.BnBRepo.GetBirdsnBflys(selectedList.ListType); // 1.3 seconds
Lists parentList = App.BnBRepo.GetAList(SelectedList.ListId); // .5 seconds
BnBItem newBnBItem;
foreach (BirdsnBflysMaster bbf in bbfList) // .4 seconds
{
newBnBItem = new BnBItem(parentList, bbf, selectedLocation, newList, thisYearList.ListId);
newList.ListAll.Add(newBnBItem);
if (newBnBItem.ListTypeID == "Bird")
{
...
}
else
{
...
}
}
return newList;
}
So:
buildThisList gets called when the SelectedList property changes.
buildThisList calls buildBnBList which is the time consuming process.
buildBnBList has nothing in it that is done asynchronously.
StatusBarIsVisible is bound to both IsVisible and IsRunning of the ActivityIndicator.
How can I code this so that executing buildBnBList does not block the UI thread?
Yes you a mixing blocking (.Result) with async code which risks causing deadlocks. async void should be avoided, unless in an even handler.
So then why not do just that?
Create an event and event handler.
public event EventHandler ListSelected = delegate { }
this should now allow you to create an event handler
private async void OnListSelected(object sender, EventArgs e) {
StatusBarIsVisibile = true;
ThisList = await buildBnBList(SelectedList, selectedLocation, thisYearList.ListId);
StatusBarIsVisibile = false;
ThisList.MainVM = this;
ThisList.BuildView();
PIShowListHeaderText = SelectedList.Title.Trim();
}
You would obviously subscribe to the event (early in the life-cycle of course)
this.ListSelected += OnListSelected;
and raise the event as needed
private ListItem selectedList;
public ListItem SelectedList {
get {
return selectedList;
}
set {
if (selectedList != value) {
var oldValue = selectedList;
selectedList = value;
OnListSelected(this, EventArgs.Empty);
}
}
}
This is my code. I am using Application.DoEvents() for waiting that UI thread is finished.
public override void Process(Crawler crawler, PropertyBag propertyBag)
{
AspectF.Define.
NotNull(crawler, "crawler").
NotNull(propertyBag, "propertyBag");
if (propertyBag.StatusCode != HttpStatusCode.OK)
return;
if (!IsHtmlContent(propertyBag.ContentType))
return;
m_Logger.Verbose("CefGlue started for url {0}", propertyBag.ResponseUri.ToString());
CefGlueBrowserForm cefGlueBrowserForm = new CefGlueBrowserForm(propertyBag.ResponseUri.ToString());
cefGlueBrowserForm.Show();
while (!cefGlueBrowserForm.Done)
Application.DoEvents();
string htmlSource = cefGlueBrowserForm.DocumentDomHtml;
propertyBag.GetResponse = () => new MemoryStream(Encoding.UTF8.GetBytes(htmlSource));
base.Process(crawler, propertyBag);
}
I am reading that Application.DoEvents() is evil. I am also getting sometimes stackoverflow exception. What to use instead of Application.DoEvents()?
I try something with BackgroundWorker but nothing works
Example:
AutoResetEvent waitHandle = new AutoResetEvent(false);
BackgroundWorker bw = new BackgroundWorker();
bw.WorkerReportsProgress = true;
bw.WorkerSupportsCancellation = true;
bw.DoWork += (sender, e) =>
{
if (!e.Cancel)
{
CefGlueBrowserForm cefGlueBrowserForm = new CefGlueBrowserForm(propertyBag.ResponseUri.ToString());
cefGlueBrowserForm.Show();
while (!cefGlueBrowserForm.Done)
Application.DoEvents();
e.Result = cefGlueBrowserForm.DocumentDomHtml;
cefGlueBrowserForm.Dispose();
waitHandle.Set();
}
};
bw.RunWorkerCompleted += (sender, e) =>
{
string htmlSource = e.Result.ToString();
propertyBag.GetResponse = () => new MemoryStream(Encoding.UTF8.GetBytes(htmlSource));
base.Process(crawler, propertyBag);
};
bw.RunWorkerAsync(TimeSpan.FromSeconds(10));
waitHandle.WaitOne(TimeSpan.FromSeconds(20));
What can I do?
EDIT:
added code how cefGlueBrowserForm.Done is set.
public partial class CefGlueBrowserForm : Form
{
public CefGlueBrowserForm(string url)
{
m_Logger = NCrawlerModule.Container.Resolve<ILog>();
m_url = url;
InitializeComponent();
CefManager.InitializeCef();
AddWebBrowser(m_url);
}
private void AddWebBrowser(string startUrl)
{
m_textBox = new TextBox
{
Dock = DockStyle.Bottom,
ReadOnly = true,
};
m_textBox.Parent = this;
Console.Box = m_textBox;
Console.WriteLine("Loading URL ...");
CefGlueBrowser = new ChromiumCefWebBrowser();
CefGlueBrowser.Dock = DockStyle.Fill;
CefGlueBrowser.BringToFront();
CefGlueBrowser.StartUrl = startUrl;
CefGlueBrowser.Parent = this;
Controls.Add(CefGlueBrowser);
Console.WriteLine("URL " + startUrl + " loaded.");
CefGlueBrowser.LoadEnd += Browser_LoadEnd;
}
private void Browser_LoadEnd(object sender, EventArgs e)
{
m_Logger.Verbose("Page load was ended for url {0}", m_url);
MyCefStringVisitor visitor = new MyCefStringVisitor(this, m_url);
((LoadEndEventArgs)e).Frame.Browser.GetMainFrame().GetSource(visitor);
}
private class MyCefStringVisitor : CefStringVisitor
{
#region Instance Fields
private CefGlueBrowserForm m_cefGlueBrowserForm;
private string m_url;
private ILog m_Logger;
#endregion
#region Constructors
public MyCefStringVisitor(CefGlueBrowserForm cefGlueBrowserForm, string url)
{
m_Logger = NCrawlerModule.Container.Resolve<ILog>();
m_cefGlueBrowserForm = cefGlueBrowserForm;
m_url = url.NormalizeUrl();
}
#endregion
#region Instance Methods
protected override void Visit(string value)
{
string currentUrl = m_cefGlueBrowserForm.CefGlueBrowser.Browser.GetMainFrame().Url.NormalizeUrl();
if (m_url.Equals(currentUrl, StringComparison.OrdinalIgnoreCase) || currentUrl.Contains(m_url))
{
m_Logger.Verbose("Getting html source for url {0} and closing Event", m_url);
m_cefGlueBrowserForm.DocumentDomHtml = value;
m_cefGlueBrowserForm.Done = true;
m_cefGlueBrowserForm.CefGlueBrowser.LoadEnd -= m_cefGlueBrowserForm.Browser_LoadEnd;
}
}
#endregion
}
#endregion
}
So what you want to do is execute the rest of the code after the form has been closed. You can do that by simply subscribing to the FormClosed event and running the rest of that code there, rather than blocking the UI thread until the form is closed:
CefGlueBrowserForm cefGlueBrowserForm =
new CefGlueBrowserForm(propertyBag.ResponseUri.ToString());
cefGlueBrowserForm.Show();
cefGlueBrowserForm.FormClosed += (sender, e) =>
{
string htmlSource = cefGlueBrowserForm.DocumentDomHtml;
propertyBag.GetResponse = () =>
new MemoryStream(Encoding.UTF8.GetBytes(htmlSource));
base.Process(crawler, propertyBag);
};
There's no need for other threads to do this.
Another approach is to leverage the await keyword to accomplish this same general task, but with a generally easier syntax. If we take the time to write a simple helper method that generates a Task that will be completed when the form is closed:
public static Task WhenClosed(this Form form)
{
var tcs = new TaskCompletionSource<bool>();
FormClosedEventHandler handler = null;
handler = (s, args) =>
{
tcs.TrySetResult(true);
form.FormClosed -= handler;
};
form.FormClosed += handler;
return tcs.Task;
}
Then we can write the method like this:
public async Task Process(Crawler crawler, PropertyBag propertyBag)
{
//...
CefGlueBrowserForm cefGlueBrowserForm =
new CefGlueBrowserForm(propertyBag.ResponseUri.ToString());
cefGlueBrowserForm.Show();
await cefGlueBrowserForm.WhenClosed();
string htmlSource = cefGlueBrowserForm.DocumentDomHtml;
propertyBag.GetResponse = () =>
new MemoryStream(Encoding.UTF8.GetBytes(htmlSource));
base.Process(crawler, propertyBag);
}
And while this looks like it's blocking until the form is closed, under the hood this is generating code that will act rather similarly to the code that we have above; it will run everything after the await as a continuation fired when the event fires.
I am modifying a windows desktop application that works with some external hardware. When the user activates the hardware from the application a progress (UI) form is started. This form creates a thread that performs all of the work with the hardware. The problem comes when I try to report progress back to the UI thread. It appears that the first of my Control.BeginInvoke ("Negotiating message") works fine. However, the second one (first adjustment to progressbar) never seems to call it's delegate and as a result the application locks up on the subsequent endinvoke. I believe the issue is that the GUI is now in an idle state, but I am not sure how to fix the situation. Any help would be appreciated. Code found below:
In the UI Load Method Thread:
private void frmTwainAquire_Load(object sender, EventArgs e)
{
try
{
//Show the GUI
this.Visible = showGUI;
pbScanningProgress.Value = 0;
btnCancel.Enabled = false;
btnCancel.Visible = false;
// Set the delegates.
SetScanMessageDelegate = new SetScanMessage(this.SetScanMessageMethod);
SetRegistrationMessageDelegate = new SetRegistrationMessage(this.SetRegistrationMessageMethod);
AddScanProgressDelegate = new AddScanProgress(this.AddScanProgressMethod);
AddRecogProgressDelegate = new AddRecogProgress(this.AddRecogProgressMethod);
// Set progress bars.
pbScanningProgress.Value = 0;
pbRecognition.Value = 0;
abortScan = false;
// Create thread here!
twainInstance = new rScan.Twain();
rScanning = new rScanThread(this, twainInstance);
// Start the thread.
rScanning.tScan = new Thread(rScanning.Scan);
rScanning.tScan.Start();
}
catch (Exception ex)
{
// Error checking here.
}
}
Delegate Methods:
public void SetScanMessageMethod(string scanMessage)
{
this.lblScanMessage.Text = scanMessage;
}
public void SetRegistrationMessageMethod(string recogMessage)
{
this.lblRecognition.Text = recogMessage;
}
public void AddScanProgressMethod(int progress)
{
this.pbScanningProgress.Value += progress;
}
public void AddRecogProgressMethod(int progress)
{
this.pbRecognition.Value += progress;
}
Thread method that is giving the problem. Please note that the thread is in a different class then the previous two code blocks (both are in the UI class):
public class rScanThread : IMessageFilter
public void Scan()
{
// Set progress bar message.
IAsyncResult result;
if (frmTwainAquireInstance.lblScanMessage.IsHandleCreated && frmTwainAquireInstance.lblScanMessage.InvokeRequired)
{
result = frmTwainAquireInstance.lblScanMessage.BeginInvoke(frmTwainAquireInstance.SetScanMessageDelegate, "Negotiating Capabilities with Scanner.");
frmTwainAquireInstance.lblScanMessage.EndInvoke(result);
}
else
{
frmTwainAquireInstance.lblScanMessage.Text = "Negotiating Capabilities with Scanner.";
}
// Start the intialization of the rScan process.
bool intializeSuccess = twainInstance.Initialize(frmTwainAquireInstance.Handle);
// If the process could not be started then quit.
if (!intializeSuccess)
{
frmTwainAquireInstance.Close();
return;
}
if (frmTwainAquireInstance.pbScanningProgress.IsHandleCreated && frmTwainAquireInstance.pbScanningProgress.InvokeRequired)
{
result = frmTwainAquireInstance.pbScanningProgress.BeginInvoke(frmTwainAquireInstance.AddScanProgressDelegate, 33);
frmTwainAquireInstance.pbScanningProgress.EndInvoke(result); // Lock up here.
}
else
{
frmTwainAquireInstance.pbScanningProgress.Value += 33;
}
// Do more work after. The code never makes it this far.
} // End of rScanThread.Scan()
I Want to write my own control, when the ctor is invoked, a MessageBox is shown.
public class Class1
{
public Class1()
{
ShowDialog();
}
void ShowDialog()
{
SynchronizationContext context = SynchronizationContext.Current;
if (context != null)
{
context.Post((f) =>
{
MessageDialog dialog = new MessageDialog("Hello!");
dialog.ShowAsync();
}, null);
}
}
}
If my class is used by someone, and write the codes as below, UnauthorizedAccessException is always thrown in dialog.ShowAsync();
void MainPage_Loaded(object sender, RoutedEventArgs e)
{
ClassLibrary1.Class1 c1 = new ClassLibrary1.Class1();
MessageDialog dialog1 = new MessageDialog("");
dialog1.ShowAsync();
}
Is there a way to show a message dialog without exception?
I found a way, enjoy it!
Task ShowDialog()
{
CoreDispatcher dispatcher = Windows.ApplicationModel.Core.CoreApplication.MainView.CoreWindow.Dispatcher;
Func<object, Task<bool>> action = null;
action = async (o) =>
{
try
{
if (dispatcher.HasThreadAccess)
await new MessageDialog("Hello!").ShowAsync();
else
{
dispatcher.RunAsync(CoreDispatcherPriority.Normal,
() => action(o));
}
return true;
}
catch (UnauthorizedAccessException)
{
if (action != null)
{
Task.Delay(500).ContinueWith(async t => await action(o));
}
}
return false;
};
return action(null);
}
As MessageDialogue needs to run on the UI thread, can you try switching it to:
var dispatcher = Windows.UI.Core.CoreWindow.GetForCurrentThread().Dispatcher;
dispatcher.RunAsync(DispatcherPriority.Normal, <lambda for your code which should run on the UI thread>);
The cleaner solution may look like this. The interesting part ist hidden in die showDialogAsync(). For convenience you can use the Close() method to close the current dialog again programmatically. The IUIDispatcher is another helper interface you can rebuild yourself easily:
private readonly IUIDispatcher _dispatcher;
readonly Object _queueMonitor = new object();
readonly Object _showMonitor = new object();
private IAsyncOperation<IUICommand> _currentDialogOperation;
readonly Queue<MessageDialog> _dialogQueue = new Queue<MessageDialog>();
public async Task ShowAsync(string content)
{
var md = new MessageDialog(content);
await showDialogAsync(md);
}
public async Task ShowAsync(string content, string caption)
{
var md = new MessageDialog(content, caption);
await showDialogAsync(md);
}
public async Task<MessageDialogResult> ShowAsync(string content, MessageDialogType dialogType)
{
var messageDialogResult = await ShowAsync(content, null, dialogType);
return messageDialogResult;
}
public async Task<MessageDialogResult> ShowAsync(string content, string caption, MessageDialogType dialogType)
{
var result = MessageDialogResult.Ok;
var md = string.IsNullOrEmpty(caption) ? new MessageDialog(content) : new MessageDialog(content, caption);
switch (dialogType)
{
case MessageDialogType.Ok:
md.Commands.Add(new UICommand(ResWrapper.Strings["MessageDialogButtonOk"], command => result = MessageDialogResult.Ok));
md.CancelCommandIndex = 0;
md.DefaultCommandIndex = 0;
break;
case MessageDialogType.OkCancel:
md.Commands.Add(new UICommand(ResWrapper.Strings["MessageDialogButtonOk"], command => result = MessageDialogResult.Ok));
md.Commands.Add(new UICommand(ResWrapper.Strings["MessageDialogButtonCancel"], command => result = MessageDialogResult.Cancel));
md.DefaultCommandIndex = 0;
md.CancelCommandIndex = 1;
break;
case MessageDialogType.YesNo:
md.Commands.Add(new UICommand(ResWrapper.Strings["MessageDialogButtonYes"], command => result = MessageDialogResult.Yes));
md.Commands.Add(new UICommand(ResWrapper.Strings["MessageDialogButtonNo"], command => result = MessageDialogResult.No));
md.DefaultCommandIndex = 0;
md.CancelCommandIndex = 1;
break;
case MessageDialogType.YesNoCancel:
md.Commands.Add(new UICommand(ResWrapper.Strings["MessageDialogButtonYes"], command => result = MessageDialogResult.Yes));
md.Commands.Add(new UICommand(ResWrapper.Strings["MessageDialogButtonNo"], command => result = MessageDialogResult.No));
md.Commands.Add(new UICommand(ResWrapper.Strings["MessageDialogButtonCancel"], command => result = MessageDialogResult.Cancel));
md.DefaultCommandIndex = 0;
md.CancelCommandIndex = 1;
break;
default:
throw new ArgumentOutOfRangeException("dialogType");
}
await showDialogAsync(md);
return result;
}
/// <summary>
/// Shows the dialogs, queued and one after the other.
/// We need this as a workaround for the the UnauthorizedAcsess exception.
/// </summary>
/// <param name="messageDialog">The message dialog.</param>
/// <returns></returns>
async Task showDialogAsync(MessageDialog messageDialog)
{
//Calls this function in a separated task to avoid ui thread deadlocks.
await Task.Run(async () =>
{
lock (_queueMonitor)
{
_dialogQueue.Enqueue(messageDialog);
}
try
{
while (true)
{
MessageDialog nextMessageDialog;
lock (_queueMonitor)
{
if (_dialogQueue.Count > 1)
{
Debug.WriteLine("MessageDialogService.cs | showDialogAsync | Next dialog is waiting for MessageDialog to be accessable!!");
Monitor.Wait(_queueMonitor); //unlock and wait - regains lock after waiting
}
nextMessageDialog = _dialogQueue.Peek();
}
var showing = false;
_dispatcher.Execute(async () =>
{
try
{
lock (_showMonitor)
{
showing = true;
_currentDialogOperation = nextMessageDialog.ShowAsync();
}
await _currentDialogOperation;
lock (_showMonitor)
_currentDialogOperation = null;
}
catch (Exception e)
{
Debug.WriteLine("MessageDialogService.cs | showDialogAsync | " + e);
}
lock (_showMonitor)
{
showing = false;
Monitor.Pulse(_showMonitor); //unlock and wait - regains lock after waiting
}
});
lock (_showMonitor)
{
if (showing)
{
Debug.WriteLine("MessageDialogService.cs | showDialogAsync | Waiting for MessageDialog to be closed!!");
//we must wait here manually for the closing of the dialog, because the dispatcher does not return a waitable task.
Monitor.Wait(_showMonitor); //unlock and wait - regains lock after waiting
}
}
Debug.WriteLine("MessageDialogService.cs | showDialogAsync | MessageDialog was closed.");
return true;
}
}
finally
{
//make sure we leave this in a clean state
lock (_queueMonitor)
{
_dialogQueue.Dequeue();
Monitor.Pulse(_queueMonitor);
}
}
});
}
public void Close(string keyContent="")
{
try
{
if (keyContent.IsNullOrEmpty())
{
lock (_showMonitor)
{
if (_currentDialogOperation == null) return;
_currentDialogOperation.Cancel();
_currentDialogOperation = null;
}
}
else
{
var cancel = false;
lock (_queueMonitor)
{
if (_dialogQueue.Count == 0)
return;
var currentDialog = _dialogQueue.Peek();
Debug.WriteLine("MessageDialogService.cs | Close | {0}", currentDialog.Content);
if (currentDialog.Content == keyContent)
{
cancel = true;
}
}
if (!cancel) return;
lock (_showMonitor)
{
if (_currentDialogOperation == null) return;
_currentDialogOperation.Cancel();
_currentDialogOperation = null;
}
}
}
catch (Exception e)
{
Debug.WriteLine("MessageDialogService.cs | Close | " + e);
}
}
I think I've found it. I had the same problem when creating messageboxes in any other threads besides the main thread.
This is the C++ solution but I think you can convert it easily ;)
IAsyncOperation<IUICommand^> ^Op = msgbox->ShowAsync();
task<IUICommand^>( Op ).then([=](IUICommand^ C)
{
}).then([](task<void> t)
{
try
{
t.get();
}
catch (Platform::Exception ^e)
{
//ERROR!
}
});
On a side note this is the correct way to handle ANY WinRT/Windows 8 Store C++ exception.
You can always use
Execute.OnUIThread( async () => {
...
var dialog = new MessageDialog(yourMessage);
await dialog.ShowAsync();
...
});
This doesn't solve race conditions in the UI if you are trying to launch multiple dialogs from background threads. But you could use a try/catch to make sure you cover for that case.