Showing MessageDialogs one after another in WindowsStoreApps using c# - c#

In WindowsStoreApps I have three MessageDialogs which have to be showed one bye one by clicking a button in each MessageDialog.While doing this I get an 'System.UnauthorizedAccessException'.It seems we cant open another messageDialog while one is open.Is there a possiblity to close the previous dialog while opening the next one? or Can any one suggest me an idea how to handle this issue.
MessageDialog md = new MessageDialog("Have you been enjoying your experience with " + Modules.Title + " ?");
UICommand btn_ntreally = new UICommand("Not Really");
md.Commands.Add(btn_ntreally);
btn_ntreally.Invoked += btn_ntreally_invoked;
UICommand btn_yeah = new UICommand("Yeah!");
md.Commands.Add(btn_yeah);
btn_yeah.Invoked += btn_yeah_invoked;
md.ShowAsync();
I get system.unauthorised exception messagedialog.showasync.
private async void btn_yeah_invoked(IUICommand command)
{
MessageDialog md = new MessageDialog("Deal is deal");
UICommand btn_Sure_invoked = new UICommand("Sure");
md.Commands.Add(btn_Sure_invoked);
btn_ntreally.Invoked += btn_Sure_invoked;
UICommand btn_yeah = new UICommand("No thanks!");
md.Commands.Add(btn_tnks);
await md.ShowAsync(); //getting system.UnauthorizedAccessException here
}
private async void btn_Sure_invoked(IUICommand command)
{
UICommand btn_rateAppsure = new UICommand("Yes!");
md.Commands.Add(btn_rateAppsure);
btn_rateAppsure.Invoked += btn_rateAppsure_invoked;
UICommand btn_rateNothanks = new UICommand("No.Thanks");
md.Commands.Add(btn_rateNothanks);
await md.ShowAsync(); //getting system.UnauthorizedAccessException here
}

The MessageDialog is intended to block all other activities in your app and force the user to respond to the action your request from him. So it doesn't seem logical to fire 3 messagedialogs at the same time. That's most likely the reason your getting the exception.
Because your code sample isn't that clear about what you're trying to achieve with the 3 messagedialogs, I'll come up with some approaches that you might like:
1
Show a custom kind of message dialog where you use viewstates to differentiate the different questions that the user has to answer before he can continue.
2
Show a messagedialog where all 3 questions are shown and multiple buttons to answer the variants?
The last one isn't the nicest solution. If you eloborate a bit on what you exactly trying to achieve maybe we can come up with some better solutions to fix your problem.

If you really want this use this pattern (which I don't really recommend), you can set a timer to call you some time after the dialog has been closed, and then you will be able to call another dialog to open.

Related

Can I make a ContentDialog.Async() await another ContentDialog.Async() in UWP?

I'm running an UWP app with 2 pages. In MainPage I start a ContentDialog Async method which opens page2 in a frame. In page2 I have a secondary ContentDialog which I open by pressing a button.
In the Button_Click method I want to close the running Async() method and await to start the next one until I am 100% sure the first one is closed.
The problem I encounter now is that the program crashes if I press the secondary ContentDialog's buttons too fast after it opens.
I've tried thread sleeping but that only delays the problem.
Mainpage(CustomerInfoPage):
transactionContent = new ContentDialog();
Frame transactionFrame = new Frame();
transactionFrame.Navigate(typeof(TransactionPage), selectedAccount);
transactionContent.Content = transactionFrame;
transactionContent.ShowAsync();
Page2(TransactionPage):
private async void DepositButton_ClickAsync(object sender, RoutedEventArgs e)
{
CustomerInfoPage.transactionContent.Hide();
ContentDialog confirmationDialog = new ContentDialog
{
Title = "Deposit Funds.",
Content = $"You will deposit {depositTextBox.Text} SEK.\nYour new balance will be: {ReceivedAccount.Balance + deposit} SEK",
PrimaryButtonText = "CONFIRM",
SecondaryButtonText = "CANCEL"
};
confirmationDialog.PrimaryButtonClick += ConfirmationDialog_PrimaryButtonClick;
await confirmationDialog.ShowAsync();
async void ConfirmationDialog_PrimaryButtonClick(ContentDialog _sender, ContentDialogButtonClickEventArgs args)
{
confirmationDialog.Hide();
}
CustomerInfoPage.transactionContent.ShowAsync();
}
So this works as long as you don't call the ConfirmationDialog_PrimaryButtonClick too fast by clicking on it instantly after it is opened.
This is introduced in the UWP documentation about Dialog.
There can only be one ContentDialog open per thread at a time. Attempting to open two ContentDialogs will throw an exception, even if they are attempting to open in separate AppWindows.
So you can't start the second CotnentDialog while the first ContentDialog is still running.
Best regards.
As #Richard Zhang - MSFT said in previous answer
So you can't start the second CotnentDialog while the first
ContentDialog is still running.
If you wish to close the ContentDialog from previous page right before opening new ContentDialog you can use the code from below which will close any ContentDialog which is currently open.
var openedpopups = VisualTreeHelper.GetOpenPopups(Window.Current);
foreach (var popup in openedpopups)
{
if(popup.Child is ContentDialog)
{
(popup.Child as ContentDialog).hide();
}
}

Form is displaying before async function completes

I've got a WinForms project that scans a given network and returns valid IP addresses. Once all the addresses are found, I create a user control for each and place it on the form. My functions to ping ip addresses use async and Task which I thought would "wait" to execute before doing something else, but it doesn't. My form shows up blank, then within 5 seconds, all the user controls appear on the form.
Declarations:
private List<string> networkComputers = new List<string>();
Here's the Form_Load event:
private async void MainForm_Load(object sender, EventArgs e)
{
//Load network computers.
await LoadNetworkComputers();
LoadWidgets();
}
The LoadNetworkComputers function is here:
private async Task LoadNetworkComputers()
{
try
{
if (SplashScreenManager.Default == null)
{
SplashScreenManager.ShowForm(this, typeof(LoadingForm), false, true, false);
SplashScreenManager.Default.SetWaitFormCaption("Finding computers");
}
else
Utilities.SetSplashFormText(SplashForm.SplashScreenCommand.SetLabel, "Scanning network for computers. This may take several minutes...");
networkComputers = await GetNetworkComputers();
}
catch (Exception e)
{
MessageBox.Show(e.Message + Environment.NewLine + e.InnerException);
}
finally
{
//Close "loading" window.
SplashScreenManager.CloseForm(false);
}
}
And the last 2 functions:
private async Task<List<string>> GetNetworkComputers()
{
networkComputers.Clear();
List<string> ipAddresses = new List<string>();
List<string> computersFound = new List<string>();
for (int i = StartIPRange; i <= EndIPRange; i++)
ipAddresses.Add(IPBase + i.ToString());
List<PingReply> replies = await PingAsync(ipAddresses);
foreach(var reply in replies)
{
if (reply.Status == IPStatus.Success)
computersFound.Add(reply.Address.ToString());
}
return computersFound;
}
private async Task<List<PingReply>> PingAsync(List<string> theListOfIPs)
{
var tasks = theListOfIPs.Select(ip => new Ping().SendPingAsync(ip, 2000));
var results = await Task.WhenAll(tasks);
return results.ToList();
}
I'm really stuck on why the form is being displayed before the code in the MainForm_Load event finishes.
EDIT
I forgot to mention that in the LoadNetworkComputers it loads a splash form which lets the user know that the app is running. It's when the form shows up behind that, that I'm trying to avoid. Here's a screenshot (sensitive info has been blacked out):
The reason one would use async-await is to enable callers of functions to continue executing code whenever your function has to wait for something.
The nice thing is that this will keep your UI responsive, even if the awaitable function is not finished. For instance if you would have a button that would LoadNetworkComputers and LoadWidgets you would be glad that during this relatively long action your window would still be repainted.
Since you've defined your Mainform_Loadas async, you've expressed that you want your UI to continue without waiting for the result of LoadNetWorkComputers.
In this interview with Eric Lippert (search in the middle for async-await) async-await is compared with a a cook making dinner. Whenever the cook finds that he has to wait for the bread to toast, he starts looking around to see if he can do something else, and starts doing it. After a while when the bread is toasted he continues preparing the toasted bread.
By keeping the form-load async, your form is able to show itself, and even show an indication that the network computers are being loaded.
An even nicer method would be to create a simple startup-dialog that informs the operator that the program is busy loading network computers. The async form-load of this startup-dialog could do the action and close the form when finished.
public class MyStartupForm
{
public List<string> LoadedNetworkComputers {get; private set;}
private async OnFormLoad()
{
// start doing the things async.
// keep the UI responsive so it can inform the operator
var taskLoadComputers = LoadNetworkComputers();
var taskLoadWidgets = LoadWidgets();
// while loading the Computers and Widgets: inform the operator
// what the program is doing:
this.InformOperator();
// Now I have nothing to do, so let's await for both tasks to complete
await Task.WhenAll(new Task[] {taskLoadComputers, taskLoadWidgets});
// remember the result of loading the network computers:
this.LoadedNetworkComputers = taskLoadComputers.Result;
// Close myself; my creator will continue:
this.Close();
}
}
And your main form:
private void MainForm_Load(object sender, EventArgs e)
{
// show the startup form to load the network computers and the widgets
// while loading the operator is informed
// the form closes itself when done
using (var form = new MyStartupForm())
{
form.ShowDialog(this);
// fetch the loadedNetworkComputers from the form
var loadedNetworkComputers = form.LoadedNetworkComputers;
this.Process(loadedNetworkComputers);
}
}
Now while loading, instead of your mainform the StartupForm is shown while the items are loaded.. The operator is informed why the main form is not showing yet. As soon as loading is finished, the StartupForm closes itself and loading of the main form continues
My form shows up blank, then within 5 seconds, all the user controls appear on the form.
This is by design. When the UI framework asks your app to display a form, it must do so immediately.
To resolve this, you'll need to decide what you want your app to look like while the async work is going on, initialize to that state on startup, and then update the UI when the async work completes. Spinners and loading pages are a common choice.

How to detect call hang up in windows phone 10

I want to programmatically detect when call hang up in UWP app for windows phone 10.
I see Caller ID sample and see Communication blocking and filtering sample too.
But I don't find simple solution for detect when call hang up. I found CallHistoryChanged trigger and I think my complex solution is read call history when call history changed trigger and get last incoming call.
Is there any simple solution for detect call hang up?
Is my solution is correct?
Is there a better solution than my solution?
Is there any simple solution for detect call hang up?
Is my solution is correct? Is there a better solution than my solution?
As far as I know, there is no other simple solution for detect calls' hang up.
There is an event PhoneCallManager.CallStateChanged, which can also detect hang up like below:
private bool callCame = false;
PhoneCallManager.CallStateChanged += PhoneCallManager_CallStateChanged;
private async void PhoneCallManager_CallStateChanged(object sender, object e)
{
if (callCame&&(!PhoneCallManager.IsCallActive))
{
//do something
}
if (PhoneCallManager.IsCallIncoming)
{
callCame = true;
}
}
But I don't think it's better than CallHistoryChanged trigger. And it won't get you the last Hang up phone's number either.
Is my solution is correct?
So yes, your solution is correct.
Update: There is no trick here. Register the BackgroundTask:
private void btnClick_Click(object sender, RoutedEventArgs e)
{
var taskRegistered = false;
var exampleTaskName = "MyBackgroundTask";
foreach (var task in BackgroundTaskRegistration.AllTasks)
{
if (task.Value.Name == exampleTaskName)
{
taskRegistered = true;
break;
}
}
if (!taskRegistered)
{
var builder = new BackgroundTaskBuilder();
builder.Name = exampleTaskName;
builder.TaskEntryPoint = "PhoneCallBackground.Class1";
builder.SetTrigger(new PhoneTrigger(Windows.ApplicationModel.Calls.Background.PhoneTriggerType.CallHistoryChanged, false));
builder.Register();
}
}
And don't forget to register it in the appxmanifest file:
The Run Method will be fired after you hang up, if you registered the BackgroundTask. PhoneCallManager can not be registered for BackgroundTask. You need to set it as the default PhoneCall App, if you want to use this.
Update2:
I checked the demo, you are still using PhoneTriggerType.CallOriginDataRequest to register the background task. Please change it to PhoneTriggerType.CallHistoryChanged. And also make sure the registered background task is unregistered after you making any change to your codes.
Here is the demo that I modified: CallHistoryChangeTest.

Locked Controls during Special Process

I wrote a function that download something like a pic from net , and use it
in a click event of special button.
my problem is when i click on button and the app start downloading pic from
internet , all of my controls in form , lock (until download process is done!)
not just only controls , all of my form too.
so how can i handle this process in background of application and the
user can work with other control at Same time.
All you need is asynchronous programming
here is a very simple demo
private async void button1_Click(object sender, EventArgs e)
{
this.Text = "doing something...";
var result = await SomeHeavyWork();
this.Text = result.ToString();
}
private async Task<int> SomeHeavyWork()
{
using (var hc = new HttpClient())
{
var data = await hc.GetAsync("www.google.com");
return data.Content.Headers.Count();
}
}
What's happening here?
when you click button1, button1_Click will execute.
it first set the form text to "doing something..."
it now waits for SomeHeavyWork() to complete its work.
we are now exiting button1_Click function and do what we were doing before clicking button1(running the form message loop). but somewhere else we execute SomeHeavyWork() and waiting for it.
when SomeHeavyWork() job is finished we came back to button1_Click and execute the this.Text = result.ToString(); line.
please read this msdn article

Issue with Async / Await method along with Choosers and Launchers

I added a the following extension method for photo chooser task and camera chooser task.
public static Task<TTaskEventArgs> ShowAsync<TTaskEventArgs>(this ChooserBase<TTaskEventArgs> chooser) where TTaskEventArgs : TaskEventArgs
{
var taskCompletionSource = new TaskCompletionSource<TTaskEventArgs>();
EventHandler<TTaskEventArgs> completed = null;
completed = (s, e) =>
{
chooser.Completed -= completed;
taskCompletionSource.SetResult(e);
};
chooser.Completed += completed;
chooser.Show();
return taskCompletionSource.Task;
}
And I invoked this method in my button click like this,
var photoResult = await new PhotoChooserTask().ShowAsync();
if (photoResult.TaskResult == TaskResult.OK)
{
// set the photo to image source.
}
After adding this every thing is working fine, But my issue is that while the time of invoking task by setting tombstone mode on, The code after my await is not executing (ie the completed event). How i can tackle this situation, I am expecting an answer that solve my issue on the above mentioned implementation(async / await). Not expecting the answer of registering event in the constructor.
I see you're following my article for this, it just turns out I forgot that my current solution doesn't work for tombstoning, as pointed out by someone in the article comments.
I'm preparing a fix for this, and I'll update the thread once I got it ready!

Categories