Maps control SetView works only on the page's first load - c#

I have a problem with Bing Maps control I use in my WP7 application.
When I'm navigated to the page with map control, it starts the GeoCoordinateWatcher. When GeoCoordinateWatcher has some location data for me, it calls a SetView() method to center the map at current location. There is also a button on ApplicationBar that's also starting the GeoCoordinateWatcher.
Now, the thing is, when I first navigate to this page, all works fine: GeoCoordinateWatcher starts, gives me the location data after some time, calls SetView() and the map centers when I need it too. The same with the button.
But if I press the Back button to get back to the main page and then try to navigate again to the map page, SetView() stops working. In debugging I see that the code surrounding it works as expected and the data passed to SetView() is correct, but nothing happens with the control and events for changing view don't fire either.
I'm assuming there may be something wrong with map initialization (or disposing on navigating from), but I don't know where to dig.
Edit:
I've tried changing Map.Center directly and it doesn't work in exactly the same way the SetView() doesn't: it works fine the first time page is navigated to and doesn't work on the other times.
Edit 2:
Ok, it gets weirder. In debugging I see that my map's center actually gets set to a correct value. But an actual control shows absolutely different location and me, moving map around, doesn't change the value that I see from code.
Edit 3:
I've added a button to ApplicationBar that just calls SetView() and it works fine. Apparently, the problem appears when I call SetView() as a result of GeoCoordinateWatcher.PositionChanged event raising. How could I work around that?

Try using map.Center = loc.CoOrdinates;

I've found the solution.
In my original code I've subscribed to the GeoCoordinateWatcher.Position property change event in the page constructor: App.PropertyChanged += AtmInfoPageOnAppPropertyChanged
All I had to do was to move that to the OnNavigatedTo event handler and add App.PropertyChanged -= AtmInfoPageOnAppPropertyChanged to the OnNavigatedFrom event handler.
I think, the problem was that keeping the old page subscribed to the event didn't allow it to be disposed, and at the same time didn't allow the new page to subscribe to that same event, thus causing the code to be called for the different page and different map control than the one displayed on the screen.

Related

ScriptManager.RegisterStartupScript On Button Click (within updatepanel) Does not fire on FIRST click

My project is essentially a web page with a menu and an updatepanel. The user selects a choice from the menu, and a usercontrol is loaded into the updatepanel. I would prefer not to use an update panel, but, there are multiple databound controls that contain information that will then change the contents of another databound control. Anyways, my project calls for a message box to appear on the screen, which I have no issue in getting to work:
string s= "<script>alert('HayGuise');</script>";
ScriptManager.RegisterClientScriptBlock(c.Page, c.Page.GetType(), GUID.NewGUID().ToString(),s,false);
Now, I've tried a number of different tactics, including replacing GUID with a static string; I've used RegisterStartupScript, etc. My issue is that the message box does not show on the first click of the call button AFTER the updatepanel has updated to show a new usercontrol. But, if I click the button again, everything is great. If this is done on the very first form loaded into the updatepanel (opening up the site and selecting from the menu), everything works fine; it is only when the updatepanel updates again with a new form, that this will occur, and again, only on the first click.
Additionally, the code is being fired, and all code that follows the ScriptManager code fires, but the message box will not show until the button is clicked again. As I am testing this behavior at the moment, I've added the popup code to each of the buttons on the form, and the behavior is the same with each of them. It sucks that its taken so long to implement a reliable piece of code (for the messagebox) only to have this slight issue, and this is after I just figured out why my button events were firing twice on a single click. I pretty sure that it's going to be something simple, some sort of property that I'm not familiar with that needs to be set correctly. Damn, I'd love to just be able to settle all these little issues so I can proceed with the rest of the project. Sooooo close. Thank you for any help.
Edit: Additionally, the buttons are located in another usercontrol that is added to the usercontrol form that is shown in the updatepanel.
Edit II:
Thanks for your input, I apologize for getting back to this so late, I moved on to other parts of the project and just came back to this. The issue is not the startupscript method, nor the clientscriptblck method; the issue resides in the loss of value/viewstate/clientid's on postback.
At the time I posted this question, this project was a single page application. I tested functionality by creating a multipage application, and just kept going from there, vowing to come back to this issue. Well, I'm back and the issue does not reside in the update panel, it has something to do with my code, as I clear out the update panel (tried with a regular panel as well) and then reload the new usercontrol. When cleared, something goes haywire, and nothing fires on the first postback. Its a weird issue, that I have yet to find much (a couple articles) information on that is specific to just the first postback causing this issue. I'll update with an answer if I ever find one; the only fix I've found is to add a line to the menu select code, Server.Transfer(thecurrentpage), essentially refreshing the page. This solves all of the issues, but it seems a bit in poor taste. Thanks again for your input.
If you are working with AJAX UpdatePanel, following code should work for you. In my case, I was using update panel and none of the about worked except this one.
ScriptManager.RegisterStartupScript(myUpdatePanelID, myUpdatePanelID.GetType(), "myFunction", "myFunction();", true);
If you are using update panel in your page then the following code should work for you. You should use the RegisterStartupScript in the whole page using "this".ScriptManager.RegisterStartupScript(this, this.GetType(), "myFunction", "myFunction();", true);

How do I perform sequential BringIntoView calls in WPF?

We have a TreeView in our application with the following requirements:
When an item is added:
The newly-added item is scrolled into view
The parent of the newly added item is also scrolled into view.
If they are too far away to both be seen at the same time, the item takes precedence.
This seems easy, simply scroll the parent into view first, then scroll the child.
The problem is when you call it like this:
parent.BringIntoView();
child.BringIntoView();
...only the second one seems to have any effect. The first one is basically ignored.
I then tried wrapping the second call in a BeginInvoke() call like this:
parent.BringIntoView();
Dispatcher.BeginInvoke((Action)(() => {
child.BringIntoView();
}));
Which does work, but now you can visibly see the TreeView scroll twice; once for the parent, then a moment later, for the child, which just looks bad.
So how can I call BringIntoView back-to-back but without the double-refresh issue of using the dispatcher?
Try using the Loaded event instead of the dispatcher. According to this article, it's a perfect fit for situations like this:
... we initially implemented the Loaded event so that
it would fire just after the window was rendered, but before any input
was processed. We figured that if it was ready enough for input, it
was ready enough for load-time initialization. But then we started to
trigger animations off of the Loaded event, and saw the problem; for a
split second you’d see the content render without the animation, then
you’d see the animation start. You might not always notice it, but it
was especially noticeable when you run the app remotely.
So we moved
Loaded so that it now fires after layout and data binding have had a
chance to run, but just before the first render. (And note that if
you do anything in your Loaded event handler that invalidates layout,
it might be necessary to re-run it before rendering.)
In other words, on Loaded you have the most up to date information about the physical layout of the element, but it hasn't actually rendered yet, so you should be safe from any "screen flicker" issues.
EDIT: To answer your question in the comments, you can wire up events "local" to the current method using a closure, like this:
EventHandler handler = null;
handler = (sender, e) => {
this.LayoutUpdated -= handler; // only run once
child.BringIntoView();
};
this.LayoutUpdated += handler;
By defining the handler inside the method, you are able to access the method's local variables (child) from within. Very similar to the Dispatcher call.
I'm not sure if relying on LayoutUpdated is a good idea, actually. It happens quite often so it may end up firing sooner than you need. It happens twice for individual Width and Height settings, for example. Another one to look into is ScrollViewer.ScrollChanged. Or you could avoid BringIntoView altogether and try manually examining the element sizes to calculate where to scroll to.

RootVisual is null when returning from Tombstoning?

Hi I just found out that my application was crashing when returning from tombstoning. I was able to target the problem here inside the constructor of my page:
RadPhoneApplicationFrame frame = App.Current.RootVisual as RadPhoneApplicationFrame;
frame.PageTransitionCompleted +=
new EventHandler<EventArgs>(frame_PageTransitionCompleted);
Everytime the app is Re-Activated the RootVisual is setting the frame to null. I'm wondering if there is a casting issue here because before I used this code my tombstoning was working perfectly and I was able to navigate freely throughout the app. Any ideas on what might be causing this? Or maybe a work around?
You should move this code from page constructor to OnNavigatedTo method override in your page. Reason is that RootVisual is probably set in RootFrame.Navigated event handler which is generated after page is constructed, not before (this depends of implementation in your App.xaml.cs).
Of course because OnNavigatedTo method may be runned more that once for a page, you should make sure that PageTransitionCompleted event handler is not assigned two times (just use -= before +=).
Another option is to move this code to App.xaml.cs. This makes sense most to me, because that PageTransitionCompleted event is related to whole app, not a single page.

Issue when using Routed Commands with a Frame

My WPF project has a main window with a number of buttons and a frame. I display a page within the frame, and the buttons above use routed commands in order to call methods present in the page below. With me so far?
Everything works fine until I change the page. Even though this new page has methods which relate to the commands, it seems the routed commands are still looking for methods in the previous page. I don't know why this is happening when I've set the typeof() argument in the command itself:
public static RoutedCommand cmd = new RoutedCommand("Foo", typeof(BarPage));
How can I fix this? I've noticed that setting focus on a textbox in the newly-selected page will correct things, however this isn't a viable solution as the page will not always contain fields. I've also tried setting focus on the page itself but the problem still applies.
Thanks in advance.

Navigate to existing instance of page in silverlight

On a Frame in silverlight I want to be able to navigate to an existing instance of a Page. In short this is what I want:
Page p = ...; // initialize the page and set some of the properties
contentframe.Navigate(p);
Instead of using an Uri from which the page is created.
Can this be achieved (as in WPF), or should the frame rather be replaced by a ContentControl?
Edit: More clarity: Is there a way that NavigationService.Navigate(object root) that is available in WPF can be simulated in silverlight?
You question seems really quite confused.
should the frame rather be replaced by a ContentControl?
That would imply that you don't have good reason to have the frame there in the first place and you aren't using a navigating framework. In which case certainly you should replace the Frame with something else.
If you can replace the frame with something else the there is no need for your "Page" to be of type Page, it may as well be a UserControl.
It can all boil do down to have this simple Xaml:-
<Border x:Name="content" />
and this cs:-
UserControl p = ...;
content.Child = p;
Edit:
You need to keep the frame therefore you can't replace it with a ContentControl.
You might just assign your Page directly to the Frame Content property. However I'm not sure what would happen if you then click the back button. I suspect it would navigate to the page prior to the page you replaced.
Another option would be to us a static service to push your page properties on to a stack, you page can then pop them off this stack when initialising. This would allow you to navigate using a Uri to your page.
The problem you are facing is the same problem that I am facing. An event happens outside the frame, and the page has no idea that the event has ocured, but it needs to be notified of that event.
Now what can be done is force the page within that frame to refresh itself or handle those events by 1: storing the page's state temporarily, and b) passing "commands" through the query string.

Categories

Resources