How to open ActionCall Activity from DependencyServic in Xamarin Forms? - c#

Hi I am facing a very simple problem but I am not exactly sure why?
I am trying to call directly from xamarin forms app, without showing dailer screen, user will see list of its contacts in a screen click a button to call, and it will make a direct call without showing dialer screen.
to achieve this I have used DependencyServic and I have used this as my base https://www.c-sharpcorner.com/UploadFile/e4bad6/code-to-start-call-in-xamarin-forms/
the only difference is this is PCL and I am using shared library
Where I am getting Problem?
My Interface
public interface IPhoneCall
{
void MakeQuickCall(string PhoneNumber);
}
My call to Dependency Service
private void makeCall_Clicked(object sender, EventArgs e)
{
try
{
DependencyService.Get<IPhoneCall>().MakeQuickCall("+xxxxxxxxx");
} catch(Exception ex)
{
DisplayAlert("Alert!!!", ex.Message, "ok");
}
}
My Dependency service call for Android:
[assembly: Dependency(typeof(PhoneCall_Droid))]
namespace MakeCall.Droid
{
public class PhoneCall_Droid : IPhoneCall
{
public void MakeQuickCall(string PhoneNumber)
{
try
{
var uri = Android.Net.Uri.Parse(string.Format("tel:{0}", PhoneNumber));
var intent = new Intent(Intent.ActionCall, uri);
Xamarin.Forms.Forms.Context.StartActivity(intent);
}
catch (Exception ex)
{
new AlertDialog.Builder(Android.App.Application.Context).SetPositiveButton("OK", (sender, args) =>
{
//User pressed OK
})
.SetMessage(ex.ToString())
.SetTitle("Android Exception")
.Show();
}
}
}
}
This alert is returning an exception Unable to add window - token null is not valid; is your activity running?
I have looked different solutions like this
Intent ActionCall is not making phone call in xamarin forms
and this
https://forums.xamarin.com/discussion/129166/unable-to-add-window-token-null-is-not-for-an-application-alertbuilder
but I am still not able to sort this, out,
also I tried this in my Main activity
internal static MainActivity Instance { get; private set; }
and then added this line in OnCreate method
Instance = this;
and changed my Android dependency service class method to this
public void MakeQuickCall(string PhoneNumber)
{
var context = MainActivity.Instance;
try
{
new AlertDialog.Builder(context ).SetPositiveButton("OK", (sender, args) =>
{
//User pressed OK
})
.SetMessage(Android.Net.Uri.Parse(string.Format("tel:{0}", PhoneNumber)).ToString())
.SetTitle("Android Exception")
.Show();
Intent intent = new Intent(Intent.ActionCall, Android.Net.Uri.Parse(string.Format("tel:{0}", PhoneNumber)));
context.StartActivity(intent);
}
catch (Exception ex)
{
new AlertDialog.Builder(Android.App.Application.Context).SetPositiveButton("OK", (sender, args) =>
{
//User pressed OK
})
.SetMessage(ex.ToString())
.SetTitle("Android Exception")
.Show();
}
}
and by doing this alert is showing the dailed phone number, but it is not calling and for call part is still showing same of unable to add window ..,

I can reproduce your issue at my side, if you request the runtime permissions after Android 6.0, you will solved your issue.
Firstly, you could defined a static variable in MainActiviy:
public static MainActivity macvivity;
protected override void OnCreate(Bundle savedInstanceState)
{
TabLayoutResource = Resource.Layout.Tabbar;
ToolbarResource = Resource.Layout.Toolbar;
base.OnCreate(savedInstanceState);
macvivity = this;
global::Xamarin.Forms.Forms.Init(this, savedInstanceState);
LoadApplication(new App());
}
Then requesting permissions before call:
public void MakeQuickCall(string PhoneNumber)
{
try
{
if (ActivityCompat.CheckSelfPermission(MainActivity.macvivity, Android.Manifest.Permission.CallPhone) != Android.Content.PM.Permission.Granted)
{
ActivityCompat.RequestPermissions(MainActivity.macvivity, new string[] { Android.Manifest.Permission.CallPhone }, 1);
return;
}
else
{
var uri = Android.Net.Uri.Parse(string.Format("tel:{0}", PhoneNumber));
var intent = new Intent(Intent.ActionCall, uri);
Xamarin.Forms.Forms.Context.StartActivity(intent);
//MainActivity.macvivity.StartActivity(intent);
}
}
catch (Exception ex)
{
new AlertDialog.Builder(Android.App.Application.Context).SetPositiveButton("OK", (sender, args) =>
{
//User pressed OK
})
.SetMessage(ex.ToString())
.SetTitle("Android Exception")
.Show();
}
}

Related

Xamarin.Forms Firebasepushnotification plugin OnNotificationOpened event causes app to restart for android

I'm trying to handle a notifications opening on android that I've sent through Google's FCM on the SharedProject level by using "Plugin.FirebasePushNotification" plugin and subscribing to "OnNotificationOpened" event.
When I try to open the notification while the app is in the background I'm able to hit a breakpoint inside "OnNotificationOpened" event but after the work inside the event ends the App const. is hit and the application restarts.
I want the application to continue from its last state and hit "OnResume" method that is located inside the App class.
I've done some research about it online and almost all of them were about how splash activity might cause this issue so I've disabled my splash activity by turning the whole "SplashActivity.cs" file into a comment except the namespace and usages and implemented the wanted features of splashactivity(style) inside the "MainActivity" class after that I made sure my "MainActivity" class was the only activity that had it's "MainLauncher" attribute set to true but the problem continues.
Here are the relevant classes:
FirebaseReg.cs
public class FirebaseReg
{
public static void FirebaseInit()
{
CrossFirebasePushNotification.Current.OnTokenRefresh += (s, p) =>
{
System.Diagnostics.Debug.WriteLine($"TOKEN : {p.Token}");
CrossFirebasePushNotification.Current.Subscribe("defaultTopic");
};
CrossFirebasePushNotification.Current.OnNotificationOpened += (s, p) =>
{
try
{
//Breakpoint hits here and I'm able to finish all my work without any exceptions
}
catch (Exception ex)
{
}
};
CrossFirebasePushNotification.Current.OnNotificationAction += (s, p) =>
{
};
CrossFirebasePushNotification.Current.OnNotificationReceived += Current_OnNotificationReceived;
}
private static void Current_OnNotificationReceived(object source, FirebasePushNotificationDataEventArgs e)
{
//DO WORK
}
}
App.xaml.cs
public partial class App : Application
{
public static Uri ServerUri = new Uri(" ");
public static bool IsInForeground { get; set; } = false;
public App()
{
try
{
InitializeComponent(); //After the work in OnNotificationOpened ends breakpoint goes here
Application.Current.UserAppTheme = OSAppTheme.Unspecified;
Application.Current.MainPage = new LoginPage();
}
catch (Exception ex)
{
}
}
protected override void OnStart()
{
IsInForeground = true;
}
protected override void OnSleep()
{
IsInForeground = false;
}
protected override void OnResume()
{
IsInForeground = true;
}
}
MainActivity.cs
[Activity(Label = "TestProject1", Theme = "#style/MyTheme.Splash", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation | ConfigChanges.UiMode | ConfigChanges.ScreenLayout | ConfigChanges.SmallestScreenSize )]
public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
{
protected override void OnCreate(Bundle savedInstanceState)
{
base.Window.RequestFeature(WindowFeatures.ActionBar);
// Name of the MainActivity theme you had there before.
// Or you can use global::Android.Resource.Style.ThemeHoloLight
base.SetTheme(Resource.Style.MainTheme);
base.OnCreate(savedInstanceState);
Rg.Plugins.Popup.Popup.Init(this);
UserDialogs.Init(this);
Xamarin.FormsGoogleMaps.Init(this, savedInstanceState);
Xamarin.Essentials.Platform.Init(this, savedInstanceState);
global::Xamarin.Forms.Forms.Init(this, savedInstanceState);
FirebasePushNotificationManager.ProcessIntent(this ,Intent);
LoadApplication(new App());
}
protected override void OnNewIntent(Intent intent)
{
FirebasePushNotificationManager.ProcessIntent(this, intent);
base.OnNewIntent(intent);
}
public override void OnRequestPermissionsResult(int requestCode, string[] permissions, Permission[] grantResults)
{
Xamarin.Essentials.Platform.OnRequestPermissionsResult(requestCode, permissions, grantResults);
base.OnRequestPermissionsResult(requestCode, permissions, grantResults);
}
}
MainApplication.cs
[Application]
public class MainApplication : Application, Application.IActivityLifecycleCallbacks
{
public MainApplication(IntPtr handle, JniHandleOwnership transer) : base(handle, transer)
{
}
public override void OnCreate()
{
base.OnCreate();
RegisterActivityLifecycleCallbacks(this);
if (Build.VERSION.SdkInt >= Android.OS.BuildVersionCodes.O)
{
FirebasePushNotificationManager.DefaultNotificationChannelId = "DefaultChannel";
FirebasePushNotificationManager.DefaultNotificationChannelName = "defaultTopic";
}
#if DEBUG
FirebasePushNotificationManager.Initialize(this, true);
FirebaseRegister.FirebaseInit();
#else
FirebasePushNotificationManager.Initialize(this, false);
FirebaseRegister.FirebaseInit();
#endif
}
public override void OnTerminate()
{
base.OnTerminate();
UnregisterActivityLifecycleCallbacks(this);
}
public void OnActivityCreated(Activity activity, Bundle savedInstanceState)
{
CrossCurrentActivity.Current.Activity = activity;
}
public void OnActivityDestroyed(Activity activity)
{
}
public void OnActivityPaused(Activity activity)
{
}
public void OnActivityResumed(Activity activity)
{
CrossCurrentActivity.Current.Activity = activity;
}
public void OnActivitySaveInstanceState(Activity activity, Bundle outState)
{
}
public void OnActivityStarted(Activity activity)
{
CrossCurrentActivity.Current.Activity = activity;
}
public void OnActivityStopped(Activity activity)
{
}
}
From the Android docs, it states this:
If it has declared its launch mode to be "multiple" (the default) and
you have not set FLAG_ACTIVITY_SINGLE_TOP in the same intent, then it
will be finished and re-created; for all other launch modes or if
FLAG_ACTIVITY_SINGLE_TOP is set then this Intent will be delivered to
the current instance's onNewIntent().
That's why your app is restarting.
The launchMode attribute of the activity affects how the activity is launched.
singleTop, singleTask, or singleInstance should be used to prevent the notification intent from creating a new activity instance.
The flag FLAG_ACTIVITY_NEW_TASK doesn't influence a new activity being created, but makes the launched activity the root of a new task.
For more, check:
https://developer.android.com/guide/topics/manifest/activity-element.html#lmode
https://developer.android.com/guide/components/activities/tasks-and-back-stack

Xamarin - Requesting camera permissions in WebView

I want to make a container-app for my web application, and I decided to do so in Xamarin because the rest of the project is also .NET.
Initially I downloaded and setup the project from Xamarin Sample Pages:
https://learn.microsoft.com/en-us/xamarin/xamarin-forms/user-interface/webview?tabs=windows
I simply changed a few variables in WebPage.cs: https://github.com/xamarin/xamarin-forms-samples/blob/master/WorkingWithWebview/WorkingWithWebview/WebPage.cs
using Xamarin.Forms;
namespace WorkingWithWebview
{
public class WebPage : ContentPage
{
public WebPage()
{
var browser = new WebView();
browser.Source = "https://xamarin.swappsdev.net";
Content = browser;
}
}
}
Secondly I updated App.cs to suit my needs: https://github.com/xamarin/xamarin-forms-samples/blob/master/WorkingWithWebview/WorkingWithWebview/App.
using Xamarin.Forms;
namespace WorkingWithWebview
{
public class App : Application
{
public App ()
{
MainPage = new WebPage();
}
}
}
And boom! I had an app.
Then came the real struggle. In the web application I can – when opening the site (https://xamarin.swappsdev.net) in the browser – click on a button which requests permissions from the device and then display the camera feed in the same window.
When doing the same action in the app nothing happens.
I then started googling for an answer and really didn’t find a lot. And the answers I found seems to be of an older version of Xamarin (?), since I wasn’t able to compare the files and structure in the answer compared to the one of the Xamarin Sample Page.
https://stackoverflow.com/a/50560855
I tried implementing the answer from Robbit here. After a long struggle I managed to compile it and install it on my device but it doesn't actually ask for permissions.
I am at a loss and could need some help/guidance.
Updated:
In my previous answer, it shows how to add camera permission on webview.
The link you provided, it works now. https://xamarin.swappsdev.net/ It seems to provide a camera preview function. It need to check permissions on API 23+.
On Xamarin.Forms, you could use Permissions Plugin. https://github.com/jamesmontemagno/PermissionsPlugin
First, add the camera permission in Android Manifest.
Your Project.Android> Properties> Android Manifest> Required permissions> Camera. After that, it would generate the user permission in AndroidManifest.xml.
<uses-permission android:name="android.permission.CAMERA" />
Create a Utils.cs.
public static class Utils
{
public static async Task<PermissionStatus> CheckPermissions(Permission permission)
{
var permissionStatus = await CrossPermissions.Current.CheckPermissionStatusAsync(permission);
bool request = false;
if (permissionStatus == PermissionStatus.Denied)
{
if (Device.RuntimePlatform == Device.iOS)
{
var title = $"{permission} Permission";
var question = $"To use this plugin the {permission} permission is required. Please go into Settings and turn on {permission} for the app.";
var positive = "Settings";
var negative = "Maybe Later";
var task = Application.Current?.MainPage?.DisplayAlert(title, question, positive, negative);
if (task == null)
return permissionStatus;
var result = await task;
if (result)
{
CrossPermissions.Current.OpenAppSettings();
}
return permissionStatus;
}
request = true;
}
if (request || permissionStatus != PermissionStatus.Granted)
{
var newStatus = await CrossPermissions.Current.RequestPermissionsAsync(permission);
if (!newStatus.ContainsKey(permission))
{
return permissionStatus;
}
permissionStatus = newStatus[permission];
if (newStatus[permission] != PermissionStatus.Granted)
{
permissionStatus = newStatus[permission];
var title = $"{permission} Permission";
var question = $"To use the plugin the {permission} permission is required.";
var positive = "Settings";
var negative = "Maybe Later";
var task = Application.Current?.MainPage?.DisplayAlert(title, question, positive, negative);
if (task == null)
return permissionStatus;
var result = await task;
if (result)
{
CrossPermissions.Current.OpenAppSettings();
}
return permissionStatus;
}
}
return permissionStatus;
}
}
In MainActivity.cs, add the code in OnCreate method.
Plugin.CurrentActivity.CrossCurrentActivity.Current.Init(this, savedInstanceState);
OnRequestPermissionsResult is needed in MainActivity.cs.
public override void OnRequestPermissionsResult(int requestCode, string[] permissions,
[GeneratedEnum] Android.Content.PM.Permission[] grantResults)
{
PermissionsImplementation.Current.OnRequestPermissionsResult(requestCode, permissions, grantResults);
base.OnRequestPermissionsResult(requestCode, permissions, grantResults);
}
And then impletement it.
private async void _button_Clicked(object sender, EventArgs e)
{
webView.Source = "https://xamarin.swappsdev.net/";//"https://test.webrtc.org/";
var status = PermissionStatus.Unknown;
status = await CrossPermissions.Current.CheckPermissionStatusAsync(Permission.Camera);
if (status != PermissionStatus.Granted)
{
status = await Utils.CheckPermissions(Permission.Camera);
}
}
I have upload on my GitHub. Check the folder. Test/CameraRuntimePermission_WebView/RuntimePermission
https://github.com/WendyZang/Test.git
Edit:
If you do not want to call this in button click event, you could delete the button in MainPage.xaml.
MainPage.xaml.cs
public MainPage()
{
InitializeComponent();
webView.Source = "https://xamarin.swappsdev.net/";
}
protected override void OnAppearing()
{
base.OnAppearing();
RunTimePermission();
}
public async void RunTimePermission()
{
var status = PermissionStatus.Unknown;
status = await CrossPermissions.Current.CheckPermissionStatusAsync(Permission.Camera);
if (status != PermissionStatus.Granted)
{
status = await Utils.CheckPermissions(Permission.Camera);
}
}
After following several guides to enable the WebView's camera, I have finally succeeded.
I followed all of the above steps, and despite getting prompts for allowing the camera I could never get rid of the permissions error (even when debug showed the permissions were granted). I then replaced the MyWebViewRenderer code (as given above by Wendy) with the following (as given on https://forums.xamarin.com/discussion/183988/how-to-give-camera-and-microphone-permission-to-webview-with-xamarin-forms-on-android):
[assembly: ExportRenderer(typeof(CustomWebView), typeof(CustomWebViewRenderer))]
namespace App19F_8.Droid
{
public class CustomWebViewRenderer : WebViewRenderer
{
public CustomWebViewRenderer(Context context) : base(context)
{
}
protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.WebView> e)
{
base.OnElementChanged(e);
if (e.NewElement != null)
{
Control.SetWebChromeClient(new MyWebChromeClient(MainActivity.Instance));
Control.Settings.JavaScriptEnabled = true;
}
}
}
public class MyWebChromeClient : WebChromeClient
{
Activity mActivity = null;
public MyWebChromeClient(Activity activity)
{
mActivity = activity;
}
public override void OnPermissionRequest(PermissionRequest request)
{
mActivity.RunOnUiThread(() => {
request.Grant(request.GetResources());
});
}
}
}
In case the link above becomes invalid, I should mention that in Android's MainActivity you should insert the following:
public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
{
public static MainActivity Instance { get; private set; }
protected override void OnCreate(Bundle savedInstanceState)
{
...
base.OnCreate(savedInstanceState);
Instance = this;
global::Xamarin.Forms.Forms.Init(this, savedInstanceState);
LoadApplication(new App());
}
}
Now finally the camera is working :-) I'm not exactly sure what the culprit was in the previous code. Thanks a lot to Wendy, Yelinzh and all for the thorough responses.
I tried implementing the answer from Robbit here. After a long struggle I managed to compile it and install it on my device but it doesn't actually ask for permissions.
I try the code provided by Robbit from the link.
Camera on Xamarin WebView
Actually, it works well. For better understanding, you could use the link below to check. https://test.webrtc.org/
If I use the webview to load the url directly, it would throw the error like below.
If I use the custom renderer from Robbit, it would ask for permission with the code in MyWebViewRenderer.
public override void OnPermissionRequest(PermissionRequest request)
{
mContext.RunOnUiThread(() =>
{
request.Grant(request.GetResources());
});
}
I have also check the link you used, nothing happened. The link would not open the camera in Android device.
Usage of the code from Robbit.
Create the MyWebView in your project.
public class MyWebView : WebView
{
}
Create the MyWebViewRenderer.cs in Android part of your project.
[assembly: ExportRenderer(typeof(MyWebView), typeof(MyWebViewRenderer))]
namespace WebViewDemo.Droid
{
public class MyWebViewRenderer : WebViewRenderer
{
Activity mContext;
public MyWebViewRenderer(Context context) : base(context)
{
this.mContext = context as Activity;
}
protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.WebView> e)
{
base.OnElementChanged(e);
Control.Settings.JavaScriptEnabled = true;
Control.ClearCache(true);
Control.SetWebChromeClient(new MyWebClient(mContext));
}
public class MyWebClient : WebChromeClient
{
Activity mContext;
public MyWebClient(Activity context)
{
this.mContext = context;
}
[TargetApi(Value = 21)]
public override void OnPermissionRequest(PermissionRequest request)
{
mContext.RunOnUiThread(() =>
{
request.Grant(request.GetResources());
});
}
}
}
}
Usage:
MainPage.xaml
<StackLayout>
<Button x:Name="_button" Clicked="_button_Clicked" />
<local:MyWebView
x:Name="webView"
HeightRequest="500"
WidthRequest="500" />
</StackLayout>
MainPage.xaml.cs
private void _button_Clicked(object sender, EventArgs e)
{
webView.Source = "https://test.webrtc.org/";//"https://xamarin.swappsdev.net/";
}
You could download the whole project from GitHub folder CameraRuntimePermission_WebView. The Page1 is used to test the link with webview. The MainPage is used to test with custom renderer.
https://github.com/WendyZang/Test.git

How to store authenticated state through Office365 API in Xamarin.forms

I'm new to Xamarin and using the Office365 API. I'm attempting to learn through creating a Xamarin.Forms application that reads data from the Office365 server once the user is authenticated.
I've been following a tutorial and ended up with the following login page
namespace CMLender.Pages
{
public partial class Login
{
public IPlatformParameters PlatformParameters { get; set; }
public Login()
{
InitializeComponent();
LoginButton.Clicked += LoginButton_Clicked;
}
protected override void OnAppearing()
{
App.ClientApplication.PlatformParameters = PlatformParameters;
base.OnAppearing();
}
private async void LoginButton_Clicked(object sender, EventArgs e)
{
try
{
AuthenticationResult ar = await App.ClientApplication.AcquireTokenAsync(App.Scopes);
}
catch (MsalException ex)
{
WelcomeText.Text = ex.Message;
}
finally
{
await Navigation.PushAsync(new MainTab());
}
}
}
}
Once a user clicks on the login button they are taken through to the Office365 user authentication page. Once they have logged in with a valid username and password, the application then loads the MainTab XAML page.
Now this is where my problem starts. My MainTab page looks like this:
namespace CMLender.Pages
{
public partial class MainTab : ContentPage
{
public MainTab()
{
InitializeComponent();
DisplayMessage();
}
private async void DisplayMessage()
{
try
{
AuthenticationResult ar = await App.ClientApplication.AcquireTokenAsync(App.Scopes);
WelcomeText.Text = $"Welcome {ar.User.Name}";
}
catch (MsalException ex)
{
WelcomeText.Text = ex.Message;
}
finally
{
WelcomeTextTwo.Text = "BlaBlaBlab";
}
}
}
}
I wanted this page to write the logged in users name to a label (which it does) but first the user has to re-authenticate.
I'm pretty sure it's down to the AcquireTokenAsync task but it's the only way I can get it to work. How can I store the information that the user is already authenticated and access their user name?
I've done all the reading I can but the information just seems so far and wide on the subject.
For the most simplistic impllementation you can create a public static property in you App.cs or App.xaml.cs like :
public static AuthenticationResult LoggedInUser { get; set; }
In your login page add this to your login button click event :
private async void LoginButton_Clicked(object sender, EventArgs e)
{
try
{
AuthenticationResult ar = await App.ClientApplication.AcquireTokenAsync(App.Scopes);
App.LoggedInUser = ar;
}
catch (MsalException ex)
{
WelcomeText.Text = ex.Message;
}
finally
{
await Navigation.PushAsync(new MainTab());
}
}
And in you main page, get the data from the static property instead of calling the API again :
private async void DisplayMessage()
{
try
{
WelcomeText.Text = $"Welcome {App.LoggedInUser.User.Name}";
}
catch (MsalException ex)
{
WelcomeText.Text = ex.Message;
}
finally
{
WelcomeTextTwo.Text = "BlaBlaBlab";
}
}
Also, in your login method, It does not seem right to show the main page in finally because even if an exception occurs finally would get executed. I suggest you to move await Navigation.PushAsync(new MainTab()); to try and show exception to user in catch.

Xamarin - MediaPicker not showing the videoPicker for iOS

I tried doing this in my main app I'm writing but can't seem to get it to work. So I created a Single View Application to try it out and figure it out but I still seem to be stuck. He's what i got.
public partial class HelloViewController : UIViewController
{
partial class VideoPickerController : UIViewController
{
MediaPicker videoPicker;
readonly TaskScheduler uiScheduler = TaskScheduler.FromCurrentSynchronizationContext();
public VideoPickerController (IntPtr handle) : base (handle)
{
}
public override void DidReceiveMemoryWarning ()
{
// Releases the view if it doesn't have a superview.
base.DidReceiveMemoryWarning ();
// Release any cached data, images, etc that aren't in use.
}
public override void ViewDidLoad ()
{
base.ViewDidLoad ();
var picker = new MediaPicker ();
PresentViewController (picker.GetPickPhotoUI (), true, null);
}
}
}
Basically all I get is a white screen and nothing happens. Thanks!
I don't think you need need to to manually present it. This is code that I used and it automatically presents the UI for me. This code is not in it's own viewcontroller, it is just in whatever viewcontroller that I have the button it to take the pic. There are similar methods for the photo album and for taking videos.
Here is a link to the github page where I have this sample app hosted.
var picker = new Xamarin.Media.MediaPicker();
btnCamera.Hidden = !picker.IsCameraAvailable;
btnCamera.TouchUpInside += async (sender, e) =>
{
try
{
MediaFile file =
await picker.TakePhotoAsync(new StoreCameraMediaOptions());
processImage(file);
}
catch { }
};
btnPhoto.Hidden = !picker.PhotosSupported;
btnPhoto.TouchUpInside += async (sender, e) =>
{
try
{
MediaFile file = await picker.PickPhotoAsync();
processImage(file);
}
catch { }
};
private void processImage(MediaFile file)
{
if (file != null)
{
viewModel.Image = file.GetStream();
viewModel.ImagePath = file.Path;
setImage();
}
}
private void setImage()
{
try
{
System.Diagnostics.Debug.WriteLine(viewModel.ImagePath);
if (!string.IsNullOrEmpty(viewModel.ImagePath) &&
System.IO.File.Exists(viewModel.ImagePath))
{
imgImage.Image = new UIImage(NSData.FromFile(viewModel.ImagePath));
}
else if (viewModel.Image != null && viewModel.Image.Length != 0)
{
imgImage.Image = new UIImage(NSData.FromStream(viewModel.Image));
}
}
//just don't load image
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex.Message);
}
}

Calling own WCF WebService twice from different BackgroundWorkers closes application

I've written a small WCF WebService (.svc) which I want to call from other applications. It's working fine so far.
In another application I've got a Windows Form. When this is shown, it will call BackgroundWorker1 to get a list of objects from the WebService and show it to the user on it's completed1-method. So far, so good.
Now, after the user selects one object and clicks "ok", then BackgroundWorker2 will call the WebService again to gather more information. But here, within the doWork2-method exactly after the WebService-call, the whole application breaks without any exceptions or errors. It just closes directly after the WebService is called.
This is very weird, because as I have a look at the WebServices log files, it seems to work normal and still logs the successful operation AFTER the other application is closed. So the WebService cannot be the problem, I think.
Another weird thing: If I call the WebService the second time on the GUI thread (and not with BackgroundWorker2), it just works. It blocks the UI, but it works.
So, why is my application just "broken" after the second call without any notification?
Any ideas are very much welcomed.
Thanks in advance.
Greets
Here's some simplified code. The application closes in "bgwGetSingleCar_DoWork":
public partial class MyForm : Form
{
private Controller _ctrl { get; set; }
private Config _config { get; set; }
private List<Cars> _cars { get; set; }
public bool Result { get; private set; }
public MyForm(Controller ctrl, Config config)
{
this._ctrl = ctrl;
this._config = config;
this.Result = false;
InitializeComponent();
}
private void MyForm_Load(object sender, EventArgs e)
{
try
{
this.bgwGetAllOffers.RunWorkerAsync(new WorkerInfo()
{
WorkerType = WorkerType.Type1,
IdLocal = this._config.IdLocal,
IdExternal = this._config.IdExternal,
});
}
catch (Exception ex)
{
// ...
}
}
private void FillList(List<Cars> list)
{
// ...
}
private void btnOk_Click(object sender, EventArgs e)
{
CarListItem v = (CarListItem)this.lstBoxCars.SelectedValue;
this._config.IdExternal = v.IdExternal;
try
{
this.bgwGetSingleCar.RunWorkerAsync(new WorkerInfo()
{
WorkerType = WorkerType.Type2,
IdLocal = this._config.IdLocal,
IdExternal = this._config.IdExternal,
});
}
catch (Exception ex)
{
// ...
}
}
private void bgwGetAllCars_DoWork(object sender, DoWorkEventArgs e)
{
try
{
WorkerInfo info = (WorkerInfo)e.Argument;
Client client = new Client();
GetCarsResult result = client.GetAllCars(new GetAllCarsRequest()
{
IdLocal = info.IdLocal,
IdExternal = info.IdExternal
});
if (!result.Success)
{
// ...
}
if (result.Cars != null)
{
this._cars = result.Cars.ToList();
}
}
catch (Exception ex)
{
/// ...
}
}
private void bgwGetAllCars_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
this.FillList(this._cars);
}
private void bgwGetSingleCar_DoWork(object sender, DoWorkEventArgs e)
{
try
{
WorkerInfo info = (WorkerInfo)e.Argument;
Client client = new Client();
// Application closes after this line, but WebService log still shows activity
GetCarsResult result = client.GetSingleCar(new GetSingleCarRequest()
{
IdLocal = info.IdLocal,
IdExternal = info.IdExternal
});
if (result.Success)
{
this.Result = true;
}
}
catch (Exception ex)
{
/// ...
}
}
private void bgwGetSingleOffer_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
this.DialogResult = System.Windows.Forms.DialogResult.OK;
}
}
public class CarListItem : Car
{
public override string ToString()
{
return ((DateTime)this.LastUpdate).ToString("dd.MM.yyyy - HH:mm");
}
}
I just found my "design break".
It was the button's "DialogResult" which caused the application to close too soon. But strange that the debugger didn't step ahead...

Categories

Resources