Xamarin - MediaPicker not showing the videoPicker for iOS - c#

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);
}
}

Related

How to open ActionCall Activity from DependencyServic in Xamarin Forms?

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();
}
}

How to call a function in a backgroundworker thread that is to be completed on the main UI thread? [duplicate]

So, first I have read a ton of threads on this particular problem and I still do not understand how to fix it. Basically, I am trying to communicate with a websocket and store the message received in an observable collection that is bound to a listview. I know that I am getting a response back properly from the socket, but when it tries to add it to the observable collection it gives me the following error:
The application called an interface that was marshalled for a different thread. (Exception from HRESULT: 0x8001010E (RPC_E_WRONG_THREAD))
I've read some information on "dispatch" as well as some other things, but I am just massively confused! Here is my code:
public ObservableCollection<string> messageList { get; set; }
private void MessageReceived(MessageWebSocket sender, MessageWebSocketMessageReceivedEventArgs args)
{
string read = "";
try
{
using (DataReader reader = args.GetDataReader())
{
reader.UnicodeEncoding = Windows.Storage.Streams.UnicodeEncoding.Utf8;
read = reader.ReadString(reader.UnconsumedBufferLength);
}
}
catch (Exception ex) // For debugging
{
WebErrorStatus status = WebSocketError.GetStatus(ex.GetBaseException().HResult);
// Add your specific error-handling code here.
}
if (read != "")
messageList.Add(read); // this is where I get the error
}
And this is the binding:
protected override async void OnNavigatedTo(NavigationEventArgs e)
{
//await Authenticate();
Gameboard.DataContext = Game.GameDetails.Singleton;
lstHighScores.ItemsSource = sendInfo.messageList;
}
How do I make the error go away while still binding to the observable collection for my listview?
This solved my issue:
Windows.ApplicationModel.Core.CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal,
() =>
{
// Your UI update code goes here!
}
);
Correct way to get the CoreDispatcher in a Windows Store app
Try replacing
messageList.Add(read);
with
Dispatcher.Invoke((Action)(() => messageList.Add(read)));
If you're calling from outside your Window class, try:
Application.Current.Dispatcher.Invoke((Action)(() => messageList.Add(read)));
Slight modification for task based async methods but the code in here will not be awaited.
await Windows.ApplicationModel.Core.CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal,
() =>
{
// Your UI update code goes here!
}
).AsTask();
This code WILL await, and will allow you to return a value:
private async static Task<string> GetPin()
{
var taskCompletionSource = new TaskCompletionSource<string>();
CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal,
async () =>
{
var pin = await UI.GetPin();
taskCompletionSource.SetResult(pin);
}
);
return await taskCompletionSource.Task;
}
And on Android:
private async Task<string> GetPin()
{
var taskCompletionSource = new TaskCompletionSource<string>();
RunOnUiThread(async () =>
{
var pin = await UI.GetPin();
taskCompletionSource.SetResult(pin);
});
return await taskCompletionSource.Task;
}
Maby this is not a "good" practice, but it works.. I leave a message from webSocket, to mainBody instance, where I have a timered reader...
public class C_AUTHORIZATION
{
public Observer3.A_MainPage_cl parentPageInstance; //еще одни экземпляр родителя
public WebSocket x_Websocket;
private string payload = "";
private DateTime nowMoment = DateTime.Now;
public void GET_AUTHORIZED()
{
bitfinex_Websocket= new WebSocket("wss://*****.com/ws/2");
var apiKey = "";
var apiSecret = "";
DateTime nowMoment = DateTime.Now;
payload = "{}";
x_Websocket.Opened += new EventHandler(websocket_Opened);
x_Websocket.Closed += new EventHandler(websocket_Closed);
}
void websocket_Opened(object sender, EventArgs e)
{
x_Websocket.Send(payload);
parentPageInstance.F_messager(payload);
}
void websocket_Closed(object sender, EventArgs e)
{
parentPageInstance.F_messager("L106 websocket_Closed!");
GET_AUTHORIZED();
}
}
public sealed partial class A_MainPage_cl : Page
{
DispatcherTimer ChartsRedrawerTimer;
public bool HeartBeat = true;
private string Message;
public A_MainPage_cl()
{
this.InitializeComponent();
ChartsRedrawerTimer = new DispatcherTimer() { Interval = new TimeSpan(0, 0, 0, 0, 100) };
ChartsRedrawerTimer.Tick += Messager_Timer;
ChartsRedrawerTimer.Start();
}
private void Messager_Timer(object sender, object e)
{
if(Message !=null) //
{
F_WriteLine(Message);
Message = null; //
}
}
public void F_messager(string message) //
{
Message = message;
}
In Xamarin, I got around this by using:
Device.BeginInvokeOnMainThread(() => {
// code goes here
});

c# Using an action from GUI while running thread

Question :
I'm a beginner in c# and i'm having a bit of trouble to understand how thread works with a form. I'm trying to update a progressbar when my program hit keypoints and i can't get it to work here is my code.
For my "worker" class :
public void addFollower(string followerName, Action<string> followerAction) {
this.followers.Add(followerName, followerAction);
}
private void notifyFollowers(string message) {
if (followers.Count > 0) {
foreach (String followerName in followers.Keys) {
followers[followerName].Invoke(message);
}
}
}
for my linking class (controller maybe?) :
public void runWithParams(Dictionary<string,string> parameters, Action<string> updateManager = null){
string app = parameters["appName"];
string navigator = parameters["navigatorName"];
string mode = parameters["mode"];
string scenario = parameters["scenarioName"];
try {
Scenario sc = this.scenarioBuilders[app].buildScenario(scenario);
if(updateManager != null) sc.addFollower("updateManager", updateManager);
Thread TestRunner = new Thread(sc.run);
TestRunner.Start();
} catch (Exception ex) {
Console.WriteLine(ex.Message);
Console.WriteLine("Unexpected shutdown or driver unreachable");
}
}
For the gui :
private void ButtonRun_Click(object sender, EventArgs e) {
Dictionary<string, string> parameters = new Dictionary<string, string>{
{"appName",this.CBApplicationChoice.SelectedItem.ToString()},
{"navigatorName",this.CBNavigatorChoice.SelectedItem.ToString()},
{"mode",this.CBModeChoice.SelectedItem.ToString()},
{"scenarioName",this.CBScenarioChoice.SelectedItem.ToString()}
};
this.dispatcher.runWithParams(parameters, ManageRealTimeStep1);
}
public void ManageRealTimeStep1(string liveevent){
if (liveevent.Contains("NumberOfPages")) {
this.PBStep1.Maximum = Convert.ToInt32(liveevent.Split(':')[1]);
} else if (liveevent.Contains("StartingTestNewPage")) {
this.PBStep1.Increment(1);
}
}
I'm getting an InvalidOperationException when i click on the RunButton and the error says that i'm trying to call a function that is in another thread. How can i fix it?
Thanks in advance for any answer/ insights
Solution :
I changed the method in gui for :
public void ManageRealTimeStep1(string liveevent) {
BeginInvoke(new Action(() => {
if (liveevent.Contains("NumberOfPages")) {
this.PBStep1.Maximum = Convert.ToInt32(liveevent.Split(':')[1]);
} else if (liveevent.Contains("StartingTestNewPage")) {
this.PBStep1.Increment(1);
}
}));
}
Use BeginInvoke method:
BeginInvoke(new Action(() =>
{
this.PBStep1.Maximum = Convert.ToInt32(liveevent.Split(':')[1]);
}));
Read more about updating WinForms UI from another thread here
You are not allowed to update the GUI from a different thread, see How to update the GUI from another thread in C#?.
You are accessing the GUI from the ManageRealTimeStep1 method which is used by the Scenario class (as a callback) on the background thread.

The application called an interface that was marshalled for a different thread - Windows Store App

So, first I have read a ton of threads on this particular problem and I still do not understand how to fix it. Basically, I am trying to communicate with a websocket and store the message received in an observable collection that is bound to a listview. I know that I am getting a response back properly from the socket, but when it tries to add it to the observable collection it gives me the following error:
The application called an interface that was marshalled for a different thread. (Exception from HRESULT: 0x8001010E (RPC_E_WRONG_THREAD))
I've read some information on "dispatch" as well as some other things, but I am just massively confused! Here is my code:
public ObservableCollection<string> messageList { get; set; }
private void MessageReceived(MessageWebSocket sender, MessageWebSocketMessageReceivedEventArgs args)
{
string read = "";
try
{
using (DataReader reader = args.GetDataReader())
{
reader.UnicodeEncoding = Windows.Storage.Streams.UnicodeEncoding.Utf8;
read = reader.ReadString(reader.UnconsumedBufferLength);
}
}
catch (Exception ex) // For debugging
{
WebErrorStatus status = WebSocketError.GetStatus(ex.GetBaseException().HResult);
// Add your specific error-handling code here.
}
if (read != "")
messageList.Add(read); // this is where I get the error
}
And this is the binding:
protected override async void OnNavigatedTo(NavigationEventArgs e)
{
//await Authenticate();
Gameboard.DataContext = Game.GameDetails.Singleton;
lstHighScores.ItemsSource = sendInfo.messageList;
}
How do I make the error go away while still binding to the observable collection for my listview?
This solved my issue:
Windows.ApplicationModel.Core.CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal,
() =>
{
// Your UI update code goes here!
}
);
Correct way to get the CoreDispatcher in a Windows Store app
Try replacing
messageList.Add(read);
with
Dispatcher.Invoke((Action)(() => messageList.Add(read)));
If you're calling from outside your Window class, try:
Application.Current.Dispatcher.Invoke((Action)(() => messageList.Add(read)));
Slight modification for task based async methods but the code in here will not be awaited.
await Windows.ApplicationModel.Core.CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal,
() =>
{
// Your UI update code goes here!
}
).AsTask();
This code WILL await, and will allow you to return a value:
private async static Task<string> GetPin()
{
var taskCompletionSource = new TaskCompletionSource<string>();
CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal,
async () =>
{
var pin = await UI.GetPin();
taskCompletionSource.SetResult(pin);
}
);
return await taskCompletionSource.Task;
}
And on Android:
private async Task<string> GetPin()
{
var taskCompletionSource = new TaskCompletionSource<string>();
RunOnUiThread(async () =>
{
var pin = await UI.GetPin();
taskCompletionSource.SetResult(pin);
});
return await taskCompletionSource.Task;
}
Maby this is not a "good" practice, but it works.. I leave a message from webSocket, to mainBody instance, where I have a timered reader...
public class C_AUTHORIZATION
{
public Observer3.A_MainPage_cl parentPageInstance; //еще одни экземпляр родителя
public WebSocket x_Websocket;
private string payload = "";
private DateTime nowMoment = DateTime.Now;
public void GET_AUTHORIZED()
{
bitfinex_Websocket= new WebSocket("wss://*****.com/ws/2");
var apiKey = "";
var apiSecret = "";
DateTime nowMoment = DateTime.Now;
payload = "{}";
x_Websocket.Opened += new EventHandler(websocket_Opened);
x_Websocket.Closed += new EventHandler(websocket_Closed);
}
void websocket_Opened(object sender, EventArgs e)
{
x_Websocket.Send(payload);
parentPageInstance.F_messager(payload);
}
void websocket_Closed(object sender, EventArgs e)
{
parentPageInstance.F_messager("L106 websocket_Closed!");
GET_AUTHORIZED();
}
}
public sealed partial class A_MainPage_cl : Page
{
DispatcherTimer ChartsRedrawerTimer;
public bool HeartBeat = true;
private string Message;
public A_MainPage_cl()
{
this.InitializeComponent();
ChartsRedrawerTimer = new DispatcherTimer() { Interval = new TimeSpan(0, 0, 0, 0, 100) };
ChartsRedrawerTimer.Tick += Messager_Timer;
ChartsRedrawerTimer.Start();
}
private void Messager_Timer(object sender, object e)
{
if(Message !=null) //
{
F_WriteLine(Message);
Message = null; //
}
}
public void F_messager(string message) //
{
Message = message;
}
In Xamarin, I got around this by using:
Device.BeginInvokeOnMainThread(() => {
// code goes here
});

Why does PlaybackState remain at Playing after PlaybackStopped fires?

I'm a little new to using NAudio so I'm surely missing something important, hence this question.
Starting with example/demo code, I put together a class as simple as I could make it to play MP3 or WAV files:
public class AudioPlayer : IDisposable
{
WaveStream _waveStream; // sound data stream
WaveChannel32 _waveChannel32; // sound channel ??
IWavePlayer _iWavePlayer; // sound output driver
public bool IsPlaying
{
get { return _iWavePlayer != null
&& _iWavePlayer.PlaybackState
!= Wave.PlaybackState.Stopped; }
}
public PlaybackState PlaybackState
{
get { return _iWavePlayer.PlaybackState; }
}
public void LoadMp3(byte[] mp3Bytes)
{
Load(CreateInputStreamFromMp3Bytes(mp3Bytes));
}
public void LoadFile(string filename)
{
Load(CreateInputStream(filename));
}
void Load(WaveStream waveStream)
{
if (_iWavePlayer != null)
Dispose();
_iWavePlayer = new WaveOut();
_iWavePlayer.PlaybackStopped +=
new EventHandler(_iWavePlayer_PlaybackStopped);
_waveStream = waveStream;
_waveChannel32 = new WaveChannel32(_waveStream);
_waveChannel32.PadWithZeroes = false;
_iWavePlayer.Init(_waveChannel32);
}
void _iWavePlayer_PlaybackStopped(object sender, EventArgs e)
{
Stop();
}
static WaveStream CreateInputStreamFromMp3Bytes(byte[] mp3Bytes)
{
return new Mp3FileReader(new MemoryStream(mp3Bytes), false);
}
static WaveStream CreateInputStream(string fileName)
{
if (fileName.EndsWith(".wav"))
return new WaveFileReader(fileName);
else if (fileName.EndsWith(".mp3"))
return new Mp3FileReader(fileName);
else
throw new InvalidOperationException("Unsupported extension");
}
public void Play()
{
_iWavePlayer.Play();
}
public void Stop()
{
if (_iWavePlayer != null
&& _iWavePlayer.PlaybackState != PlaybackState.Stopped) {
_iWavePlayer.Stop();
_waveStream.Position = 0;
}
}
public void Dispose()
{
Stop();
if (_iWavePlayer != null) {
_iWavePlayer.Dispose();
_iWavePlayer = null;
}
if (_waveChannel32 != null) {
_waveChannel32.Dispose();
_waveChannel32 = null;
}
if (_waveStream != null) {
_waveStream.Dispose();
_waveStream = null;
}
}
}
I'm using the code in question to play MP3 files (not WAVs).
It works ok for the most part, which is pretty awesome considering that I'll be able to replace MediaElements in my project. The issue I'm having is that the PlaybackState stays at Playing rather than changing to Stopped once PlaybackStopped fires. To go around that, I subscribe to PlaybackStopped and call Stop() from there.
Is it normal that I have to call Stop() like that, or is there is something I am missing here?
Looks like a bug. If you look at NAudio code WaveOut will not change PlaybackState in RaisePlaybackStoppedEvent. But DirectSoundOut will change it to stopped. A little crazy.
Try this:
In the Load method change this line:
_iWavePlayer = new WaveOut();
by this:
_iWavePlayer = new WaveOut(WaveCallbackInfo.FunctionCallback());

Categories

Resources