Suppress navigation while awaiting result on Windows Phone 8.1 - c#

I would like to prevent changing the current page by pressing Back button or any navigation events while awaiting not finished. Because then exception happens, its should shown in the same page, on the other case it would be difficult to understand what action generate this exception
private async void AppBarButton_Click(object sender, RoutedEventArgs e)
{
MessageDialog dialog = null;
try
{
progressRing.IsActive = true;
this.IsEnabled = false;
commandBar1.IsEnabled = false;
await GlobalVars.API.Call(CC.ChangeDate, date);
var notify = new MessageDialog("Done");
await notify.ShowAsync();
}
catch (Exception ex)
{
dialog = new MessageDialog(ex.Message);
}
finally
{
progressRing.IsActive = false;
this.IsEnabled = true;
commandBar1.IsEnabled = true;
}
if (dialog != null) await dialog.ShowAsync(); // must be shown in the same page
}

You can intercept the back button using:
protected override void OnBackKeyPress(System.ComponentModel.CancelEventArgs e)
{
e.Cancel = true;
}
Obviously you can do whatever you want in there.

Related

How to prevent hanging of application when a button is clicked multiple times?

I have an application where user can click on a Scan button to scan the image to preview in the application. When user clicks, usually a "Preparing to scan" message will be shown and goes away when the scan is 100% complete.
The scan works fine. The problem if I stress test it by pressing the scan button many times while it's doing it's work, the application completely hangs and the message just stays there and I had to restart my whole application.
The code: It's just a small section
private void ScanStripButton_Click(object sender, EventArgs e)
{
if (SCAN_INTO_BATCH)
{
GENERATE_BATCH_FOLDER = true;
StartTwainScan();
}
}
Any idea on how to prevent this issue?
Appreciate the help
EDIT:
public void StartTwainScan()
{
Boolean EnableUI = false;
Boolean ADF = false;
Boolean EnableDuplex = false;
if (Properties.Settings.Default.TwainShow.Equals("1"))
{
EnableUI = true;
}
if (Properties.Settings.Default.ScanType.Equals("2"))
{
ADF = true;
}
if (Properties.Settings.Default.DuplexEnable.Equals("1"))
{
EnableDuplex = true;
}
var rs = new ResolutionSettings
{
Dpi = GetResolution(),
ColourSetting = GetColorType()
};
var pg = new PageSettings()
{
Size = GetPageSize()
};
var settings = new ScanSettings
{
UseDocumentFeeder = ADF,
ShowTwainUI = EnableUI,
ShowProgressIndicatorUI = true,
UseDuplex = EnableDuplex,
Resolution = rs,
Page = pg
};
try
{
TwainHandler.StartScanning(settings);
}
catch (TwainException ex)
{
MessageBox.Show(ex.Message);
//Enabled = true;
//BringToFront();
}
}
This isn't going to be the correct answer, but you haven't shown enough code to give you the right code. It should point you in the right direction.
private void ScanStripButton_Click(object sender, EventArgs e)
{
ScanStripButton.Enabled = false;
if (SCAN_INTO_BATCH)
{
GENERATE_BATCH_FOLDER = true;
StartTwainScan();
}
ScanStripButton.Enabled = true;
}
Basically you disable the button when the scan starts and enable it when it finishes.
private async void ScanStripButton_Click(object sender, EventArgs e)
{
await Task.Run(() =>
{
if (SCAN_INTO_BATCH)
{
GENERATE_BATCH_FOLDER = true;
StartTwainScan();
}
});
}
or
private bool clicked = false;
private void ScanStripButton_Click(object sender, EventArgs e)
{
try
{
if(clicked)
return;
clicked = true;
if (SCAN_INTO_BATCH)
{
GENERATE_BATCH_FOLDER = true;
StartTwainScan();
}
}
finally
{
clicked = false;
}
}

e.Cancel cannot be set after awaiting async dialog in UWP

This is for a Windows 10 UWP app. When the user tries to navigate away from a page, I want to have the user confirm if he wants to save the current data.
I have overridden OnNavigatingFrom as shown below. However, after the async MessageDialog, setting e.Cancel=false doesn't work. The page still stays on the current page even e.Cancel is later set to false. Please help!
protected override async void OnNavigatingFrom(NavigatingCancelEventArgs e)
{
e.Cancel = true; //if I don't put this at the top, the page navigates right away
var yesCommand = new UICommand("Yes", async cmd => {
try
{
await SaveWorkshetItem(false);
e.Cancel = false;
}
catch (Exception ex)
{
await new MessageDialog("Error saving Worksheet Item. Please contact you administrator." + ex.Message + Environment.NewLine + ex.StackTrace).ShowAsync();
}
});
var noCommand = new UICommand("No", cmd => { e.Cancel = false; });
var cancelCommand = new UICommand("Cancel", cmd => { e.Cancel = true; });
var dialog = new MessageDialog("Do you want to save the current item before navigating away?");
dialog.Options = MessageDialogOptions.None;
dialog.Commands.Add(yesCommand);
dialog.Commands.Add(noCommand);
dialog.Commands.Add(cancelCommand);
await dialog.ShowAsync();
base.OnNavigatingFrom(e);
}
To simplify this the below code causes the page to never leave even though I am changing back e.Cancel=false after the sample MessageDialog.
protected override async void OnNavigatingFrom(NavigatingCancelEventArgs e)
{
e.Cancel = true; //if I don't put this at the top, the page navigates right away
await new MessageDialog("Do you want to save the current item before navigating away?").ShowAsync();
e.Cancel = false; //unconditionally setting this back to false and it still won't leave the page
base.OnNavigatingFrom(e);
}
To handle the navigation yourself, set Cancel=true (as you already do), then bring up the dialog to obtain user input. Once you know the user's choice, use the navigation APIs (e.g. Frame.GoBack) to perform the desired navigation (based on e.NavigationMode) if the user decided to allow the navigation to happen.
Here is some basic sample code:
private bool isNavigationConfirmed = false;
protected async override void OnNavigatingFrom(NavigatingCancelEventArgs e)
{
base.OnNavigatingFrom(e);
if (isNavigationConfirmed)
{
isNavigationConfirmed = false;
return;
}
e.Cancel = true;
var noCommand = new UICommand("No", cmd => { });
var yesCommand = new UICommand("Yes", cmd =>
{
if (e.NavigationMode == NavigationMode.Back)
{
Frame.GoBack();
}
else
{
isNavigationConfirmed = true;
Frame.Navigate(e.SourcePageType);
}
});
var dialog = new MessageDialog("Do you want to allow navigation?");
dialog.Options = MessageDialogOptions.None;
dialog.Commands.Add(yesCommand);
dialog.Commands.Add(noCommand);
await dialog.ShowAsync();
}

Xamarin.Forms setting IsVisible doesn't trigger before function is done.

In my Xamarin.Forms project I have a login form that logs in the user and then redirects them to another page. I want to show an ActivityIndicator while it attempts to login, but setting IsVisible to true doesn't actually take effect before the login function is done. My code looks like this:
void OnLoginButtonClicked(object sender, EventArgs e)
{
LoadingIndicator.IsVisible = true;
Login();
}
public void Login()
{
var user = new User
{
Email = usernameEntry.Text,
Password = passwordEntry.Text
};
User validUser = AreCredentialsCorrect(user);
if (validUser != null)
{
Navigation.PushAsync(new ProfilePage());
}
else
{
messageLabel.Text = "Login failed";
passwordEntry.Text = string.Empty;
//It will only show the LoadingIndicator at this point.
}
}
If the user is correct, it never shows the LoadingIndicator because it navigates to another page before it can show it.
If the user is invalid, it will only show the LoadingIndicator after it hits the else clause and shows the "Login failed". Can anyone figure why that is, and what I can do to fix it?
Use Async calls and await the main block of operations. If anything you want to update/change in UI, do it using BeginInvokeOnMainThread.
void OnLoginButtonClicked(object sender, EventArgs e)
{
LoadingIndicator.IsVisible = true;
await Login();
}
public async void Login()
{
await Task.Run(() => {
var user = new User
{
Email = usernameEntry.Text,
Password = passwordEntry.Text
};
User validUser = AreCredentialsCorrect(user);
}).ContinueWith((a) => SomeMethod(validUser));
}
public void SomeMethod()
{
Device.BeginInvokeOnMainThread(() =>
if (validUser != null)
{
Navigation.PushAsync(new ProfilePage());
}
else
{
messageLabel.Text = "Login failed";
passwordEntry.Text = string.Empty;
//It will only show the LoadingIndicator at this point.
}
}
}
Try using async/await. Allow the UI to update while also navigating.
async void OnLoginButtonClicked(object sender, EventArgs e)
{
LoadingIndicator.IsVisible = true;
await Login();
}
public async Task Login()
{
var user = new User
{
Email = usernameEntry.Text,
Password = passwordEntry.Text
};
User validUser = AreCredentialsCorrect(user);
if (validUser != null)
{
await Navigation.PushAsync(new ProfilePage());
}
else
{
messageLabel.Text = "Login failed";
passwordEntry.Text = string.Empty;
//It will only show the LoadingIndicator at this point.
}
}
Two possible explanations here one it could be redirecting so fast that it doesn't have time to display the loadingindicator, I have experienced this problem before. We had a really nice loading symbol and animation but then we switched to Aurelia framework and it logs in so fast it just doesn't have time to display it even though it was actually working. As for code changes I would try to add it into the login function as well at least for right now to give some clarity to if its actually just logging in so fast its not displayed or its just not displaying at all. Her is my suggestion.
void OnLoginButtonClicked(object sender, EventArgs e)
{
LoadingIndicator.IsVisible = true;
Login(LoadingIndicator.IsVisible);
}
public void Login(Bool IsVisible)<--- might have type wrong not familiar with you custom defines types I would expect it to be a bool though.
IsVisible = true;
{
var user = new User
{
IsVisible = true;
Email = usernameEntry.Text,
Password = passwordEntry.Text
};
User validUser = AreCredentialsCorrect(user);
if (validUser != null)
{
IsVisible = true;
Navigation.PushAsync(new ProfilePage());
}
else
{
IsVisible = true;
messageLabel.Text = "Login failed";
passwordEntry.Text = string.Empty;
//It will only show the LoadingIndicator at this point.
}
}
If nothing else this might help clarify why it isn't being displayed. Also don't forget to use the web debugger f12 by default on most browsers and look for the element that will contain the Indicator.
Hope this helps! If not let me know and I'll remove the answer(I had to use an answer because I can't comment under 50 rep) Cheers!

MessageDialog confirmation does not work in Windows 10 Mobile but works in Windows 10

I want to ask for confirmation if the user wants to leave the page when the Back button (hardware or AppViewBackButton) is pressed using the following code in my App.xaml.cs
protected override void OnLaunched(LaunchActivatedEventArgs e)
{
...
SystemNavigationManager.GetForCurrentView().BackRequested += OnBackRequested;
...
}
Private async void OnBackRequested(object sender, BackRequestedEventArgs e)
{
Frame rootFrame = Window.Current.Content as Frame;
if (rootFrame.Content.GetType() == typeof(GamePage))
{
var op = await ShowAsync("Do you want to exit?", "Exit?");
if (op == MessageBoxResult.OK)
{
rootFrame.GoBack();
e.Handled = true;
}
}
else
{
if (rootFrame.CanGoBack)
{
e.Handled = true;
rootFrame.GoBack();
}
}
}
public async Task<MessageBoxResult> ShowAsync(string messageBoxText, string caption)
{
MessageBoxResult result = MessageBoxResult.None;
MessageDialog md = new MessageDialog(messageBoxText, caption);
md.Commands.Add(new UICommand("OK",
new UICommandInvokedHandler((cmd) => result = MessageBoxResult.OK)));
md.Commands.Add(new UICommand("Cancel",
new UICommandInvokedHandler((cmd) => result = MessageBoxResult.Cancel)));
md.CancelCommandIndex = (uint)md.Commands.Count - 1;
var op = await md.ShowAsync();
return result;
}
The problem is var op = await md.ShowAsync(); does not await the result. The app showed the dialog briefly and without waiting for any input, just close the app.
I do not have my Windows 10 Mobile device to test at the moment so I am testing with the emulator. Is the problem with the emulator or the code?
This code works fine on my desktop though.

"InvalidOperationException: A method was called at an unexpected time" when calling MediaCapture.StartPreviewAsync

I'm trying to start and stop a MediaCapture preview for the camera in a Windows 8.1 Universal app. In the OnNavigatedTo method, I have the following code:
protected override async void OnNavigatedTo(NavigationEventArgs e)
{
var scanItemsParameter = e.Parameter as ScanItemParameter;
if (scanItemsParameter != null)
{
((ScanItemViewModel)DataContext).ScanCallback = scanItemsParameter.ScanCallback;
}
try
{
HardwareButtons.CameraPressed += HardwareButtonsOnCameraPressed;
HardwareButtons.CameraHalfPressed += HardwareButtonsOnCameraHalfPressed;
DisplayInformation.GetForCurrentView().OrientationChanged += OnOrientationChanged;
if (!_mediaInitialized)
{
var cameras = await DeviceInformation.FindAllAsync(DeviceClass.VideoCapture);
if (cameras.Count < 1)
{
return;
}
MediaCaptureInitializationSettings settings;
settings = new MediaCaptureInitializationSettings
{
VideoDeviceId = cameras[0].Id,
PhotoCaptureSource = PhotoCaptureSource.Photo
};
await _mediaCapture.InitializeAsync(settings);
VideoCapture.Source = _mediaCapture;
_mediaInitialized = true;
}
SetOrientation(DisplayInformation.GetForCurrentView().CurrentOrientation);
await _mediaCapture.StartPreviewAsync();
await _mediaCapture.VideoDeviceController.ExposureControl.SetAutoAsync(true);
if (_mediaCapture.VideoDeviceController.FocusControl.FocusChangedSupported)
{
var focusSettings = new FocusSettings();
focusSettings.AutoFocusRange = AutoFocusRange.Normal;
focusSettings.Mode = FocusMode.Auto;
focusSettings.WaitForFocus = true;
focusSettings.DisableDriverFallback = false;
_mediaCapture.VideoDeviceController.FocusControl.Configure(focusSettings);
}
_mediaCapture.VideoDeviceController.FlashControl.Auto = true;
}
catch (Exception ex)
{
var ex2 = ex;
throw;
}
}
In the OnNavigatingFrom method, I am cleaning up some event handlers and calling MediaCapture.StopPreviewAsync():
protected override async void OnNavigatingFrom(NavigatingCancelEventArgs e)
{
await _mediaCapture.StopPreviewAsync();
HardwareButtons.CameraPressed -= HardwareButtonsOnCameraPressed;
HardwareButtons.CameraHalfPressed -= HardwareButtonsOnCameraHalfPressed;
DisplayInformation.GetForCurrentView().OrientationChanged -= OnOrientationChanged;
}
The call works correctly the first time I open the page, but if I navigate away from the page and come back, I get an InvalidOperationException. What am I missing?
As a note, I'm using MVVM light, if that makes any difference...
Thanks in advance for any help...
I was able to resolve this by disposing of the MediaCapture element before navigating away from the page, and re-instantiating it upon returning to the page.
In the OnNavigatingFrom method, I added _mediaCapture.Dispose(); and _mediaCapture = null;:
protected override async void OnNavigatingFrom(NavigatingCancelEventArgs e)
{
if (_mediaCapture != null)
{
await _mediaCapture.StopPreviewAsync();
_mediaCapture.Dispose();
_mediaCapture = null;
}
HardwareButtons.CameraPressed -= HardwareButtonsOnCameraPressed;
HardwareButtons.CameraHalfPressed -= HardwareButtonsOnCameraHalfPressed;
DisplayInformation.GetForCurrentView().OrientationChanged -= OnOrientationChanged;
}
Then, just before the _mediaCapture.InitializeAsync() call in OnNavigatedTo, I instantiate a new one:
//...
_mediaCapture = new MediaCapture();
//...

Categories

Resources