I've recently upgraded my WP7 app to Mango and am having some problems with the camera. The code below used to work on 7.0, but on 7.1 the completed handler fires before the dialog is even shown, so I can't capture the result. After taking the photo, the phone displays "Resuming..." which it never used to do.
var dlg = new CameraCaptureTask();
dlg.Completed += (s, e) =>
{
if (e.TaskResult == TaskResult.OK) {
BitmapImage bmp = new BitmapImage();
bmp.SetSource(e.ChosenPhoto);
//var img = new Image();
//img.Source = bmp;
string caption = string.Empty;
var inputDialog = new InputPrompt()
{
Title = "Caption",
Message = "Enter caption/description for snapshot",
};
inputDialog.Completed += (ss, ee) =>
{
if (ee.PopUpResult == PopUpResult.Ok)
{
caption = ee.Result;
var snap = SnapshotBLL.AddSnapshot(recipeId, bmp, caption);
onComplete(null, new SnapshotEventArgs(snap));
}
};
inputDialog.Show();
}
};
dlg.Show();
The MSDN docs appear to show a variation of my code but I can no longer get the result of the camera capture task.
Assuming that your sample comes from a single method I wouldn't expect it to ahve worked pre Mango.
The CameraCaptureTask should be created and the callback assigned in the constructor of the page for it to work properly.
Something like:
public partial class MainPage : PhoneApplicationPage
{
private CameraCaptureTask cct = new CameraCaptureTask();
public MainPage()
{
InitializeComponent();
cct.Completed += new EventHandler<PhotoResult>(cct_Completed);
}
private void cct_Completed(object sender, PhotoResult e)
{
// Do whatever here
}
private void SomeEventHandler(object sender, RoutedEventArgs e)
{
cct.Show();
}
}
This works in both 7.0 & 7.1
Related
I am building a camera application in Xamarin.Forms with a custom renderer.
Android.
I want to emit a shutter sound when the camera shutter button is pressed.
Currently, I have the TalkePhotoButtonClickedHandler as shown below.
private async void TakePhotoButtonClickedHandler(object sender, EventArgs e)
{
if (this.imageAvailableListener == null)
{
this.imageAvailableListener = new ImageAvailableListener(this);
}
var bitmap = this.texture.Bitmap;
CameraManager manager = (CameraManager)MainActivity.context.GetSystemService(Context.CameraService);
try
{
CameraCharacteristics characteristics = manager.GetCameraCharacteristics(this.device.Id);
StreamConfigurationMap map = characteristics.Get(CameraCharacteristics.ScalerStreamConfigurationMap) as StreamConfigurationMap;
Size[]? jpegSize = map.GetOutputSizes((int)ImageFormatType.Jpeg);
int ww = jpegSize[0].Width;
int hh = jpegSize[0].Height;
ImageReader reader = ImageReader.NewInstance(ww, hh, ImageFormatType.Jpeg, 1);
List<Surface> outputSurfaces = new List<Surface>(2);
outputSurfaces.Add(reader.Surface);
outputSurfaces.Add(new Surface(this.texture.SurfaceTexture));
CaptureRequest.Builder captureBuilder = this.device.CreateCaptureRequest(CameraTemplate.StillCapture);
captureBuilder.AddTarget(reader.Surface);
captureBuilder.Set(CaptureRequest.ControlMode, (int)ControlMode.Auto);
reader.SetOnImageAvailableListener(imageAvailableListener, backgroundHandler);
var sessionListener = new CameraSessionCallback(this);
this.device.CreateCaptureSession(
outputSurfaces,
new CameraStateCallback(captureBuilder, sessionListener, this.backgroundHandler),
this.backgroundHandler
);
}
catch (CameraAccessException ex)
{
throw ex;
}
}
It looks like I should write the shutter callback here.
private Camera.ShutterCallback mShutterListener =
new Camera.ShutterCallback() {
public void onShutter() {
// empty OK。
}
};
private Camera.PictureCallback mPictureListener =
new Camera.PictureCallback() {
public void onPictureTaken(byte[] data, Camera camera) {
}
};
I found the Java code, but how can I write it in C#?
I use Xamarin.Essentials: Media Picker to take photo, a shutter sound when the camera shutter button is pressed.
<StackLayout>
<Image x:Name="PhotoImage" />
<Button
x:Name="takephoto"
Clicked="takephoto_Clicked"
Text="take photo" />
</StackLayout>
private async void takephoto_Clicked(object sender, EventArgs e)
{
var result = await Xamarin.Essentials.MediaPicker.CapturePhotoAsync();
if (result != null)
{
var stream = await result.OpenReadAsync();
takephoto.ImageSource = ImageSource.FromStream(() => stream);
}
}
I have 2 TapGestureRecognizers on my custom control:
1)
The first one is internal / exists only within the custom control.
2)
The second one is attached on the page on which the custom control is instanciated.
I'm using the first TapGestureRecognizer to trigger an animation at a Tap internally / within the custom control, and the second TapGestureRecognizer is used to track Taps on the custom control on the Page so that I can react to taps.
It feels wrong to do the animation "outside" / on the Page as every instance of this control should animate, that's why I attached a TapGestureRecognizer within the custom control.
However, when I do this, only the "internal" TapGestureRecognizer works, the one on the outside doesn't.
Is that normal behaviour?
public class clsGridCell : ContentView
{
var _Grid1ContainerForImageAndLabel = new Grid()
{
}
var nTapRec = new TapGestureRecognizer();
nTapRec.Tapped += OnItemSelected;
_Grid1ContainerForImageAndLabel.GestureRecognizers.Add(nTapRec);
this.Content = _Grid1ContainerForImageAndLabel;
}
private async void OnItemSelected(object sender, EventArgs e)
{
await Task.WhenAny<bool>
(
_image1.ScaleTo(0.9, 50, Easing.Linear)
);
//run some background color animation, too
}
And "outside" / on the Page:
public class MainPage : ContentPage
{
var nGridCell = new clsGridCell
{
ImageSource = nImgSrc,
BackgroundColor = Color.Blue;
};
_BigGrid.Children.Add(nGridCell);
var nTapRec = new TapGestureRecognizer();
nTapRec.Tapped += OnItemSelected;
nGridCell.GestureRecognizers.Add(nTapRec);
private async void OnItemSelected(object sender, EventArgs e)
{
//Not fired! When I remove the "internal" TapGestureRecognizer, it does work
Just create the internal TapGestureRecognizer as a public/internal property of the class and, instead of creating a new Gesture "outside", add a new Tapped action to the class' TapGestureRecognizer. Like this:
public class clsGridCell : ContentView
{
public TapGestureRecognizer TapGesture { get; set; }
Action<clsGridCell> tap;
public Action<clsGridCell> Tap
{
get => tap;
set
{
tap = value;
TapGesture.Tapped += (sender, e) => { value(this); };
}
}
public clsGridCell()
{
var _Grid1ContainerForImageAndLabel = new Grid() { };
TapGesture = new TapGestureRecognizer();
TapGesture.Tapped += OnItemSelected;
_Grid1ContainerForImageAndLabel.GestureRecognizers.Add(TapGesture);
this.Content = _Grid1ContainerForImageAndLabel;
}
private async void OnItemSelected(object sender, EventArgs e)
{
await Task.WhenAny<bool> ( _image1.ScaleTo(0.9, 50, Easing.Linear) ); //run some background color animation, too
}
}
And outside use myGrid.Tap = Method;
I have a list picker which is displayed in my phone application page.I have created list picker in starting of class,and i am adding the list picker in the phoneApplicationPage_loaded() method.When the page is launched the first time, ,the scenario works perfectly and its navigates further to second page.When i navigate back to previous page(containing list picker),it shows Invalid Operation Exception occured stating "Element is already the child of another element."
I want to know how to handle these scenarios?
Code is below
namespace My.Design
{
public partial class myclass : PhoneApplicationPage
{
String[] values = null;
ListPicker picker = new ListPicker();
StackPanel sp;
StackPanel mainFrame;
String statementInfo = "";
public myclass()
{
InitializeComponent();
}
private void PhoneApplicationPage_Loaded(object sender, RoutedEventArgs e)
{
Debug.WriteLine("Phone Application Page Loaded_>>>>>>");
List<String> source = new List<String>();
displayUI();
}
public void displayUI()
{
Debug.WriteLine("About to display UI in miniStatement");
Debug.WriteLine("<-------------Data--------->");
Debug.WriteLine(statementInfo);
Debug.WriteLine("<-------------Data--------->");
int count = VisualTreeHelper.GetChildrenCount(this);
if (count > 0)
{
for (int i = 0; i < count; i++)
{
UIElement child = (UIElement)VisualTreeHelper.GetChild(this, i);
string childTypeName = child.GetType().ToString();
Debug.WriteLine("Elements in this Child" + childTypeName);
}
}
List<String> source = new List<String>();
String[] allParams = ItemString.Split('#');
source.Add("PleaseSelect");
for (int i = 0; i < allParams.Length; i++)
{
Debug.WriteLine("All Params Length" + allParams[i]);
if (!(allParams[i].Equals("") && (!allParams[i].Equals(null))))
{
if (values != null)
{
Debug.WriteLine("Values length" + values.Length);
values[values.Length] = allParams[i];
}
else
{
Debug.WriteLine("Allparams Length" + allParams[i]);
source.Add(allParams[i]);
}
}
}
//picker = new ListPicker();
this.picker.ItemsSource = source;
mainFrame = new StackPanel();
TextBlock box = new TextBlock();
box.Text = "> DEmoClass";
box.FontSize = 40;
mainFrame.Children.Add(box);
Canvas canvas = new Canvas();
StackPanel sp = new StackPanel();
TextBlock box1 = new TextBlock();
box1.Text = "Number";
box1.HorizontalAlignment = HorizontalAlignment.Center;
box1.FontSize = 40;
SolidColorBrush scb1 = new SolidColorBrush(Colors.Black);
box1.Foreground = scb1;
sp.Children.Add(box1);
picker.Width = 400;
picker.Height = 150;
sp.Children.Add(picker);
Canvas.SetTop(sp, 150);
canvas.Children.Add(sp);
mainFrame.Children.Add(canvas);
this.ContentPanel1.Children.Add(mainFrame);
}
protected override void OnNavigatingFrom(System.Windows.Navigation.NavigatingCancelEventArgs e)
{
/*
Debug.WriteLine("OnNavigatingFrom>>>.>>MainPage");
if (sp != null)
{
sp.Children.Remove(picker);
}*/
base.OnNavigatingFrom(e);
}
}
}
If you are not intending to update the listpicker after navigating back from the second page add the following line in your Loaded event handler
private void PhoneApplicationPage_Loaded(object sender, RoutedEventArgs e)
{
this.Loaded -= PhoneApplicationPage_Loaded;
Debug.WriteLine("Phone Application Page Loaded_>>>>>>");
List<String> source = new List<String>();
displayUI();
}
i don't know why you can not use that case when app resume from tombstoned.
error happened because when you back to your page , loaded event runs again.
by the way,
Application_Activated 's argument can tell you app resumes from tombstoned or not--.
if (e.IsApplicationInstancePreserved)
{
IsTombstoning = false;
}
else
{
IsTombstoning = true;
}
I'm curious why you're creating it in code and not leaving it in XAML? Also the error is coming from the fact that you're attempting to add it twice into a location that can probably only have a single content element. What's the higher level problem you're trying to solve?
I've to download an image from the server on button click.
The code is:
private void Button_Click(object sender, RoutedEventArgs e)
{
(sender as Button).IsEnabled = false;
progressbar.IsIndeterminate = true;
WebClient w = new WebClient();
w.OpenReadAsync(new Uri("http://example.com/xxx/image.png"));
w.OpenReadCompleted += new OpenReadCompletedEventHandler(w_OpenReadCompleted);
}
void w_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e)
{
progressbar.IsIndeterminate = false;
BitmapImage b = new BitmapImage();
b.SetSource(e.Result);
Image img = new Image();
img.Source = b;
LayoutRoot.Children.Add(img);
}
The problem which I'm facing is that for the first time the data is being downloaded from the server and shown correctly. However, if I quit the application and again start it, it downloads the old image even if I have deleted the image from the server or changed the image. I think the image is getting cached somewhere but don't know how to solve this problem.
I think this will be the same as your issue:
How do you disable caching with WebClient and Windows Phone 7
I haven't noticed this behaviour when using the HttpWebRequest to get data. But I'am not sure about it.
Update: HttpWebRequest has by default the same behaviour but can be disabled. This blogpost is talking about the options you have:
http://www.nickharris.net/2010/10/windows-phone-7-httpwebrequest-returns-same-response-from-cache/
Finally managed to fix it.The only change that was made is:
w.OpenReadAsync(new Uri("http://example.com/xxx/image.png?q="+Guid.NewGuid()));
You could also use HttpWebRequest to download fresh data every request. Here is a simple class which sets up the asynchronous calls
Here is a simple http client which will download data from the given uri.
public static class HttpClient
{
public static void Execute(Uri uri, Action<HttpWebRequest> onrequest, Action<HttpWebResponse> onresponse)
{
var request = HttpWebRequest.CreateHttp(uri);
onrequest(request);
request.BeginGetResponse
(
result =>
{
try
{
if (request.HaveResponse)
onresponse((HttpWebResponse)request.EndGetResponse(result));
}
catch { }
},
null
);
}
}
Using the HttpClient with your button click event you get this
private void Button_Click(object sender, RoutedEventArgs e)
{
(sender as Button).IsEnabled = false;
progressbar.IsIndeterminate = true;
HttpClient.Execute
(
new Uri(http://example.com/xxx/image.png),
request =>
{
request.UserAgent = "Custom HTTP Client";
},
response =>
{
progressbar.IsIndeterminate = false;
BitmapImage b = new BitmapImage();
b.SetSource(response.GetResponseStream());
Image img = new Image();
img.Source = b;
LayoutRoot.Children.Add(img);
}
);
}
I'm using this to make a web request and download some data:
public partial class MainPage : PhoneApplicationPage
{
public MainPage()
{
InitializeComponent();
var client = new WebClient();
client.DownloadStringCompleted += (s, e) => {
textBlock1.Text = e.Result;
};
client.DownloadStringAsync(new Uri("http://example.com"));
}
}
The text of textBlock1 never changes even though e.Result has the correct data. How do I update that from the callback?
Edit: If I add MessageBox.Show(e.Result); in the callback along with the textBlock1.Text assignment, both the messsage box and the text box show the correct data.
Edit Again: If I add a TextBox and set it's text right after the line textBlock1.Text line, they both show the correct text.
I think, it's a bug.
I also ran into some problems with updating the UI from different dispatchers. What I finally did was use the TextBlock's (or other UI Element) own dispatcher and that worked for me. I think the phone framework may be using different dispatchers between the app and UI Elements. Notice the change from dispatcher.BeginInvoke to textbox1.Dispatcher...
void MainPage_Loaded(object sender, RoutedEventArgs e)
{
var dispatcher = Deployment.Current.Dispatcher;
var client = new WebClient();
client.DownloadStringCompleted += (s, e) =>
{
var result = e.Result;
textBlock1.Dispatcher.BeginInvoke(
()=> textBlock1.Text = result
);
};
client.DownloadStringAsync(new Uri("http://example.com"));
}
From browsing through the WP7 forums, a bunch of people were reporting that this was related to a video card driver issue. I've updated my ATI Radeon HD 3400 drivers to the latest version and it appears to work now.
client.DownloadStringAsync is expecting a Uri like this:
client.DownloadStringAsync(new Uri("http://example.com"));
also, shouldn't you update your TextBlock through a Dispatcher.BeginInvoke like this:
client.DownloadStringCompleted += (s, e) =>
{
if (null == e.Error)
Dispatcher.BeginInvoke(() => UpdateStatus(e.Result));
else
Dispatcher.BeginInvoke(() => UpdateStatus("Operation failed: " + e.Error.Message));
};
public partial class MainPage : PhoneApplicationPage
{
public MainPage()
{
InitializeComponent();
Loaded += MainPage_Loaded;
}
void MainPage_Loaded(object sender, RoutedEventArgs e)
{
var dispatcher = Deployment.Current.Dispatcher;
var client = new WebClient();
client.DownloadStringCompleted += (s, e) =>
{
var result = e.Result;
dispatcher.BeginInvoke(
()=> textBlock1.Text = result
);
};
client.DownloadStringAsync(new Uri("http://example.com"));
}
}
I want to comment but can't yet. Yes, I have a very similar issue. In my case it's my viewmodel that is updating a DownloadStatus property, then when the download is completed I do some more work and continue updating this property.
The view stops updating once the ViewModel code hits the OpenReadCompleted method. I've stepped carefully through the code. PropertyChanged fires, and the view even comes back and retrieves the new property value, but never shows the change.
I was sure it was a bug, but then I created a brand new project to reproduce the issue, and it works fine!
Here's a snippet of my non-reproducing code. The UI textblock bound to "DownloadStatus" happily updates properly all the way through. But the same paradigm doesn't work in my main project. Infuriating!
public void BeginDownload(bool doWorkAfterDownload)
{
DownloadStatus = "Starting ...";
_doExtraWork = doWorkAfterDownload;
var webClient = new WebClient();
string auth = "Basic " + Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes("test:password"));
webClient.Headers["Authorization"] = auth;
webClient.DownloadProgressChanged += new DownloadProgressChangedEventHandler(webClient_DownloadProgressChanged);
webClient.OpenReadCompleted += new OpenReadCompletedEventHandler(webClient_OpenReadCompleted);
webClient.OpenReadAsync(new Uri("http://www.ben.geek.nz/samsung1.jpg"));
}
void webClient_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e)
{
if (e.Error != null)
{
DownloadStatus = e.Error.Message;
return;
}
DownloadStatus = "Completed. Idle.";
if(_doExtraWork)
{
Thread t = new Thread(DoWork);
t.Start(e.Result);
}
}
void DoWork(object param)
{
InvokeDownloadCompleted(new EventArgs());
// just do some updating
for (int i = 1; i <= 10; i++)
{
DownloadStatus = string.Format("Doing work {0}/10", i);
Thread.Sleep(500);
}
DownloadStatus = "Completed extra work. Idle.";
InvokeExtraWorkCompleted(new EventArgs());
}