How to improve loading performance in Tabbed Page xamarin forms - c#

I am trying to create bottom tabbed page in Xamarin forms and i am doing this for Android.
here i am using latest version of Xamarin Forms.
My sample Bottom tabbed page like below.
<TabbedPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:d="http://xamarin.com/schemas/2014/forms/design"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:views="clr-namespace:SampleTabbedPage.Views"
xmlns:android="clr-namespace:Xamarin.Forms.PlatformConfiguration.AndroidSpecific;assembly=Xamarin.Forms.Core"
android:TabbedPage.ToolbarPlacement="Bottom"
android:TabbedPage.BarItemColor="Gray"
android:TabbedPage.BarSelectedItemColor="Blue"
mc:Ignorable="d"
x:Class="SampleTabbedPage.Views.SampleTabbed">
<!--Pages can be added as references or inline-->
<NavigationPage
Title="Main"
NavigationPage.HasNavigationBar="False">
<x:Arguments>
<views:SampleDetailsPage/>
</x:Arguments>
</NavigationPage>
<ContentPage Title="Tab 1" />
<ContentPage Title="Tab 2" />
</TabbedPage>
My sample details page like
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:d="http://xamarin.com/schemas/2014/forms/design"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
x:Class="SampleTabbedPage.Views.SampleDetailsPage"
BackgroundColor="Gray">
<ContentPage.Content>
<StackLayout>
<ListView BackgroundColor="White" ItemTapped="ListView_ItemTapped">
<ListView.ItemsSource>
<x:Array Type="{x:Type x:String}">
<x:String>Mango</x:String>
<x:String>Banana</x:String>
<x:String>Pinaple</x:String>
<x:String>Apple</x:String>
<x:String>Avacado</x:String>
<x:String>Coconut</x:String>
<x:String>Dragan Fruit</x:String>
<x:String>Pomaganate</x:String>
<x:String>Wood Apple</x:String>
</x:Array>
</ListView.ItemsSource>
</ListView>
</StackLayout>
</ContentPage.Content>
</ContentPage>
And the navigation i am doing as follows
in App.xamal.cs
MainPage = new NavigationPage(new FirstPage());
I have simple first page
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:d="http://xamarin.com/schemas/2014/forms/design"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
x:Class="SampleTabbedPage.Views.FirstPage">
<ContentPage.Content>
<StackLayout>
<Button Text="Click Me!" Clicked="Button_Clicked"
VerticalOptions="CenterAndExpand"
HorizontalOptions="CenterAndExpand" />
</StackLayout>
</ContentPage.Content>
</ContentPage>
here in button click event i do the navigation to "Sample Tabbed Page"
await Navigation.PushAsync(new SampleTabbed());
This is working fine.
but there is a performance issue.
if i run this and click on button in First page it is taking 3 seconds to load tabbed page.
if i remove list view in sample detail page it take 2 seconds to load.
but if i add just a content page to click event it take only milliseconds to load.
Am i doing some thing wrong with implementing tabbed page?
or
is there any way to improve the loading performance with tabbed pages.

A solution is to make the heavy pages load their content in a lazy manner, only when their tab becomes selected. This way, since these pages are now empty when TabbedPage is created, navigating to the TabbedPage suddenly becomes very fast!
1.create a behavior for the TabbedPage page, called ActivePageTabbedPageBehavior.
class ActivePageTabbedPageBehavior : Behavior<TabbedPage>
{
protected override void OnAttachedTo(TabbedPage tabbedPage)
{
base.OnAttachedTo(tabbedPage);
tabbedPage.CurrentPageChanged += OnTabbedPageCurrentPageChanged;
}
protected override void OnDetachingFrom(TabbedPage tabbedPage)
{
base.OnDetachingFrom(tabbedPage);
tabbedPage.CurrentPageChanged -= OnTabbedPageCurrentPageChanged;
}
private void OnTabbedPageCurrentPageChanged(object sender, EventArgs e)
{
var tabbedPage = (TabbedPage)sender;
// Deactivate previously selected page
IActiveAware prevActiveAwarePage = tabbedPage.Children.OfType<IActiveAware>()
.FirstOrDefault(c => c.IsActive && tabbedPage.CurrentPage != c);
if (prevActiveAwarePage != null)
{
prevActiveAwarePage.IsActive = false;
}
// Activate selected page
if (tabbedPage.CurrentPage is IActiveAware activeAwarePage)
{
activeAwarePage.IsActive = true;
}
}
}
2.define IActiveAware interface
interface IActiveAware
{
bool IsActive { get; set; }
event EventHandler IsActiveChanged;
}
3.create a base generic abstract class called LoadContentOnActivateBehavior
abstract class LoadContentOnActivateBehavior<TActivateAwareElement> : Behavior<TActivateAwareElement>
where TActivateAwareElement : VisualElement
{
public DataTemplate ContentTemplate { get; set; }
protected override void OnAttachedTo(TActivateAwareElement element)
{
base.OnAttachedTo(element);
(element as IActiveAware).IsActiveChanged += OnIsActiveChanged;
}
protected override void OnDetachingFrom(TActivateAwareElement element)
{
(element as IActiveAware).IsActiveChanged -= OnIsActiveChanged;
base.OnDetachingFrom(element);
}
void OnIsActiveChanged(object sender, EventArgs e)
{
var element = (TActivateAwareElement)sender;
element.Behaviors.Remove(this);
SetContent(element, (View)ContentTemplate.CreateContent());
}
protected abstract void SetContent(TActivateAwareElement element, View contentView);
}
4.the specialized LazyContentPageBehavior
class LazyContentPageBehavior : LoadContentOnActivateBehavior<ContentView>
{
protected override void SetContent(ContentView element, View contentView)
{
element.Content = contentView;
}
}
then we can use in xaml like this:
<TabbedPage>
<TabbedPage.Behaviors>
<local:ActivePageTabbedPageBehavior />
</TabbedPage.Behaviors>
<ContentPage Title="First tab">
<Label Text="First tab layout" />
</ContentPage>
<local:LazyLoadedContentPage Title="Second tab">
<ContentPage.Behaviors>
<local:LazyContentPageBehavior ContentTemplate="{StaticResource ContentTemplate}" />
</ContentPage.Behaviors>
<ContentPage.Resources>
<ResourceDictionary>
<DataTemplate x:Key="ContentTemplate">
<!-- Complex and slow to render layout -->
<local:SlowContentView />
</DataTemplate>
</ResourceDictionary>
</ContentPage.Resources>
</local:LazyLoadedContentPage>
</TabbedPage>
we moved the ContentPage complex layout to become a DataTemplate.
Here's the custom LazyLoadedContentPage page which is activation aware:
class LazyLoadedContentPage : ContentPage, IActiveAware
{
public event EventHandler IsActiveChanged;
bool _isActive;
public bool IsActive
{
get => _isActive;
set
{
if (_isActive != value)
{
_isActive = value;
IsActiveChanged?.Invoke(this, EventArgs.Empty);
}
}
}
}
SlowContentView do some complex things
public partial class SlowContentView : ContentView
{
public SlowContentView()
{
InitializeComponent();
// Simulating a complex view
...
}
}

Related

AnimationNavigationPage is only sliding left to right instead of right to left

I'm using the AnimationNavigationPage nuget package (found here) to try and create a page slide animation going from right to left. So far it seems that all I'm able to get is left to right and it doesn't reflect when I change the animation type / subtype.
I'm sure I'm just missing something small but for the life of me I can't see it.
MainPage.xaml.cs
using FormsControls.Base;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Forms;
namespace PageNavigationExample
{
// Learn more about making custom code visible in the Xamarin.Forms previewer
// by visiting https://aka.ms/xamarinforms-previewer
[DesignTimeVisible(false)]
public partial class MainPage : AnimationPage
{
public MainPage()
{
InitializeComponent();
}
private async void Button_Clicked(object sender, EventArgs e)
{
await Navigation.PushAsync(new Page1());
}
}
}
MainPage.xaml
<?xml version="1.0" encoding="utf-8" ?>
<controls:AnimationPage
xmlns:controls="clr-namespace:FormsControls.Base;assembly=FormsControls.Base" xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:d="http://xamarin.com/schemas/2014/forms/design"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
x:Class="PageNavigationExample.MainPage">
<controls:AnimationPage.PageAnimation>
<controls:SlidePageAnimation Duration="Short" Type="Slide" Subtype="FromRight"/>
</controls:AnimationPage.PageAnimation>
<StackLayout>
<!-- Place new controls here -->
<Label Text="Main page"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand" />
<Button Text="Main page button"
Clicked="Button_Clicked"/>
</StackLayout>
</controls:AnimationPage>
And then just basic content pages for navigation purposes that I haven't modified...Page1, Page2, etc.
What am I missing here to just get the slide animation to slide in from the right when I click a button and slide in from the left when I click the Back button?
And then just basic content pages for navigation purposes that I
haven't modified...Page1, Page2, etc.
Have you let your Page1, Page2, etc to inherit AnimationPage and set the PageAnimation?
for example:
app.xaml.cs :
public App()
{
InitializeComponent();
MainPage = new AnimationNavigationPage(new MainPage());
}
MainPage.xaml.cs:
public partial class MainPage : AnimationPage
{
public MainPage()
{
InitializeComponent();
}
private async void Button_Clicked(object sender, EventArgs e)
{
await Navigation.PushAsync(new Page1());
}
}
MainPage.xaml:
<?xml version="1.0" encoding="utf-8" ?>
<controls:AnimationPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:d="http://xamarin.com/schemas/2014/forms/design"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
xmlns:controls="clr-namespace:FormsControls.Base;assembly=FormsControls.Base"
x:Class="App18.MainPage">
<controls:AnimationPage.PageAnimation>
<controls:SlidePageAnimation Duration="Medium" Subtype="FromRight" />
</controls:AnimationPage.PageAnimation>
<StackLayout>
<!-- Place new controls here -->
<Label Text="Main page"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand" />
<Button Text="Main page button"
Clicked="Button_Clicked"/>
</StackLayout>
</controls:AnimationPage>
Page1.xaml.cs:
public partial class Page1: AnimationPage
{
public Anim2()
{
InitializeComponent();
}
}
Page1.xaml:
<?xml version="1.0" encoding="utf-8" ?>
<controls:AnimationPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:d="http://xamarin.com/schemas/2014/forms/design"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
xmlns:controls="clr-namespace:FormsControls.Base;assembly=FormsControls.Base"
x:Class="App18.Page1">
<controls:AnimationPage.PageAnimation>
<controls:SlidePageAnimation Duration="Short" Type="Slide" Subtype="FromRight"/>
</controls:AnimationPage.PageAnimation>
<StackLayout>
<Label Text="Welcome to Xamarin.Forms!"
VerticalOptions="CenterAndExpand"
HorizontalOptions="CenterAndExpand" />
</StackLayout>
</controls:AnimationPage>
the effect like:

ViewModel constructor not executed when page is navigated to, mvvm

I have a PopUp page I navigate to. The issue I am having is that while debugging the code never executes the constructor. I have other pages in this application which all work fine, as well as another pop up page where the contructor is executed just fine.
I am using Prism Mvvm for ViewModel location. I have double checked that all namespaces are correct, all of which you will see below. If anyone has encountered this before please help me out of this one. The view is also registered in my App.xaml.cs for Navigation
View
<popup:PopupPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:d="http://xamarin.com/schemas/2014/forms/design"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:popup="clr-namespace:Rg.Plugins.Popup.Pages;assembly=Rg.Plugins.Popup"
xmlns:templates="clr-namespace:MyApp.Views.Templates;assembly=MyApp"
xmlns:prism="clr-namespace:Prism.Mvvm;assembly=Prism.Forms"
prism:ViewModelLocator.AutowireViewModel="True"
mc:Ignorable="d"
x:Class="MyApp.Views.UserProfileView">
<ScrollView VerticalOptions="Center">
<Frame Margin="15"
BackgroundColor="White">
<StackLayout IsClippedToBounds="True"
Padding="10, 5"
Spacing="3">
<Label Text="Test"/>
<Button Text="Go Back" Command="{Binding GoBackCommand}"/>
</StackLayout>
</Frame>
</ScrollView>
</popup:PopupPage>
ViewModel
namespace MyApp.ViewModels
{
public class UserProfileView : BaseViewModel
{
private INavigationService _navigationService;
public DelegateCommand GoBackCommand { get; }
public UserProfileView(INavigationService navigationService)
{
_navigationService = navigationService;
GoBackCommand = new DelegateCommand(async () => await _navigationService.GoBackAsync());
}
}
How I Navigate to the page above
private async void NavigateToUserProfileView()
{
await _navigationService.NavigateAsync("UserProfileView");
}
Unless there's a typo in the question, and unless the default convention has been changed, the view model for the view UserProfileView should be called UserProfileViewModel to be found by the ViewModelLocator.

Databinding is not working between two tabbedpage children

I'm new to Xamarin.Forms development and I'm trying to build a tiny Xamarin app to start.
My app currently has one main TabbedPage that has two ContentPages children. On the ListePage, I have a ListView with an ObservableCollection with OlonaModel is an object with an int Numero and a Text string. I would like the Details page to show details of the selected OlonaModel from the listview of ListePage, but the Details page doesn't seem to update to changes when I select an item from the listview.
Both of the content pages are bound to the same ListPageViewModel. The view model updates when I select an item from the listview, but the changes aren't reflected on the Details page and I'm really confused.
How can I make the Details refresh itself when the SelectedItem of the view model gets set ?
The MainPage :
<?xml version="1.0" encoding="utf-8" ?>
<TabbedPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:d="http://xamarin.com/schemas/2014/forms/design"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:App.Views"
xmlns:viewmodels="clr-namespace:App.ViewModels"
mc:Ignorable="d"
x:Class="App.MainPage">
<TabbedPage.Children>
<local:ListePage/>
<local:Details/>
</TabbedPage.Children>
</TabbedPage>
The ListePage.xaml (ContentPage1 in the post) :
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:d="http://xamarin.com/schemas/2014/forms/design"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
x:Class="App.Views.ListePage"
Title="Liste">
<ContentPage.Content>
<StackLayout>
<ListView x:Name="ListeMipoitra" ItemSelected="ListeMipoitra_ItemSelected">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Label Text="{Binding Numero}" Grid.Column="0" FontSize="Medium" FontAttributes="Bold"/>
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</ContentPage.Content>
</ContentPage>
The ListePage.xaml.cs :
namespace App.Views
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class ListePage : ContentPage
{
public static ListePageViewModel viewModel;
public ListePage()
{
InitializeComponent();
viewModel = new ListePageViewModel();
this.BindingContext = viewModel;
ListeMipoitra.ItemsSource = viewModel.listeOlonaVM;
}
private void ListeMipoitra_ItemSelected(object sender, SelectedItemChangedEventArgs e)
{
viewModel.setSelected((OlonaModel)e.SelectedItem);
}
}
}
The Details.xaml (ContentPage2 in the post) :
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:d="http://xamarin.com/schemas/2014/forms/design"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
x:Class="App.Views.Details"
Title="Détails">
<ContentPage.Content>
<StackLayout>
<Label Text="{Binding Text}"/>
</StackLayout>
</ContentPage.Content>
</ContentPage>
The Details.xaml.cs :
namespace App.Views
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class Details : ContentPage
{
public Details()
{
InitializeComponent();
this.BindingContext = ListePage.viewModel.selected;
}
}
}
The ListePageViewModel.cs :
Note: I'm using Fody and PropertyChanged.Fody weaver, so the RaisePropertyChanged() event (should be) is called automatically when a property changes
namespace App.ViewModels
{
public class ListePageViewModel : INotifyPropertyChanged
{
public ObservableCollection<OlonaModel> listeOlonaVM;
public OlonaModel selected { get; set; }
public ListePageViewModel()
{
listeOlonaVM = new ObservableCollection<OlonaModel>();
listeOlonaVM = ListeOlona.liste;
}
public event PropertyChangedEventHandler PropertyChanged;
public void setSelected(OlonaModel olona)
{
selected = olona;
}
}
}
The model of the Olona object :
namespace App.Models
{
public class OlonaModel
{
public int Numero { get; set; }
public string Text { get; set; }
public OlonaModel(int num, string text)
{
this.Numero = num;
this.Text= text;
}
}
}
The ListeOlona.cs where the model of the list is stored:
The InitializeList() method is called at App Startup.
namespace App.ViewModels
{
public static class ListeOlona
{
public static ObservableCollection<OlonaModel> liste = new ObservableCollection<OlonaModel>();
public static void InitializeList()
{
liste.Add(new OlonaModel(1,
"FirstItem"));
liste.Add(new OlonaModel(2,
"Second Item"));
}
}
}
According to your description, there is tabbedpage, two pages, one is Listpage, another is detailpage, you want to select listview item in listpage, then other detail info will display detailpage, am I right?
If yes, I suggest you can do this like this:
TabbedPage:
<TabbedPage
x:Class="App4.TabbedPage2"
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:App4"
x:Name="tabbedpage2">
<!-- Pages can be added as references or inline -->
<TabbedPage.Children>
<local:ListPage Title="Mian page" BindingContext="{Binding}" />
<local:DetailPage Title="Detail page" BindingContext="{Binding select}" />
</TabbedPage.Children>
public partial class TabbedPage2 : TabbedPage
{
public TabbedPage2 ()
{
InitializeComponent();
this.BindingContext = new ListePageViewModel();
}
}
public class OlonaModel
{
public int Numero { get; set; }
public string Text { get; set; }
}
public class ListePageViewModel : ViewModelBase
{
public ObservableCollection<OlonaModel> listeOlonaVM { get; set; }
private OlonaModel _select;
public OlonaModel select
{
get { return _select; }
set
{
_select = value;
RaisePropertyChanged("select");
}
}
public ListePageViewModel()
{
listeOlonaVM = new ObservableCollection<OlonaModel>()
{
new OlonaModel(){Numero=1,Text="first item"},
new OlonaModel(){Numero=2,Text="second item"},
new OlonaModel(){Numero=3,Text="third item"},
new OlonaModel(){Numero=4,Text="fouth item"}
};
select = listeOlonaVM[0];
}
}
ListPage:
<StackLayout>
<ListView ItemsSource="{Binding listeOlonaVM}" SelectedItem="{Binding select}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout>
<Label Text="{Binding Numero}" />
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
DetailPage:
<StackLayout>
<Label
HorizontalOptions="CenterAndExpand"
Text="{Binding Text}"
VerticalOptions="CenterAndExpand" />
</StackLayout>
ViewModelBase implement INotifyPropertyChanged interface.
public class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void RaisePropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}

Xamarin Effect affecting other controls

I am experiencing a weird bug where a Custom effect would affect other Controls as well while i am only targeting one specific control. I was able to reproduce the behavior in a small test project. What i am trying to achieve is to change the color of a specific entry control. It does work but when navigating back to the previous page the effect affects other controls as well while i only want the specific effect to affect a specific control. I also only add the effect to the specific Entry by using its Effects list from xaml.
(note i am using the standard forms navigation page for navigating defined in my app.xaml like this.
MainPage = new NavigationPage(new MainPage());
MainPage.xaml
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:App2"
x:Class="App2.MainPage">
<StackLayout>
<!-- Place new controls here -->
<Label Text="Welcome to Xamarin.Forms!"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand" />
<Entry></Entry>
<Button Clicked="Button_Clicked" Text="navigate"></Button>
<Button Clicked="Button_Clicked2" Text="navigate to other"></Button>
</StackLayout>
</ContentPage>
CodeBehind of MainPage.xaml
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
}
private void Button_Clicked(object sender, EventArgs e)
{
Application.Current.MainPage.Navigation.PushAsync(new Test());
}
private void Button_Clicked2(object sender, EventArgs e)
{
Application.Current.MainPage.Navigation.PushAsync(new Test2());
}
}
Test.Xaml
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:App2"
x:Class="App2.Test">
<ContentPage.Content>
<Entry>
<Entry.Effects>
<local:EntryLineColorEffect></local:EntryLineColorEffect>
</Entry.Effects>
</Entry>
</ContentPage.Content>
</ContentPage>
Test2.xaml
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="App2.Test2">
<ContentPage.Content>
<StackLayout>
<Label Text="test 2" />
<Entry>
</Entry>
</StackLayout>
</ContentPage.Content>
</ContentPage>
EntryLineColorEffect (forms project)
public class EntryLineColorEffect : RoutingEffect
{
public EntryLineColorEffect() : base("Prolang.EntryLineColorEffect")
{
}
}
EntryLineColorEffect (Android project)
[assembly: ResolutionGroupName("Prolang")]
[assembly: ExportEffect(typeof(EntryLineColorEffect), "EntryLineColorEffect")]
namespace App2.Droid.Effects
{
class EntryLineColorEffect : PlatformEffect
{
EditText control;
protected override void OnAttached()
{
control = Control as EditText;
UpdateLineColor();
}
protected override void OnDetached()
{
control = null;
}
private void UpdateLineColor()
{
if (control != null)
{
control.Background.SetColorFilter(Color.DarkMagenta.ToAndroid(), Android.Graphics.PorterDuff.Mode.SrcAtop);
}
}
}
}
some screenshots that make it more clear
The entry does get the Magenta color which is good
But when navigating back and then navigating to the Test2 page that entry is also getting the Magenta color which for me is undesired behavior (and i do not know why it is hapenning). So what should i do to avoid this behavior?
In the end someone on the Xamarin comunity forum was able to answer my question.
=>
Effect won't affect other controls which haven't attached that effect. It seems Background.SetColorFilter(Color.DarkMagenta.ToAndroid(), Android.Graphics.PorterDuff.Mode.SrcAtop); changes the global Entry's underline's color. The entry displayed later after this setting will apply this behavior. So your Test2's Entry still has an attacted style. Use Background.Mutate().SetColorFilter(Color.DarkMagenta.ToAndroid(), Android.Graphics.PorterDuff.Mode.SrcAtop); instead to correct that:
EditText control;
protected override void OnAttached()
{
control = Control as EditText;
UpdateLineColor();
}
protected override void OnDetached()
{
control = null;
}
private void UpdateLineColor()
{
if (control != null)
{
control.Background.Mutate().SetColorFilter(Color.DarkMagenta.ToAndroid(), Android.Graphics.PorterDuff.Mode.SrcAtop);
}
}

Xamarin.Forms dynamically change Master page content

I have a simple app with Master-Detail page.
It looks similar:
And I want to dynamically change Master page content.
E.g. on Detail page there are some Button and then you click on it - some items from Master page dissapear.
I've tried to find some item properties like item1.isVisible=False but found nothing.
Is there any way I can do it?
MainPage code:
public partial class MainPage : MasterDetailPage
{
public MainPage()
{
InitializeComponent();
masterPage.listView.ItemSelected += OnItemSelected;
}
void OnItemSelected(object sender, SelectedItemChangedEventArgs e)
{
var item = e.SelectedItem as MasterPageItem;
if (item != null)
{
Detail = new NavigationPage((Page)Activator.CreateInstance(item.TargetType));
masterPage.listView.SelectedItem = null;
IsPresented = false;
}
}
}
MainPage XAML:
<MasterDetailPage xmlns=....>
<MasterDetailPage.Master>
<views:MasterPage x:Name="masterPage" />
</MasterDetailPage.Master>
<MasterDetailPage.Detail>
<NavigationPage>
<x:Arguments>
<views:SomePage/>
</x:Arguments>
</NavigationPage>
</MasterDetailPage.Detail>
MasterPage XAML:
<StackLayout>
<ListView x:Name="listView" x:FieldModifier="public" Margin="10,50,0,0">
<ListView.ItemsSource>
<x:Array Type="{x:Type local:MasterPageItem}">
<local:MasterPageItem Title="Home" TargetType="{x:Type views:HomePage}" IconSource="nav_icon_home"/>
<local:MasterPageItem Title="Settings" TargetType="{x:Type views:HomePage}" IconSource="nav_icon_settings" />
<local:MasterPageItem Title="My Profile" TargetType="{x:Type views:HomePage}" IconSource="nav_icon_profile" />
<local:MasterPageItem Title="Help" TargetType="{x:Type views:HomePage}" IconSource="nav_icon_help" />
<local:MasterPageItem Title="About" TargetType="{x:Type views:AboutPage}" IconSource="nav_icon_about"/>
</x:Array>
</ListView.ItemsSource>
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Grid Padding="10,10,10,10" ColumnSpacing="10">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="30"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Image Source="{Binding IconSource}"/>
<Label Grid.Column="1" Text="{Binding Title}" TextColor="White" VerticalOptions="Center"/>
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
MasterPage items:
public class MasterPageItem
{
public string Title { get; set; }
public string IconSource { get; set; }
public Type TargetType { get; set; }
}
So I've implemented INotifyPropertyChanged inside MasterPageItem:
public class MasterPageItem : INotifyPropertyChanged
{
public string Title { get; set; }
public string IconSource { get; set; }
public Type TargetType { get; set; }
public event PropertyChangedEventHandler PropertyChanged = delegate { };
private bool isVisible;
public bool IsVisible
{
get { return isVisible; }
set
{
isVisible = value;
PropertyChanged(this, new PropertyChangedEventArgs("IsVisible"));
}
}
}
But how can I bind this to my MasterPage?
In the end I've implemented 2 different MasterPages, so I can switch between them when needed.
So I have 2 MainPages the 1st one refers to MasterPage1:
<MasterDetailPage.Master>
<views:MasterPage1 x:Name="masterPage1" />
</MasterDetailPage.Master>
<MasterDetailPage.Detail>
<NavigationPage>
<x:Arguments>
<views:SomePage1/>
</x:Arguments>
</NavigationPage>
</MasterDetailPage.Detail>
The 2nd MainPage2 - to MasterPage2:
<MasterDetailPage.Master>
<views:MasterPage2 x:Name="masterPage2" />
</MasterDetailPage.Master>
<MasterDetailPage.Detail>
<NavigationPage>
<x:Arguments>
<views:SomePage2/>
</x:Arguments>
</NavigationPage>
</MasterDetailPage.Detail>
I know it's not the best solution, but for my case it's enough.
First of all, learn how to ask; https://stackoverflow.com/help/how-to-ask
You expect us to understand how you build up your views and modify them, without even showing a single line of code.
Generally speaking, you can change the View of the Master Page by changing the Master-Property of a Xamarin.Forms.MasterDetailPage. If you assigned a Xamarin.Forms.ContentPage to the Master-Property, you can acces it by ((ContentPage)YourMasterDetailPage.Master).Content.
Im sure this question has been answered already 100 times and follows the basic structure of xamarin forms.
Learn MasterDetailPage from scratch here:
https://learn.microsoft.com/en-US/xamarin/xamarin-forms/app-fundamentals/navigation/master-detail-page
Since you provided some code now, here's a little example:
void OnItemSelected(object sender, SelectedItemChangedEventArgs e)
{
var item = e.SelectedItem as MasterPageItem;
if (item != null)
{
Detail = new NavigationPage((Page)Activator.CreateInstance(item.TargetType));
item.IsVisible = false; //this would make the clicked item invisible
masterPage.listView.SelectedItem = null;
IsPresented = false;
}
}

Categories