WP81 binding an image fails, setting local fallback image loses original binding - windows-phone-8.1

I am binding the ImageSource of an ImageBrush on Windows Phone 8.1 (RT not silverlight) to a remote uri, and have a handler when the image fails to show a default image:
<ImageBrush Stretch="UniformToFill" ImageSource="{Binding MyBackgroundUrl}" ImageFailed="ImageBrush_ImageFailed"/>
in the code behind I update the image source property to set it to a local image:
protected void ImageBrush_ImageFailed(object sender, ExceptionRoutedEventArgs e)
{
var img = sender as ImageBrush;
if (img == null) return;
var uri = new BitmapImage(new Uri("ms-appx:///Assets/App/MyDefaultBackground.jpg"));
img.ImageSource = uri;
}
this works GREAT, however by doing this, I am losing the original binding, so that if I reload the same screen with a DIFFERENT binding value, it doesn't re-bind.
This makes sense given what I'm doing, so in that case my question is what did I do wrong and how can I correctly setup a fallback image while allowing the image to re-bind itself when it reloads?

Of course you are. You are overwriting the binding. You have to set the property like this:
void ImageBrush_ImageFailed(object sender, ExceptionRoutedEventArgs e)
{
var img = sender as ImageBrush;
if (img == null) return;
var uri = new BitmapImage(new Uri("ms-appx:///Assets/App/MyDefaultBackground.jpg"));
var vm = img.DataContext as MainPageViewModel;
vm.MyBackgroundUrl = uri;
}
If you don't like that, then you can have two images. One on top of the other and set its visibility based on failure. Something like this pseudo code:
var img = new Image();
// you would not new it up here, you would ref your control.
img.ImageOpened += (s, e) => OverlayImage.Visibility = Visibility.Collapsed;
img.ImageFailed += (s, e) => OverlayImage.Visibility = Visibility.Collapsed;
Make sense to you?
I just noticed you are talking about an image brush and not an image. The logic should be the same, but instead of an overlay it might need to be an underlay. Also, because it is an underlay, you might not need to toggle its visibility since the successful image brush will occlude the underlay. Might be even easier in your case.
Best of luck!

Related

windows phone 8.1 dispaly PreviewFrame and calculate mean value of red pixels for every frame

Currently I'm using Lumia.Imaging to get preview frame and display it.
I create new method "GetPreview()" to go though pixels, find red pixel and than I would like to calculate mean value of red pixels for every frame.
My problem is that when I'm going through pixel there are lags in app :(
What is the proper solution to calculate mean of red pixels for every frame without performance loss?
Additional how to turn on Flash light when preview starts ?
private async Task startCameraPreview()
{
// Create a camera preview image source (from the Lumia Imaging SDK)
_cameraPreviewImageSource = new CameraPreviewImageSource();
// Checking id of back camera
DeviceInformationCollection devices = await Windows.Devices.Enumeration.DeviceInformation.FindAllAsync(Windows.Devices.Enumeration.DeviceClass.VideoCapture);
String backCameraId = devices.FirstOrDefault(x => x.EnclosureLocation != null && x.EnclosureLocation.Panel == Windows.Devices.Enumeration.Panel.Back).Id;
await _cameraPreviewImageSource.InitializeAsync(backCameraId); // use the back camera
var previewProperties = await _cameraPreviewImageSource.StartPreviewAsync();
fps = previewProperties.FrameRate.Numerator/previewProperties.FrameRate.Denominator;
_cameraPreviewImageSource.PreviewFrameAvailable += drawPreview; // call the drawPreview method every time a new frame is available
// Create a preview bitmap with the correct aspect ratio using the properties object returned when the preview started.
var width = 640.0;
var height = (width / previewProperties.Width) * previewProperties.Height;
var bitmap = new WriteableBitmap((int)width, (int)height);
_writeableBitmap = bitmap;
// Create a BitmapRenderer to turn the preview Image Source into a bitmap we hold in the PreviewBitmap object
_effect = new FilterEffect(_cameraPreviewImageSource);
_effect.Filters = new IFilter[0]; // null filter for now
_writeableBitmapRenderer = new WriteableBitmapRenderer(_effect, _writeableBitmap);
}
private async void drawPreview(IImageSize args)
{
// Prevent multiple rendering attempts at once
if (_isRendering == false)
{
_isRendering = true;
await _writeableBitmapRenderer.RenderAsync(); // Render the image (with no filter)
// Draw the image onto the previewImage XAML element
await Windows.ApplicationModel.Core.CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.High,
() =>
{
getPreview();
previewImage.Source = _writeableBitmap; // previewImage is an image element in MainPage.xaml
_writeableBitmap.Invalidate(); // force the PreviewBitmap to redraw
});
_isRendering = false;
}
}
private void getPreview()
{
var pixelBuffer = _writeableBitmap.PixelBuffer;
for (uint i = 0; i + 4 < pixelBuffer.Length; i += 4)
{
var red = pixelBuffer.GetByte(i + 2);
}
}
Instead of inspecting all pixels after the Lumia Imaging SDK has processed the image, but before you invalidate the bitmap you could:
Invalidate the writeable bitmap imidiatelly then do your analysis step in a seperate async Task. That means that the content will be displayed right away, and your analysis will be done seperatelly. Some pseudocode based on your sample would be:
await Windows.ApplicationModel.Core.CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.High, () => {
var analysisTask = Task.Run(() => getPreview());
previewImage.Source = _writeableBitmap; // previewImage is an image element in MainPage.xaml
_writeableBitmap.Invalidate(); // force the PreviewBitmap to redraw
await analysisTask;
});
This way the task of analysing the image doesn't block the update on the screen. Of course this option might not be viable if you need the result of the analysis in the rendering chain itself.
Create a custom filter for the analysis, this way you will be able to take advantage of the optimized Lumia Imaging SDK processing.
To get started on writing custom filters look at the documentation.

Change Layout / Frames in MvvmCross Dialog Elements

I am trying to lightly customise by inheritance some Elements in Mvvmcross Dialog implementation.
Colors and fonts are getting set fine, but if I try to set the Text Labels frame (to 100 X ... in this example) I cannot get it to stick.
Can anyone point me in the direction of where I am going wrong here? tried it in a couple different places.
public class MyBooleanElement : BooleanElement {
public MyBooleanElement (string caption) : base(caption, false)
{
}
protected override UISwitch CreateSwitch()
{
UISwitch s = base.CreateSwitch();
s.BackgroundColor = UIColor.Clear;
s.Opaque = false;
s.Layer.Opacity = 0.25f;
return s;
}
protected override UITableViewCell GetCellImpl(UITableView tv)
{
var cell = base.GetCellImpl(tv);
if (cell.BackgroundColor != UIColor.Clear) {
cell.BackgroundColor = UIColor.Clear;
cell.TextLabel.Font = Theme.GetContentFont();
cell.TextLabel.TextColor = UIColor.White;
cell.TextLabel.Frame = new RectangleF(100, 0, 320, 20); // this is not holding, resets to 15
cell.ContentView.Frame = new RectangleF(50, cell.ContentView.Frame.Top, cell.ContentView.Frame.Width, cell.ContentView.Frame.Height); // try this also?
}
return cell;
}
protected override void UpdateCaptionDisplay(UITableViewCell cell)
{
base.UpdateCaptionDisplay(cell);
if (cell != null) {
cell.TextLabel.Frame = new RectangleF(100, 0, 320, 20); // this is not holding, resets to 15
cell.TextLabel.BackgroundColor = UIColor.Blue; // Yet this works? some constraints somewhere cannot see in source!
}
}
}
The dialog part of the framework is positioning the headers (labels) and controls for you.
You should look at the source code a bit, maybe try to understand how it works a little bit.
You can start with a breakpoint and step into the source code while debugging. I'm sure you are going to see where the 15 value is being set.
I'm sorry I can't give you an exact answer. I had some issues myself with the incorrect positioning of dialog elements on iPad, and I had to dig a bit.

WP8 Deleting Images from Map (Error when navigating back to page)

I have a Map that has several Images placed on it (inside the page_loaded event)
MapLayer pinLayer = new MapLayer();
MapOverlay pin50 = new MapOverlay();
pin50.GeoCoordinate = new GeoCoordinate(49.42563670946435, -0.44644108276367537);
Canvas myCanvas50 = new Canvas();
// The image is defined globally
pin50.PositionOrigin = new Point(0.5, 0.5);
image50.Source = new BitmapImage(new Uri("Images/Destroyer.png", UriKind.Relative));
image50.Opacity = 1;
Point point50 = new Point(1.0, 1.0);
Canvas.SetLeft(image50, point50.X);
Canvas.SetTop(image50, point50.Y);
myCanvas50.Children.Add(image50); // <=== ERROR OCCURS HERE
// Making an event handler for the image so that we can 'tap' on it
image50.DoubleTap += image50_DoubleTap;
pin50.Content = myCanvas50;
pinLayer50.Add(pin50);
map_J.Layers.Add(pinLayer);
It works fine for all of the Images, however when I click on an Image it navigates to a new page and gives a description of the Image that was clicked on.
The problem is that when a user navigates back to this map (by intuitively pressing the hardware BACK BUTTON) the app crashes due to the error "Element is already the child of another element."
I'm guessing that the page is still loaded so when it is navigated back to it gets 're-loaded' so can't add the same Image to the same canvas etc.
I tried adding the following to clear all information from the map before navigating away from the page but it doesn't help:
protected override void OnNavigatedFrom(NavigationEventArgs e)
{
base.OnNavigatedFrom(e);
var toRemove = new List<MapLayer>();
foreach (MapLayer lyr in map_J.Layers)
{
toRemove.Add(lyr);
}
// now do the actual removal
foreach (var child in toRemove)
{
map_J.Layers.Remove(child);
}
}
Any ideas? Is there a better way to handle the reloading of the map/elements?
I would recommend clearing the map layers everytime the user leaves the page.
Add this code to the main tag in the XAML code of the view:
<phone:PhoneApplicationPage
...
Unloaded="PhoneApplicationPage_Unloaded" >
And this event code behind:
private void PhoneApplicationPage_Unloaded(object sender, RoutedEventArgs e)
{
map_J.Layers.Clear();
}

Draw route on Windows Phone 8 map as position changes?

Scenario:
I want a user to see a map and their current position. Then, if they click "start", navigation will begin and they'll see their "route" drawn onto the map as their position changes, similar to how some fitness apps work that map out your run/walk. The goal is to do this in real-time as the user's position changes.
Options:
The way I see it, there are two options: 1) use a RouteQuery and Map.AddRoute from the starting position, to the next position (when the position changes), keeping track of the last position, and always drawing a new MapRoute from that position to the new, or 2) displaying the user's current position as a dot that moves as their position changes, and then maybe when they press "stop", draw a MapRoute for each of their positions in order to show their full route.
I'd really prefer option #1 because the user can see their route progression, etc., as they go.
Here is the code that I'm using:
XAML:
<maps:Map x:Name="MainMap" />
<Button x:Name="btnStart" Content="Start"/>
<Button x:Name="btnStop" Content="Stop" IsEnabled="False"/>
Code-behind:
Global Variables:
GeoCoordinateWatcher watcher;
List<GeoCoordinate> listCoordinates;
GeoCoordinate lastCoordinate;
btnStart.Tap():
private void btnStart_Tap(object sender, GestureEventArgs e)
{
if (watcher == null)
{
watcher = new GeoCoordinateWatcher(GeoPositionAccuracy.High);
watcher.MovementThreshold = 20;
watcher.StatusChanged += watcher_StatusChanged;
watcher.PositionChanged += watcher_PositionChanged;
}
watcher.Start();
}
watcher.StatusChanged():
private void watcher_StatusChanged(object sender, GeoPositionStatusChangedEventArgs e)
{
switch (e.Status)
{
case GeoPositionStatus.Initializing:
btnStart.IsEnabled = false;
btnStop.IsEnabled = true;
break;
case GeoPositionStatus.NoData:
lblStatus.Text = "location data is not available.";
break;
case GeoPositionStatus.Ready:
lblStatus.Text = "location data is available.";
break;
}
}
watcher.PositionChanged():
void watcher_PositionChanged(object sender, GeoPositionChangedEventArgs<GeoCoordinate> e)
{
if (listCoordinates == null)
{
// first time through:
listCoordinates = new List<GeoCoordinate>();
listCoordinates.Add(e.Position.Location);
lastCoordinate = e.Position.Location;
return;
}
else
{
listCoordinates.Add(e.Position.Location);
DrawRoute(e.Position.Location);
lastCoordinate = e.Position.Location;
}
}
DrawRoute function:
private void DrawRoute(GeoCoordinate newPosition)//
{
RouteQuery query = new RouteQuery()
{
TravelMode = TravelMode.Driving,
Waypoints = new List<GeoCoordinate>() { MainMap.Center, newPosition }
};
query.QueryCompleted += RouteQueryCompleted;
query.QueryAsync();
MainMap.Center = newPosition;
lastCoordinate = newPosition;
}
And finally, RouteQueryCompleted():
void RouteQueryCompleted(object sender, QueryCompletedEventArgs<Route> e)
{
mapRoute = new MapRoute(e.Result);
MainMap.AddRoute(mapRoute);
}
What happens:
It appears to work for a second as I begin driving, a short line is drawn where my start position is, but then about 10 second in, a line is randomly drawn down a nearby street (probably equivalent to 3 or 4 blocks long) and then down another block on a side road (while the whole time I haven't even driven ONE block, let alone make any turns!). It's very bizarre and definitely not accurate. I can upload a screenshot to better illustrate it if need be.
Can anyone see what I'm doing wrong in my code or is there a better way to accomplish this? I wasn't sure if this was the best way but I wasn't able to find any examples suggesting otherwise.
I ended up using MapPolyLine to draw a line between the last GeoCoordinate and the new one.
MapPolyline line = new MapPolyline();
line.StrokeColor = Colors.Blue;
line.StrokeThickness = 15;
line.Path.Add(lastCoordinate);
line.Path.Add(pos);
MainMap.MapElements.Add(line);
I am not sure why you are using RouteQuery for your task. Generally, you use this when you want the map sdk to determine a route for you given a set of coordinates. In your case however, you always know where you are through PositionChanged event. It will be easier to plot directly on the map as you move.
Something like this
void watcher_PositionChanged(object sender, GeoPositionChangedEventArgs<GeoCoordinate> e) {
Plot(e.Position.Location);
}
void Plot(GeoCoordinate pos) {
var ellipse = new Ellipse();
ellipse.Fill = new SolidColorBrush(System.Windows.Media.Colors.Blue);
ellipse.Height = 15;
ellipse.Width = 15;
ellipse.Opacity = 25;
var mapOverlay = new MapOverlay();
mapOverlay.Content = ellipse;
mapOverlay.PositionOrigin = new System.Windows.Point(0.5, 0.5);
mapOverlay.GeoCoordinate = pos;
var mapLayer = new MapLayer();
mapLayer.Add(mapOverlay);
MainMap.Layers.Add(mapLayer);
}

MemoryStream used to save image data in CameraCaptureSequence is 0 even though image data is present in the CameraCaptureSequence

I'm using the PhotoCaptureDevice class and I can capture the camera frame, but when I am getting an error while copying the image data in the CameraCaptureFrame.CaptureSequence of the CameraCaptureSequence into a MemoryStream and then save it in the Camera Roll. This is the code snippet of what I'm trying to do.
PhotoCaptureDevice cam;
cam = await PhotoCaptureDevice.OpenAsync(<front/rear depending on user input>,<resolution depends on user input>);
CameraCaptureSequence seq;
seq = cam.CreateCaptureSequence(1);
cam.SetProperty(KnownCameraGeneralProperties.PlayShutterSoundOnCapture, true);
MemoryStream captureStream1 = new MemoryStream();
seq.Frames[0].CaptureStream = captureStream1.AsOutputStream();//This stream is for saving the image data to camera roll
await cam.PrepareCaptureSequenceAsync(seq);
await seq.StartCaptureAsync();
bool a = seq.Frames[0].CaptureStream.Equals(0);//This value is false during debugging
if(capturestream1.Length>0)//This condition evaluates to false
{
MediaLibrary library = new MediaLibrary();
Picture picture1 = library.SavePictureToCameraRoll("image1", captureStream1);
}
else
{
//Logic to handle condition
}
As I've added in the comments, the variable bool a evaluates to false which I checked by debugging the code. But for some reason the capturestream1.Length property is 0.
Here's a code snippet on how to capture a sequence with a single image and saving that image to the MediaLibrary. Obviously this is a bit of a trivial example for this API since sequence are really good for capturing multiple images and meshing them up together with post-processing.
private async void MainPage_Loaded(object sender, RoutedEventArgs e)
{
using (MemoryStream stream = new MemoryStream())
using (var camera = await PhotoCaptureDevice.OpenAsync(CameraSensorLocation.Back,
PhotoCaptureDevice.GetAvailableCaptureResolutions(CameraSensorLocation.Back).First()))
{
var sequence = camera.CreateCaptureSequence(1);
sequence.Frames[0].CaptureStream = stream.AsOutputStream();
camera.PrepareCaptureSequenceAsync(sequence);
await sequence.StartCaptureAsync();
stream.Seek(0, SeekOrigin.Begin);
using (var library = new MediaLibrary())
{
library.SavePictureToCameraRoll("currentImage.jpg", stream);
}
}
}
When you run this code snippet you can see the image stored on the device:
You can find a full working sample as part of Nokia's Camera Explorer app that demos end-to-end usecases for the WP8 camera APIs: http://projects.developer.nokia.com/cameraexplorer