Calling InitializeComponent in OnAppearing method in Xamarin Forms Project - xamarin

Is there any reason or problem I cant call InitializeComponent method in OnAppearing function of a page in xamarin forms project?
I understand that I must call InitializeComponent only once to create the actual page. But what if I check that Content is already created and do it as below. Is it a bad implementation or practice? because it is said that no xaml based application does it and always call it in a constructor of the page.
reason I want to do it as below because xamarin.forms start up time is slow running on Android and if you use Masterdetail page(I think same for tabbed page), you must initialize it at the start up, it causes every navigation page defined in masterdetail page to be initialized and it costs you 2-3 secs depending on your UI could be even higher cost. any thoughts or experiences on this?
protected override void OnAppearing()
{
if (Content == null)
{
InitializeComponent();
}
}

I do not recommend this approach. From the xamarin docs.
The constructor of that class calls InitializeComponent, which then calls the LoadFromXaml method that extracts the XAML file (or its compiled binary) from the PCL. LoadFromXaml initializes all the objects defined in the XAML file, connects them all together in parent-child relationships, attaches event handlers defined in code to events set in the XAML file, and sets the resultant tree of objects as the content of the page.
https://developer.xamarin.com/guides/xamarin-forms/xaml/xaml-basics/getting_started_with_xaml/
If your forms are too slow on Android I would enable Fast Renders instead
In the OnCreate of your main activity add this line of code just before Xamarin.Forms.Init
Forms.SetFlags("FastRenderers_Experimental");
https://xamarinhelp.com/xamarin-forms-fastrenderers-android/
It would not hurt to try to use compiled Xaml also
using Xamarin.Forms.Xaml;
...
[XamlCompilation (XamlCompilationOptions.Compile)]
public class HomePage : ContentPage
{
https://developer.xamarin.com/guides/xamarin-forms/xaml/xamlc/

Related

Xamarin custom control in a datatemplate created with CreateContent()

I have implemented a custom DataTemplateSelector according to: GitHub Xamarin Forms.
This allows for a datatemplate to be selected based on an item, which is received through a data binding. This works fine to select a proper datatemplate and render it. However, I am now at a point where I want to add custom controls to this datatemplate (custom buttons). This works on any other page, but for some reason not in this datatemplate.
The relevant lines in the datatemplate:
xmlns:controls="clr-namespace:Universal_ONE.Views.Controls"
<controls:IconButton Command="{Binding RobotLocationSave}"
Image="{StaticResource BoltBlack}"/>
The part the datatemplate is selected and created:
var templateToUse = templateSelector.SelectTemplate(item, null);
View view = (View)templateToUse.CreateContent();
view.BindingContext = bindingContext;
In the catch block I get the error (after calling CreateContent()):
Xamarin.Forms.Xaml.XamlParseException: Position 371:26. Type controls:IconButton not found in xmlns clr-namespace:Universal_ONE.Views.Controls
The problem has to be with the CreateContent(), since using the control outside of this datatemplate works.
EDIT 1
I've created a Minimal Working Example: GitHub.
The datatemplate is now hardcoded, so I'm sure that one is selected.
The same parseexception gets thrown.
I am trying to compile Xamarin.Forms myself so I can debug the framework itself. However, compiling is not going smooth; thus might take a bit longer.
EDIT 2
A bit more info on the MWE:
The MainPage.xaml has the default Xamarin.Forms app code. Below I've added a custom control, which is simply a frame with a label. The text of this label is set via a bindableproperty (not really relevant). Below this control is the datatemplatecontrol added, which in turn calls the datatemplateselector, which returns the datatemplate. This datatemplate contains the same control as the mainpage. Thus the rendered app should have 2 controls. However, in de datatemplatecontrol you can breakpoint on the catch statement (look for my comment). This is where the parseexception will show, which is caused after calling CreateContent() on the datatemplate.
EDIT 3
I've not been clear enough I think. But you have to put a breakpoint on line 41 of datatemplatecontroler.cs. Since the content of the datatemplate is set to null if the createcontent() fails, thus fails gracefully. When hitting the breakpoint you can read the parseexception.
EDIT 4
I've made an issue and a pull request on the Xamarin repository: GitHub. The problem resides with the XamlParser, which has a small bug where it selects the wrong assembly. Inside the issue I've mentioned a workaround which can be used for now.
I try to download your example and run it. When I run to Content = CreateTemplateForItem(ItemTemplate); the program does not report an error, so the program skips the catch method. Here is a screenshot of the runtime:
Then I tried to actively throw an exception in the try statement (throw new Exception();) to make the program enter the catch method, Here is a screenshot of the runtime:

Xamarin Picker selected item persisting on multiple pages

Question:
Perhaps the challenge could be stated this way: How do I bind a single property in a content page to a globally stored variable in Xamarin Forms?
Details:
I am using the MVVM pattern. I have a navigation content page (1 of 3 such pages) with a Picker object which is populated dynamically from the collectionModel and said model is read/write. I am attempting to persist the SelectedItem (or index, whichever is most appropriate) thru all 3 content pages such that navigation from page to page shows the same item (from the user's perspective). How should I do this?
I can set the Picker.SelectedIndex manually in ContentPage_Appearing() event. I would much rather use binding.
Follow these steps:
Create a static class, like this:
public static class DataClass
{
public static int PickerSelectedIndex = 0;
}
Add the xmlns:local in ContentPage mark in each Content Page, like this:
xmlns:local="clr-namespace:DataPersist"
Binding the data for your controls in each page's Xaml, like this:
<Picker x:Name="picker" SelectedIndex="{x:Static local:DataClass.PickerSelectedIndex}">
It works like this:

Load a Xaml inside a stacklayout in Xamarin forms

I have a Content View in Xamarin forms with 2 StackLayout horizontally aligned in it. I want to change the Content of the 2nd Stacklayout dynamically, but I don't want to use Master details page in that case. Please find an attachment to see what my UI looks like. I want to load different pages in StackLayout 2 on button clicks in StackLayout 1.
Update: I want to achieve above using MVVM.
You specifically said you want to load different pages inside Stacklayout2.
Out of the box, this is not possible. A Page can not be nested inside another view in Xamarin.Forms*
However, you most likely don't need to nest a whole page either, which is good news.
You can create custom xaml views as separate xaml files, and then reference them like regular controls. For example you would create a xaml file MyDataView, inside you could use a and fill it out with your different labels, entries and what nots, then instantiate and add that MyDataView inside your page like you would any other control.
For your host page, I would recommend you change your StackLayout2 to a ContentView, as it will only ever contain one view, which in case of something like your custom "MyDataView" from above, would actually contain the stack layout and all the details.
From the point of view of your page, it has the left layout with all the buttons, and it has the "container" on the right to host different complex views. So it does not need a stacklayout there.
There is also an important decision that you need to make on when and how you want to instantiate all the views that you will host inside the right pane.
You might choose to instantiate them all at once, when loading the page, if there aren't too many. Then switchig to each one during page use should be quite quick. Something like this:
public partial class MainPage
{
private MyDataView myDataView = new myDataView();
private OtherView otherView = new OtherView();
private ThirdView thirdView = new ThirdView();
public void OnSomeButtonClick(object sender, EventArgs e)
{
Container.View = myDataView; //Container would be the x:Name you gave to your ContentView control on the right side of the page that will host the different views
}
}
Or you might prefer to "lazy" instantiate the views, which would only instantiate the view the first time it is navigated to. This is useful if some views will never actually be accessed, and you can save some cpu cycles and ram by not loading the view until it's needed. The downside of course is when you do load it for the first time, it will load slower. Like this:
public partial class MainPage
{
private MyDataView myDataView;
private OtherView otherView;
private ThirdView thirdView;
public void OnSomeButtonClick(object sender, EventArgs e)
{
if (myDataView == null) myDataView = new MyDataView();
Container.View = myDataView; //Container would be the x:Name you gave to your ContentView control on the right side of the page that will host the different views
}
}
And finally you can instantiate the view everytime it is needed. I would not go with this route in most cases. Unless you really specifically need to recreate the entire view each time (like if you are dynamically changing it during use, and you need to reset it when it's shown again)
*I have seen a custom renderer implementation that nested a whole page inside a view on github. I did not test it as it was not completely implemented at the time.
Cant you do something like this:
button1.OnClick += (sender, args) =>{
StackLayout2.Children.Remove(currentview);
StackLayout2.Children.Add(newview);
}
Not sure if its called onclick or clicked.

WP7 Application is being deactivated with no reason 10 seconds after navigating to a page

A WP 7.1 project starts with a Page that host a Panorama control. At some point user click on a ListBox, and this navigates the application to a details page.
In case the debugger is attached, everything stays on the screen as it should. But If I test an application either in emulator, or on the phone without a debugger, approximately in 5-10 seconds after the details page navigation, an application gets deactivated.
No unhanded exception, not closing, but deactivated even is raised. I have placed a message boxes in each of "exit handlers" to know exactly what happens and found out that it is deactivation.
No user input takes place after navigation and before the deactivation.
What may be the reason for such "no interaction" deactivation?
I don't call no "deactivate" requests from code.
Additional info:
Details page is bound to a sample view model that is obtained via MVVM Light ViewModel locator. View model locator gets it from ninject kernel that is a static public property of an App object(Yes, I have made IOC container publicly available via App property. I know it probably is a horrible practice, but I doubt the problem is linked to that). The page initializes just fine and displays all the data from a sample view model class. It almost seems like an app is deactivated due to inactivity, but there is no such thing in WP7 as far as I know.
UPDATE
A deactivation takes place exactly 10 seconds afer I call this line:
((PhoneApplicationFrame)(Application.Current.RootVisual)).Navigate(new Uri("/Views/BookDetailsView.xaml", UriKind.Relative));
from a view model of a main application view. The problem view is a details view, not the main one.
The constructor for BookDetailsView is empty (default):
public partial class BookDetailsView : UserControl
{
public BookDetailsView()
{
InitializeComponent();
}
}
The XAML for the view binds it's datacontext to a property of a mvvm light view model locator:
DataContext="{Binding Source={StaticResource Locator}, Path=BookDetails}"
The Locator resource is decleared in App.xaml and points to ViewModelLocator.cs.
The property that provides datacontext for a problem view is:
public static IBookDetailsViewModel BookDetailsStatic
{
get;
set;
}
/// <summary>
/// Gets the Main property.
/// </summary>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance",
"CA1822:MarkMembersAsStatic",
Justification = "This non-static member is needed for data binding purposes.")]
public IBookDetailsViewModel BookDetails
{
get
{
return BookDetailsStatic;
}
}
The BookDetailsStatic is initialized from the IoC container call in the ViewModelLocator ctor:
BookDetailsStatic = App.Kernel.Get<IBookDetailsViewModel>();
In a any scenario the call to get an IBookDetailsViewModel returns an instance of a
public class SampleBookDetailsViewModel: IBookDetailsViewModel
which has an empty constructor and a bunch of properties.
SOLVED
My view, that I have been navigating to, was declared as a UserControl, and should have been as PhoneApplicationPage.
Hard to say without knowing what's on the page, but you could be hitting the memory limit.
In general, you can consider the memory limit to be 90mb, but you're better off checking DeviceStatus.ApplicationMemoryUsageLimit and DeviceStatus.ApplicationCurrentMemoryUsage and possibly displaying it on screen every half second or so to debug.
You can also try the profiler, assuming it doesn't affect the repro.
BookDetailsView was decleared as a UserControl.
Navigating to a UserControl deactivates an application in 10 seconds.
Changing the type of a view to PhoneApplicationPage solves the problem.

Refreshing the pages when navigated back in Windows Phone

I have two pages that I navigate to and from. One is called the MainPage which is a Pivot page and the other is an ordinary page/class called the AddNewHistoryPage. There is a function called DisplayHistory in the MainPage that I would like to call on navigation back to MainPage from the AddNewHistoryPage.
I found that there is a protected function called OnNavigatedTo. Could someone help to find a little more information, such as
The OnNavigatedTo function should be written in the MainPage if I want to call the DisplayHistory in the mainPage
what does ' base.OnNavigatedTo(e)' mean?
You should save your phones state when navigating to the DisplayHistory page, so when navigating back to main page your information you need retained will stay retained.
Also when using the function OnNavigatedTo that would be used on MainPage but you would have to write a statement checking which pages it was navigated from....such as DisplayHistory.
If you don't use or that write that statement, every time the page is accessed it will run that Function.
WP7 Navigation in Depth
This Above link helped me a lot when learning tombstoning and having to save specific things to memory ICE(In Case of Emergency).
Hope this will help you out! :)
Keeano Martin's Link should be enough to anwser your first question.
Regarding your second question:
'base.OnNavigatedTo(e)' calls the base classes OnNavigateTo method.
Your page inherits from a base class: 'PhoneApplicationPage'. If you do not override the OnNavigatedTo method then the base classes implementation will be called directly. When you do override a method then you should [usually] call the base class implementation (using the code you posted). If you don't do this then any code in the base classes implementation will never be run and you will probably get some unexpected behaviour.

Resources