Call MessageDialog from Property Changed handler Store App - windows-8

I'm trying to call a MessageDialog out of a PropertyChanged Handler. The first call is always successful, but when the Dialog gets called a second time, I get an UnauthorizedAccessException.
I've tried to wrap the call in a Dispatcher, but I got the same behavior.
Here's the code (snippet of MainPage.xaml.cs):
void PropertyChanged(object sender, PropertyChangedEventArgs e)
{
await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
{
showMessage("Message", "Title");
});
}
async void showMessage(String message, String title)
{
MessageDialog dialog = new MessageDialog(message, title);
await dialog.ShowAsync();
}
Could anybody please help me with this issue?

I think your problem is that multiple property changes will cause multiple calls to display the dialog. You should only ever display one dialog at a time:
bool _isShown = false;
async void showMessage(String message, String title)
{
if (_isShown == false)
{
_isShown = true;
MessageDialog dialog = new MessageDialog(message, title);
await dialog.ShowAsync();
_isShown = false;
}
}

Related

ObjectDisposedException on scrollview renderer

I am firing the following event in my Xamarin application:
AppEvents.Instance.UI.RiseSearchStringTypingEvent(this, new EventArgs());
The HomePage.xaml.cs codebehind subscriber-event performs an auto scroll to top every time the event is being fired (on every input on the search field)
void OnSearchStringTyping(object sender, EventArgs e)
{
scrollView.ScrollToAsync(0.0, 0.0, true);
}
when the searchstring is complete and the user hits the submit-button, the Oncompleted() method invokes on the SearchHeaderView.xaml.cs which navigates to the SearchPage
void OnCompleted(object sender, EventArgs e)
{
var tag = this + ".OnCompleted";
try
{
if (string.Compare(LastSearchText, SearchEntry.Text) == 0) return
if (Device.RuntimePlatform == Device.Android)
{
SearchRequest();
}
else if (Device.RuntimePlatform == Device.iOS)
{
var task = new Task(SearchRequest);
task.Start();
}
LastSearchText = SearchEntry.Text;
}
catch (Exception ex)
{
Track.Exception(tag, ex);
}
}
This procedure works perfect on iOS platforms...But in android, when i submit my search string, the app crashes with an ObjectDisposedException on the ScrollView
I think the problem is that the application tries to scroll up the view again after it navigates away from the homepage. The SearchRequest() method on Android is not invoked in a new Thread, but iOS is. How can i fix this? I can not just make the method being invoked asynchronously, because the Search doesn't work then.

Where to call async GetDataFromServer in Xamarin.Forms?

Where would be the best place to call GetDataFromServer method?
My gut feeling and reason say it belongs in the repository, but I've no clue where to call it. I've tried to call it in the constructor, but that didn't work out too well. It had issues with it being an async method.
public class SQLiteRepository : ISQLiteRepository
{
private HttpClient _httpClient = new HttpClient();
private readonly SQLiteAsyncConnection _efContext;
public SQLiteRepository()
{
_efContext = DependencyService.Get<ISQLiteDb>().GetAsyncConnection();
_efContext.CreateTableAsync<EfPartner>();
}
public async Task<IEnumerable<EfPartner>> GetAllPartnersAsync()
{
try
{
var partners = await _efContext.Table<EfPartner>().ToListAsync();
return partners;
}
catch (Exception ex)
{
throw ex;
}
}
public async Task GetDataFromServerAsync()
{
try
{
var partners = await GetPartnersFromServerAsync();
var companies = await GetCompaniesFromServerAsync();
await _efContext.InsertAllAsync(partners);
}
catch (Exception ex)
{
throw ex;
}
}
private async Task<IEnumerable<EfPartner>> GetPartnersFromServerAsync()
{
try
{
var jsonObject = await _httpClient.GetStringAsync(Constants.PartnersUrl);
var dotNetObject = JsonConvert.DeserializeObject<List<EfPartner>>(jsonObject);
return new List<EfPartner>(dotNetObject);
}
catch (Exception ex)
{
throw ex;
}
}
private async Task<IEnumerable<EfCompany>> GetCompaniesFromServerAsync()
{
try
{
var jsonObject = await _httpClient.GetStringAsync(Constants.CompaniesUrl);
var dotNetObject = JsonConvert.DeserializeObject<List<EfCompany>>(jsonObject);
return new List<EfCompany>(dotNetObject);
}
catch (Exception ex)
{
throw ex;
}
}
}
I called the GetDataFromServerAsync from PartnersListPage.xaml.cs -> which feels wrong.
I'd appreciate any help.
Thank you.
============================ UPDATE ============================
The app I'm working on creates the pages in a MasterDetailPage like so:
private void MenuListView_ItemSelected(object sender, SelectedItemChangedEventArgs e)
{
if (e.SelectedItem == null)
return;
var menuItem = e.SelectedItem as EfMenuItem;
if (menuItem == null)
return;
var page = (Page)Activator.CreateInstance(menuItem.TargetPage);
page.Title = menuItem.Title;
Detail = new NavigationPage(page);
IsPresented = false;
MdpMasterPage.MenuListView.SelectedItem = null;
}
And here is the PartnersListPage.xaml.cs, from where is GetDataFromServer called at the moment:
public partial class PartnersListPage : ContentPage
{
private readonly SQLiteRepository _repo;
public PartnersListPage()
{
InitializeComponent();
_repo = new SQLiteRepository();
}
protected override async void OnAppearing()
{
await _repo.GetDataFromServerAsync();
var partners = await _repo.GetAllPartnersAsync();
InitializeGrid(partners);
base.OnAppearing();
}
This is an important topic related to MVVM, what you are doing is "correct" but it may have issues later on once your application grow bigger, let's imaging this scenario:
The user is a desperate one and he/she wants to Navigate on your app real fast, he/she open this specific page 5 or 10 times, what will happen then?
Your OnAppearing() method will be called every time the user lands on this page and a new thread will be created for instance your application will start to behave poorly on the performance part. (Specially on Android).
So my suggestion will be to use an MVVM framework to handle those cases based on the pattern, here is a small tutorial using Prism:
https://xamgirl.com/prism-in-xamarin-forms-step-by-step-part-1/
And in regards of your question, your UI ListView specifically your ItemSource (If you are using a ListView) property should be binded to your GetAllPartnersAsync() return type.
If that is not the case and based on the context I suppose InitializeGrid(partners); is creating cells for a Grid in your XAML class so I suppose you can debug step by step if the UI is being created correctly. A Grid does not have an ItemSource property
If you want to have a Grid with an ItemSource property I suggest you sue this ones:
https://github.com/Manne990/XamTest
https://github.com/daniel-luberda/DLToolkit.Forms.Controls/tree/master/FlowListView

The video recording device is preempted by another immersive application

Am I opening the camera for taking a picture, but the user has the possibility to stop the camera if he no longer wants to capture something, so I have a close button which is intended to close the camera, so that the camera preview should be stopped.
If I open the camera, close, open again, I will get the following exception once the close button is clicked for the second time:
System.Runtime.InteropServices.COMException: 'The video recording device is preempted by another immersive application.
I do not know, how the preview camera should be stopped, more than UWP docs say here: https://learn.microsoft.com/en-us/windows/uwp/audio-video-camera/simple-camera-preview-access
The code for stopping the camera preview:
private async Task CleanupCameraAsync()
{
if (_mediaCapture != null)
{
if (_isPreviewing)
{
await _mediaCapture.StopPreviewAsync();
}
await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
CameraPreviewControl.Source = null;
if (_displayRequest != null)
{
_displayRequest.RequestRelease();
}
_mediaCapture.Dispose();
});
}
}
I tried to test your code snippet on my side and it can work well. I didn't get the above exception. I tested on the emulator build 15063 and build 14393. Since your code snippet is not the completed code, so I created a minimal project for testing as follows which can work well on my side. You may test it on your side and compare with your code if something wrong with your project.
XAML
<StackPanel Background="{ThemeResource ApplicationPageBackgroundThemeBrush}" Padding="30">
<CaptureElement Name="PreviewControl" Stretch="Uniform"/>
<Button x:Name="btnpreview" Click="btnpreview_Click" Content="preview test"></Button>
<Button x:Name="btnstop" Click="btnstop_Click" Content="stop"></Button>
</StackPanel>
Code behind
private DeviceInformation _cameraDevice;
private MediaCapture _mediaCapture;
private InMemoryRandomAccessStream _ras;
private LowLagMediaRecording _recording;
private CameraRotationHelper _rotationHelper;
private readonly DisplayRequest _displayRequest = new DisplayRequest();
private bool _isPreviewing;
public MainPage()
{
this.InitializeComponent();
}
private async void btnstop_Click(object sender, RoutedEventArgs e)
{
if (_mediaCapture != null)
{
if (_isPreviewing)
{
await _mediaCapture.StopPreviewAsync();
_isPreviewing = false;
await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
PreviewControl.Source = null;
if (_displayRequest != null)
{
_displayRequest.RequestRelease();
}
_mediaCapture.Dispose();
});
}
}
}
private async void btnpreview_Click(object sender, RoutedEventArgs e)
{
try
{
_mediaCapture = new MediaCapture();
var allVideoDevices = await DeviceInformation.FindAllAsync(DeviceClass.VideoCapture);
var desiredDevice = allVideoDevices.FirstOrDefault(x => x.EnclosureLocation != null && x.EnclosureLocation.Panel == Windows.Devices.Enumeration.Panel.Back);
_cameraDevice = desiredDevice ?? allVideoDevices.FirstOrDefault();
_rotationHelper = new CameraRotationHelper(_cameraDevice.EnclosureLocation);
_mediaCapture.Failed += MediaCapture_Failed;
var settings = new MediaCaptureInitializationSettings { VideoDeviceId = _cameraDevice.Id };
await _mediaCapture.InitializeAsync(settings);
PreviewControl.Source = _mediaCapture;
_displayRequest.RequestActive();
await _mediaCapture.StartPreviewAsync();
_isPreviewing = true;
}
catch (UnauthorizedAccessException)
{
// This will be thrown if the user denied access to the camera in privacy settings
System.Diagnostics.Debug.WriteLine("The app was denied access to the camera");
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine("MediaCapture initialization failed. {0}", ex.Message);
}
}
If you still have issues, please provide a minimal reproduced project and the testing environment information. More details please reference the official sample.

MessageDialog in Windows 8 xaml

My Code:
MessageDialog msg = new MessageDialog("Are you sure to cancel the booking?", "Confirmation");
msg.Commands.Add(new UICommand("Confirm", new UICommandInvokedHandler(CommandHandler)));
msg.Commands.Add(new UICommand("Cancel", new UICommandInvokedHandler(CommandHandler)));
msg.DefaultCommandIndex = 1;
msg.CancelCommandIndex = 1;
await msg.ShowAsync();
private async void CommandHandler(IUICommand command)
{
var commandLabel = command.Label;
switch (commandLabel)
{
case "Confirm":
CancelBookingTickets();
break;
case "Cancel":
break;
}
}
protected async void CancelBookingTickets()
{
MessageDialog msg1 = new MessageDialog("The cancellation process is complete", "Complete");
await msg1.ShowAsync();
}
I am trying to use the nested MessageDialog box in my Windows 8 xaml app but when I reach to the msg1.ShowAsync(), it fires an exception saying "Access is denied".
Can anybody help me out with this problem?
You are facing problem of multiple MessageDialog at once.
How to allow for multiple popups at once in WinRT?

Error in Windows 8 xaml Modern app with thread

I have following two methods. When user clicks on start button from ui, the step geoLocator_PositionChanged in geoLocator_PositionChanged method is fired and calls the other method geoLocator_PositionChanged.But when it comes to try block while executing the first statement it throws the following error:
"The application called an interface that was marshalled for a different thread. (Exception from HRESULT: 0x8001010E (RPC_E_WRONG_THREAD))"
private async void btnStartStop_Click_1(object sender, RoutedEventArgs e)
{
geoLocator.PositionChanged += geoLocator_PositionChanged;
}
async void geoLocator_PositionChanged(Geolocator sender, PositionChangedEventArgs args)
{
MessageDialog msgdlg = null;
bool bDisplayDialog = false;
try
{
lblAltValue.Text = args.Position.Coordinate.Altitude.ToString();
}
catch
{
}
}
Any help how can I fix this issue ?
You try to access the UI-Thread from another one.
Try something like ths
Windows.ApplicationModel.Core.CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync
(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
{
//HERE GOES THE UI ACCESS LIKE this.textbox.text = "MY AWESOME TEXT";
});