RootVisual is null when returning from Tombstoning? - c#

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.

Related

Xamarin Forms: ContentPage OnCreate event?

I'm creating a messaging app, and I need that when I enter the messaging thread with someone, message bubbles show inside the layout. I'm doing this easily using:
MyMessageThreadStackLayout.Children.Add(
// Message bubble building logic goes here
);
But currently, I'm putting this inside the:
protected override void OnAppearing ()
But this makes my elements appear after the content page animation is shown making it look really weird. Is there a OnCreate event that can let me load the messages into the view before showing them with the animation? Thank you
You could use the protected virtual void LayoutChildren method that's exposed on all Pages. Keep in mind it may be called many times, so you'll need to account for that possibility.
Another option would be to simply add your child Views in the Page's constructor. This option is not ideal, but it's guaranteed to only be called once, and always before your Page is presented.

Winform app, force execute OnLoad Event when focus is on another tab

I have a WinForm app, the form has TabControl, control has three tabs tabPage1,tabPage2,tabPage3.
The Tab 'tabPage3' is hosting a User defined control which internally has one or more child controls.
Now my problem lies in tabPage3,
I know it is a pure Winforms behavior, until your parent is not activated child controls Onload event won't fire.
I have a requirement to force the Onload event to fire when the focus is on tabPage1, tabPage2. Is there any way to force the Onload event to fire.
I have already visited following links but didn't find any clue. Link Link Link
This is a very unusual requirement, strongly smells like an XY problem. The Load event is heavily over-used in Winforms, a side-effect of it being the default event for a Form or UserControl. One of the behaviors inherited from VB6, the Load event was a big deal in that language. What you want can easily be accomplished by not giving Winforms a choice:
public UserControl3() {
InitializeComponent();
CreateHandle();
}
The CreateHandle() call does the forcing, OnLoad will immediately run. But do be aware that this happens very early, too early to do the kind of things that you'd really want to use OnLoad() or the Load event for. Which are rather limited, it is only truly necessary to discover the actual Location and Size of the control. Anything else belongs in the constructor. Surely including the code that you now run in OnLoad().
Strongly favor using the constructor instead.
I had a similar problem for a previous project, for my needs I managed to just iterate over every tab page in the forms constructor (or possibly OnLoad I can't remember) and then reset the index back to 0 before ever showing the end user.
Something similar to:
for(int i = 1; i < tabControl.TabCount; i++)
tabControl.SelectTab(i);
tabControl.SelectTab(0);

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.

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

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.

ASP.Net Exception within View Control

I admit, I'm an .NET n00b. Basically what I'm trying to do is I have a page with a text box on it and an image button. On click of the image button I want it to show a view control I have set up. Inside this view control is an image and some text. So this is what I have in my code-behind.
protected void btnSubmit_Click(object sender, ImageClickEventArgs e)
{
string email = txtUnsubscribe.Text;
vwSuccess.Visible = true;
}
Simple right? Well when I click on the button for submit, I get the "Object reference not set to an instance of an object." error message. Where am I going wrong?
Are txtUnsubscribe and vwSuccess both not null? Have you tried stepping through it in a debugger?
Based on the information (which is to say, based on not much), I'd guess you have an issue with the execution order.
Since you have txtUnsubscribe and vwSuccess members, I'm assuming you initialize these somewhere. If they are auto-generated from the aspx templates, then they are initialized automatically before the event handling so that method will never throw a null reference exception.
If the null reference exception is thrown by that event handler, then it must mean that one of these variables is not initialized (which means that at least one of them is not autogenerated from the aspx and instead should be initialized manually). If you are initializing the variables, then you are likely doing it too late in an event like PreRender or Render.
When you click the button in the browser the browser performs a PostBack to the web server. By default at this point the web server re-constructs the page, performs the event handling and then renders it back to the client. It is important to realize that the page isn't maintained on the server between requests.
The order of events during page load/postback can be found from MSDN: http://msdn.microsoft.com/en-us/library/aa719775(VS.71).aspx
Of course if the exception isn't thrown by that event handler, this whole answer is likely to be wrong and there's probably some simpler issue.

Categories

Resources