WP8 Deleting Images from Map (Error when navigating back to page) - windows-phone-8

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

Related

Why is my action script event not firing?

Presently, I am attempting to add the ability to capture all the slides of a presentation to images and save them to disk. It works now where the first page is capture, then I want an async event to fire when the second page has loaded to capture that page, and so on. Here is where I have added an event listener, though I'm not sure if I should be using stage or this:
import flash.events.Event;
private var jpgEncoder:JPGEncoder;
// ...
private function init():void{
// ...
// Add async event to capture second page after loading
stage.loaderInfo.addEventListener(Event.COMPLETE,onLoadComplete);
// ...
}
private function onPrintButtonClicked():void {
// screen capture code
jpgEncoder = new JPGEncoder(90);
// Page 1 capture
bitmapData1 = new BitmapData(stage.width, stage.height);
bitmapData1.draw(stage, new Matrix());
// move to next page
var curPage:Page = PresentationModel.getInstance().getCurrentPage();
if (curPage != null) {
LOGGER.debug("Go to next page. Current page [{0}]", [curPage.id]);
pageCount++;
dispatchEvent(new GoToNextPageCommand(curPage.id));
} else {
LOGGER.debug("Go to next page. CanNOT find current page.");
}
}
private function onLoadComplete(e:Event)
{
// Get page 2 capture
bitmapData2 = new BitmapData(stage.width, stage.height);
bitmapData2.draw(stage, new Matrix());
// Copy two pages to one bitmap
var rect1:Rectangle = new Rectangle(0, 0, stage.width, stage.height);
var pt1:Point = new Point(0, 0);
bitmapData3 = new BitmapData(stage.width, stage.height * 2);
bitmapData3.copyPixels(bitmapData1, rect1, pt1)
var rect2:Rectangle = new Rectangle(0, 0, stage.width, stage.height);
var pt2:Point = new Point(0, stage.height);
bitmapData3.copyPixels(bitmapData2, rect2, pt2)
// Convert to image
var img:ByteArray = jpgEncoder.encode(bitmapData3);
var file:FileReference = new FileReference();
file.save(img, "capture1.jpg");
}
Does anyone have any ideas as to why the OnLoadComplete function is never called? FYI, here is the full source code: https://github.com/john1726/bigbluebutton/blob/master/bigbluebutton-client/src/org/bigbluebutton/main/views/MainToolbar.mxml
TIA
Please note that I've found that the stage was still null in the init() method so an exception was being thrown:
stage.loaderInfo.addEventListener(Event.COMPLETE,onLoadComplete);
Also, after resolving that stage error I found that I have been receiving this error using this tool: https://github.com/capilkey/Vizzy-Flash-Tracer
Error #2176: Certain actions, such as those that display a pop-up window, may only be invoked upon user interaction, for example by a mouse click or button press.
So the solution is either to re-work the UI so that there is a button press to prepare the files and a second button press to actually save the image or setup them mouseup and mousedown events to call different functions:
s:Button mouseDown="prepare_PDF()" mouseUp="save_PDF()"
Source: Flex's FileReference.save() can only be called in a user event handler -- how can I get around this?
Thank you!

WP81 binding an image fails, setting local fallback image loses original binding

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!

Close popup on hardwarebutton backpressed in windows phone 8.1 application

I have a popup that comes on a click event of button..
But I am unable to close the popup..I want to close popup on hardwarebutton_backpress event..
Can anyone plzz tell me how to do so..
I am using this code to show popup
Public void showpopup_click()
{
Popup p =new Popup();
p.child= new Mypopup();
p.Isopen=true;
}
Here Mypopup is my user control..
I am using visual studio and developing a windows phone 8.1 app..
Another approach, in my opinion better, is using the IsLightDismissEnabled property where you don't need to check whether a popup is already open or not, or if you have multiple open popups, everything is handled automatically.
var popup = new Popup();
popup.IsLightDismissEnabled = true;
popup.IsOpen = true;
You have to subscribe to the Windows.Phone.UI.Input.HardwareButtons.BackPressed event to handle the back button with custom logic. If you store the Popup in a field, you can easily set IsOpen property to false.
Like this:
private Popup _popup;
public void showpopup_click()
{
_popup = new Popup();
_popup.Child = new Mypopup();
_popup.IsOpen = true;
Windows.Phone.UI.Input.HardwareButtons.BackPressed += HardwareButtons_BackPressed;
}
private void HardwareButtons_BackPressed(object sender, Windows.Phone.UI.Input.BackPressedEventArgs args)
{
_popup.IsOpen = false;
args.Handled = true;
Windows.Phone.UI.Input.HardwareButtons.BackPressed -= HardwareButtons_BackPressed;
}
In the event handler, you need to set the args.Handled property to true to prevent the application close on the back button pressed. You also need to unsubcrise from the event to avoid memory leak.

put a "back" button in front on an embed map

I've integrate a map from MapQuest in my Adobe Air app (in AS3).
The map is taking all the screen as I want.
BUT, I'd like to add a "back" button in order to go back to the previous menu.
Here's my code :
var NoumeaNord:TileMap = new TileMap("KEYcode");
//set the size of the map
NoumeaNord.size = new Size(800, 533);
//add the map to the sprite.
addChild(NoumeaNord);
NoumeaNord.addControl(new SMLargeZoomControl());
NoumeaNord.addControl(new MouseWheelZoomControl());
NoumeaNord.addShape(new Poi(new LatLng(-22.2758000,166.4580000)));
NoumeaNord.setCenter(new LatLng(-22.2758000,166.4580000),15);
function addBackBtn():void{
var back:MovieClip;
back = new backBtn
addChild(back);
back.x = 0;
back.y = 400;
setChildIndex(back,0);
}
Don't know why but the BackBtn won't be in front of the map !
I've tried with setChildIndex(back,-1); but it makes an error : "RangeError: Error #2006: index is off limit".
Any idea ?
In this situation I use holders like this:
private var bgHolder:Sprite;
private var contentHolder:Sprite;
private var menuHolder:Sprite;
Somewhere in the constructor I run a method that will set my holders. For example:
function setHolders()
{
bgHolder = new Sprite();
addChild(bgHolder);
contentHolder = new Sprite();
addChild(contentHolder);
menuHolder = new Sprite();
addChild(menuHolder);
}
Then I just add my content to the desired holder in any order between destination holder and I can always be sure to add my content to the correct "layer";
So just add your back button to the menuHolder:
menuHolder.addChild(back);
And don't worry about adding it below the map or out of index, because the map, in this case, would be added to the contentHolder!
Hope that helps!
that's because you add your back button first
just make sure that you first add the map then add the button

Windows Phone 8: How can I make a map's pushpin textbox to stay on top of any other elements on the map?

I have a map with 100 pushpins. Every time I tap a pushpin, a textbox with description is opened near that pushpin (only 1 textbox can be opened at a time, when you tap a pushpin, the previous opened textbox is closed first), but sometimes the textbox is not on top of other pushpins, other pushpins appear above the textbox, making it hard to read the description. I've tried using Canvas and Canvas.ZIndex, but nothing worked properly.
I had a similar issue, and I solved it my removing and adding the object again whenever it was tapped.
MapLayer theLayer = new MapLayer();
MapOverlay theOverlay = new MapOverlay()
{
GeoCoordinate = new GeoCoordinate(lat, lng)
};
var pp = new StackPanel { Background = new SolidColorBrush(Colors.Black), Orientation = System.Windows.Controls.Orientation.Vertical };
var img = new Image()
{
Source = new BitmapImage(new Uri(url, UriKind.Absolute)),
Width = 50,
Height = 50
};
pp.Children.Add(img);
img.Tap += (object emitter, System.Windows.Input.GestureEventArgs e) => {
theLayer.Remove(theOverlay);
theLayer.Add(theOverlay);
};
theOverlay.Content = pp;
theLayer.Add(theOverlay);
Hope this helps!