Scrollview control not working properly in .Net MAUI (Android) - c#

I have created custom tab control using ScrollView control and Bindable StackLayout control.
I have first created this solution in Xamarin.Forms (VS for Mac 2019) and it works fine in both platforms, but the same solution when developed in .Net MAUI (VS for Mac 2022 Prev) it's not working properly in Android.
Update 30 Jun 2022
There is an issue with BindableLayout (StackLayout) properties in MAUI currently so when we are changing values it does not get reflected, and because of this, I think I'm facing this issue. Here is the reference
Here is what I have done so far:
MainPage.xaml
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:vm="clr-namespace:poc_maui.ViewModels"
x:Class="poc_maui.Views.HomePage"
xmlns:tabs="clr-namespace:poc_maui.Views.SubViews"
Title="HomePage">
<ContentPage.BindingContext>
<vm:MainPageViewModel />
</ContentPage.BindingContext>
<Grid RowDefinitions="50, *" RowSpacing="0">
<ScrollView Grid.Row="0" Orientation="Horizontal" VerticalOptions="Start" HorizontalScrollBarVisibility="Never"
Scrolled="ScrollView_Scrolled">
<StackLayout x:Name="TabsView"
Orientation="Horizontal"
BindableLayout.ItemsSource="{Binding Tabs}" Spacing="0">
<BindableLayout.ItemTemplate>
<DataTemplate>
<Grid RowDefinitions="*, 4" RowSpacing="0">
<Label Grid.Row="0"
Text="{Binding TabTitle}"
TextColor="White"
BackgroundColor="navy"
Padding="20,0"
VerticalTextAlignment="Center"
HorizontalTextAlignment="Center"
FontSize="12"
HeightRequest="40"/>
<BoxView Grid.Row="1"
Color="Yellow"
IsVisible="{Binding IsSelected}"/>
<Grid.GestureRecognizers>
<TapGestureRecognizer Command="{Binding Path=BindingContext.TabChangedCommand,
Source={x:Reference TabsView}}"
CommandParameter="{Binding .}"/>
</Grid.GestureRecognizers>
</Grid>
</DataTemplate>
</BindableLayout.ItemTemplate>
</StackLayout>
</ScrollView>
<tabs:ParentRecordTabView Grid.Row="1" IsVisible="{Binding IsParentRecordTabVisible}"
VerticalOptions="FillAndExpand"/>
<tabs:AdditionalInfoTabView Grid.Row="1" IsVisible="{Binding IsAdditionalInfoTabVisible}"
VerticalOptions="FillAndExpand" />
</Grid>
</ContentPage>
MainPageViewModel
using System;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Windows.Input;
using poc_maui.Models;
namespace poc_maui.ViewModels
{
public class MainPageViewModel : BaseViewModel
{
#region Constructor
public MainPageViewModel()
{
GetTabs();
}
#endregion
#region Private Properties
private bool _isParentRecordTabVisible = true;
private bool _isAdditionalInfoTabVisible;
private ObservableCollection<TabViewModel> _tabs { get; set; }
#endregion
#region Public Properties
public bool IsParentRecordTabVisible
{
get => _isParentRecordTabVisible;
set { _isParentRecordTabVisible = value; OnPropertyChanged(nameof(IsParentRecordTabVisible)); }
}
public bool IsAdditionalInfoTabVisible
{
get => _isAdditionalInfoTabVisible;
set { _isAdditionalInfoTabVisible = value; OnPropertyChanged(nameof(IsAdditionalInfoTabVisible)); }
}
public ObservableCollection<TabViewModel> Tabs
{
get => _tabs;
set { _tabs = value; OnPropertyChanged(nameof(Tabs)); }
}
#endregion
#region Commands
public ICommand TabChangedCommand { get { return new Command<TabViewModel>(ChangeTabClick); } }
#endregion
#region Private Methods
private void GetTabs()
{
Tabs = new ObservableCollection<TabViewModel>();
Tabs.Add(new TabViewModel { TabId = 1, IsSelected = true, TabTitle = "Parent record" });
Tabs.Add(new TabViewModel { TabId = 2, TabTitle = "Additional Info" });
Tabs.Add(new TabViewModel { TabId = 3, TabTitle = "Contacts" });
Tabs.Add(new TabViewModel { TabId = 4, TabTitle = "Previous inspections" });
Tabs.Add(new TabViewModel { TabId = 5, TabTitle = "Attachments" });
SelectedTab = Tabs.FirstOrDefault();
}
private void ChangeTabClick(TabViewModel tab)
{
try
{
var tabs = new ObservableCollection<TabViewModel>(Tabs);
foreach (var item in tabs)
{
if (item.TabId == tab.TabId)
{
item.IsSelected = true;
}
else
{
item.IsSelected = false;
}
}
Tabs.Clear();
Tabs = new ObservableCollection<TabViewModel>(tabs);
switch (tab.TabId)
{
case 1:
IsParentRecordTabVisible = true;
IsAdditionalInfoTabVisible = false;
break;
case 2:
IsParentRecordTabVisible = false;
IsAdditionalInfoTabVisible = true;
break;
}
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
}
}
#endregion
}
}
#ParentTabView.xaml
<ContentView xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="poc_maui.Views.SubViews.ParentTabView">
<StackLayout HorizontalOptions="FillAndExpand" VerticalOptions="CenterAndExpand" >
<Label
Text="Welcome to Parent tab!"
VerticalOptions="Center"
HorizontalOptions="Center" />
</StackLayout>
</ContentView>
#AdditionalInfoTabView.xaml
<ContentView xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="poc_maui.Views.SubViews.AdditionalInfoTabView">
<StackLayout HorizontalOptions="FillAndExpand" VerticalOptions="CenterAndExpand" >
<Label
Text="Welcome to Additiona info tab!"
VerticalOptions="Center"
HorizontalOptions="Center" />
</StackLayout>
</ContentView>
So what happens here in Android is when I'm clicking AdditionalInfo Tab then it will show a blank white screen and if you press the hardware back button and open the app again it will show AdditionalTab as selected and its views content as well.
If I remove switch() code part from the ViewModel then it will work fine but tabs will not change. Does anyone have idea about this kind of behavior of scroll view in MAUI?
The full source code is here: maui_sample

Does this work-around fix it?
MainPage.xaml:
<ScrollView x:Name "theScrollView" ... >
MainPage.xaml.cs:
public MainPage()
{
InitializeComponent();
MessagingCenter.Subscribe<MainPageViewModel>(this, "update", (sender) =>
{
// Tell theScrollView to re-layout its contents.
(theScrollView as IView).InvalidateArrange();
});
}
MainPageViewModel:
private void ChangeTabClick(TabViewModel tab)
{
... make changes ...
MessagingCenter.Send<MainPageViewModel>(this, "update");
}
MAYBE:
I'm not sure if MessagingCenter Subscribe is on Dispatcher (Main) thread. To be reliable, do:
MessagingCenter.Subscribe<MainPageViewModel>(this, "update", (sender) =>
{
Dispatcher.Dispatch( () =>
{
(theScrollView as IView).InvalidateArrange();
});
}
UPDATE
There are other Maui bugs, that have a common "theme": Maui on Android does "something" related to layout only once - at the time the page is first drawn. UNFORTUNATELY, anything that is "not visible" at that time, is skipped. And won't work when later made visible.
Until such bugs are fixed, you'll have to do some work-around.
WORK-AROUND #1:
Start with ALL tabs IsVisible="True".
As soon as the page has been drawn the first time, in code-behind, create the desired Bindings on those IsVisible properties. Page drawn first time can be intercepted in a custom handler. But this is a temp work-around, so its easier to just run a method after a 250 ms delay. Use a boolean "flag" to make the method only run the first time.
Might have to do InvalidateArrange as shown above, to force the Bindings to function the first time.
OR WORK-AROUND #2:
Each time tab changes, use shell route to go to MainPage again. Keep same view model, so knows which tab to show first (and remembers any other state you care about).
Both of these are ugly.
I recommend creating an issue at .Net Maui github, and providing link to your github sample.

This is still not works for me properly but after looking at below two links I found that it it not what we are looking for. The Isvisible : false first and then on switch or check box change you are trying to make it visible then it will not visible but the actual control visible. So on look after I have see this link but again the answer is not what I was looking for.
Step to resolve.
On View use the Parent as ScrollView or control belongs to IView,IElement.
<ScrollView x:Name "myScrollView">
.....
...
Add Action on ViewModel
public delegate void Action(T obj);
Invoke the Action
Note: Make sure you call this on require not all the time.
e.g. On Visibility set in ViewModel call after visibility update.
MeasureAction?.Invoke("reSetVisibility");
Now on View's Code File, use Viewmodel and accept the invoke
Here Call the below line will works perfectly.
(myScrollView as IView).InvalidateMeasure();
That's IT... Enjoy IsVisible now and make your layout as require.

Related

Xamarin -- Radiobutton visual state doesn't update after setting the value in a viewmodel when using Syncfusion's SfPopupLayout

When working with data-binding I've run into an issue where the radiobutton won't update visually, but the value is correct. I have a RadiobuttonGroup.GroupName & a RadioButtonGroup.SelectedValue. The SelectedValue is data-bound to my ViewModel with a {Binding Selection}. Selection is also declared in my ViewModel.
Whenever I change the RadioButton's selection to a button that isn't selected, OnPropertyChanged(); goes off thrice. (I suppose that is due to the fact that there's three buttons in the view, could be wrong here.) Resulting in the value being selected and being handed over to my data-bound Selection. But the visual state of the button doesn't change. The radiobuttons are located in a SfPopupLayout pop-up. It always works as expected the first time the pop-up is initialized and served in the view. But with every subsequent serving, it bugs out visually. Resulting in having to click the radiobutton multiple times to make the visual-state change.
There really isn't much going on, just that Selection is stored in my ViewModel. I've checked the Xamarin-Examples-Demos on GitHub with regards to RadioButtons & data-binding and I'm not able to reproduce the same issues I'm experiencing with the demo.
XAML code snippet;
<StackLayout HeightRequest="160"
Grid.Row="2"
RadioButtonGroup.GroupName="WeekSelection"
RadioButtonGroup.SelectedValue="{Binding Selection}">
<RadioButton Padding="5"
BackgroundColor="{DynamicResource BlockBackgroundColor}"
Content="{markup:Translate Week_Selection}"
Value="{markup:Translate Week_Selection}"/>
<BoxView Style="{StaticResource SeperatorLineStyle}"/>
<RadioButton Padding="5"
BackgroundColor="{DynamicResource BlockBackgroundColor}"
Content="{markup:Translate TwoWeek_Selection}"
Value="{markup:Translate TwoWeek_Selection}"/>
<BoxView Style="{StaticResource SeperatorLineStyle}"/>
<RadioButton Padding="5"
BackgroundColor="{DynamicResource BlockBackgroundColor}"
Content="{markup:Translate Month_Selection}"
Value="{markup:Translate Month_Selection}"/>
<BoxView Style="{StaticResource SeperatorLineStyle}"/>
</StackLayout>
UPDATE: Seems like it has something to do with switching views. Whenever I go to my settings-page to change the selection of the radiobuttons, OnPropertyChanged(); is only fired once. But whenever I close the view and return to it, it fires it off twice. And subsequently with every switch it increases the amount of times OnPropertyChanged(); is called. Value still works properly, just the visual state isn't updated.
UPDATE 2: I'm pretty sure it has to do with the pop-up that's generated containing the radiobuttons. Here's the code that initializes the pop-up with the radiobuttons in them;
public void ShowAmountOfWeeksPopup()
{
_selectWeeksToViewPopupControl = new SelectWeeksToViewPopupControl(this);
_selectWeeksToViewPopupControl.Show();
}
public void DismissAmountOfWeeksPopup()
{
_selectWeeksToViewPopupControl.Dismiss();
}
FINAL UPDATE:
According to SyncFusion this is a bug, ended up creating a forum post on their support forums and they ended up supplying me with a fix. If anybody ever runs into the same issue, please refer to the following link; https://www.syncfusion.com/forums/171545/radiobuttons-not-working-properly-when-closing-and-re-opening-a-popup
Xamarin -- Radiobutton visual state doesn't update after setting the
value in a viewmodel.
I couldn't see other code of your app. So I did a test based on the sample code GroupedRadioButtonsViewModelPage.xaml, but I couldn't reproduce this problem.
You can refer to the following code:
The GroupedRadioButtonsViewModelPage.xaml
<?xml version="1.0" encoding="UTF-8"?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="RadioButtonDemos.GroupedRadioButtonsViewModelPage"
Title="Grouped RadioButtons ViewModel demo">
<StackLayout Margin="10"
RadioButtonGroup.GroupName="{Binding GroupName}"
RadioButtonGroup.SelectedValue="{Binding Selection}">
<Label Text="What's your favorite animal?" />
<RadioButton Content="Cat"
Value="Cat" />
<RadioButton Content="Dog"
Value="Dog" />
<RadioButton Content="Elephant"
Value="Elephant" />
<RadioButton Content="Monkey"
Value="Monkey"/>
<Label x:Name="animalLabel">
<Label.FormattedText>
<FormattedString>
<Span Text="You have chosen:" />
<Span Text="{Binding Selection}" />
</FormattedString>
</Label.FormattedText>
</Label>
<Button Text="test" Clicked="Button_Clicked"/>
</StackLayout>
</ContentPage>
The GroupedRadioButtonsViewModelPage.xaml.cs
public partial class GroupedRadioButtonsViewModelPage : ContentPage
{
AnimalViewModel model;
public GroupedRadioButtonsViewModelPage()
{
InitializeComponent();
model = new AnimalViewModel();
BindingContext = model;
//BindingContext = new AnimalViewModel
//{
// GroupName = "animals",
// Selection = "Monkey"
//};
}
private void Button_Clicked(object sender, System.EventArgs e)
{
model.Selection = "Dog";
}
}
The AnimalViewModel.cs
public class AnimalViewModel : INotifyPropertyChanged
{
string groupName;
object selection;
public AnimalViewModel() {
GroupName = "animals";
Selection = "Elephant";
}
public string GroupName
{
get => groupName;
set
{
groupName = value;
OnPropertyChanged(nameof(GroupName));
}
}
public object Selection
{
get => selection;
set
{
selection = value;
OnPropertyChanged(nameof(Selection));
}
}
public event PropertyChangedEventHandler PropertyChanged;
void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
Note:
I added a button, and when clicking the Button, we can change the value of Selection of the ViewModel(AnimalViewModel), then the UI will automatically refresh.

Issue displaying images with FlowListView & FFImageLoading in Xamarin.Forms

In XAML & C# using Xamarin.Forms (iOS Project) I'm trying to create a gallery where the user can add photos to it. Currently I can show a list that does have the photo data binded to each entry because the user can click on an item in the list and the correct image will show up.. However I have not been successful in actually displaying a smaller version of the pictures in my FlowListView. I know it has to be something with the binding and I'm trying to grab the image uri from each object to display it but I'm still pretty new to this, especially to xaml and haven't been successful with this part yet.
If you could point me in the right direction that would be sweet!
Expected Result
To display images in 2 columns using FlowListView and FFImageLoading
Actual Result
I currently an able to display a 2 column list that has the right objects tied to each item but the only way I can actually see if anything is there is if I add a frame or add a text label to each item.
The user can click on each label currently and the correct image will show.
This is part of my TicketPageModel
private void AddItems()
{
public void UpdatePhotosData()
{
//get the notes and set the source for the list to them.
photos = NLTicketPhotos.Get(_ticket).OrderByDescending(x => x.PhotoCreatedAt).ToList();
}
foreach (var i in photos)
{
Items.Add(i);
}
}
private ObservableCollection<NLTicketPhoto> _items = new ObservableCollection<NLTicketPhoto>();
public ObservableCollection<NLTicketPhoto> Items
{
get
{
return _items;
}
set
{
if (_items != value)
{
_items = value;
OnPropertyChanged(nameof(Items));
}
}
}
My XAML
<flv:FlowListView FlowColumnCount="2" SeparatorVisibility="Default" HasUnevenRows="True" FlowItemTapped="OnImageTapped" FlowItemsSource="{Binding Items}">
<flv:FlowListView.FlowColumnTemplate>
<DataTemplate>
<StackLayout Padding="10" Spacing="0" AutomationProperties.Name="Too Cool">
<ff:CachedImage Aspect="AspectFill" HeightRequest="30">
<ff:CachedImage.Source>
<UriImageSource Uri="{Binding Items.PhotoFileUrl}"/>
</ff:CachedImage.Source>
</ff:CachedImage>
<StackLayout Orientation="Horizontal" Padding="10" Spacing="0">
<Label HorizontalOptions="Fill" VerticalOptions="Fill" TextColor="Black" XAlign="Center" YAlign="Center" Text="Too Cool For School"/>
</StackLayout>
</StackLayout>
</DataTemplate>
</flv:FlowListView.FlowColumnTemplate>
</flv:FlowListView>
My Code Behind
void OnImageTapped(object sender, ItemTappedEventArgs e)
{
NLTicketPhoto photo = (NLTicketPhoto)e.Item;
//listPhotos.SelectedItem = null; //deselect the item
switch (photo.PhotoFileType)
{
case "mov":
if (photo.PhotoIsOnServer)
{
Device.OpenUri(new Uri(photo.PhotoFileName));
}
else
{
//Only watch videos after sync
DisplayAlert("Video Unavailable", string.Format("This video will be viewable after it is synced to the server."), "OK");
}
break;
case "jpg":
//View image
NLPageViewPhoto preview = new NLPageViewPhoto(photo);
Navigation.PushAsync(preview);
break;
default:
DisplayAlert("Photo Unavailable", string.Format("The photo format .{0} is currently not viewable", photo.PhotoFileType), "OK");
break;
}
}
Once I implemented INotifyPropertyChanged to my NLTicketPhoto model and tweaked my PhotoUrl and PhotoDescription properties to use OnPropertyChanged() I was able to get my list to display properly.
Following this example helped me. https://www.c-sharpcorner.com/article/grid-view-in-xamarin-forms-using-flowlistview/

ListView items get updated only after scrolled back into view - Xamarin Forms

I have created a listview which has children whose background is bound to itemssource.
This works well on Android with the PropertyChanged event called.
But unfortunately it doesn't work as smooth on iOS the background change gets reflected only after I've scrolled the element out of view and back into the view to redraw it.
Is there any other way I can make the content refresh manually?
Code:
<ListView x:Name="ListView" ItemsSource="{Binding ListSource}" RowHeight="50">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<ViewCell.View>
<ContentView Padding="10" BackgroundColor="{Binding BackgroundColor}">
<Label Text="{Binding Name}" HorizontalOptions="Center" TextColor="White" />
</ContentView>
</ViewCell.View>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Handling the itemclick to change the background and remove the selecteditem.
ListView.ItemTapped += async (s, e) =>
{
var list = ListSource;
var listItem = list.First(c => c.Id == ((ListItem)e.Item).Id);
listItem.Selected = !listItem.Selected;
SelectListSource = list;
ListView.SelectedItem = null;
};
Code in the model :
public Boolean Selected
{
get
{
return _selected;
}
set
{
_selected = value;
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs("BackgroundColor"));
}
}
public Color BackgroundColor
{
get
{
if (Selected)
return Color.Black;
else
return Color.Blue
}
}
Ok so I found a work around by using XFGloss.
Added Binding to the ViewCell with the help of this nuget.
<ViewCell xfg:CellGloss.BackgroundColor="{Binding BackgroundColor}">

How to make the loading screen to disappear when my data is loaded in Xamarin Forms?

I want to build a loading screen when no data is displayed. But it's not working, it keeps loading forever. How to make the loading screen to disappear when my data is loaded?
This is my C# code
if (Clublistview.ItemsSource == null)
{
try
{
base.OnAppearing();
await setClubs(Clublistview);
overlay.IsVisible = false;
Clublistview.IsVisible = true;
}
catch (Exception ex)
{
//MessagingCenter
await DisplayAlert("Error",
"There seems to be an error, please check your internet connection.",
"OK");
}
}
else
{
overlay.IsVisible = true;
Clublistview.IsVisible = false;
}
This is the XAML code
<ListView x:Name="Clublistview" HasUnevenRows="true" ItemSelected="OnItemSelected" ItemsSource="{Binding Id}" IsVisible="true">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell Height="55">
<StackLayout BackgroundColor="White"
Orientation="Vertical">
<StackLayout Orientation="Horizontal" Padding="2,2,2,2">
<Image Source="{Binding Logo}" IsVisible="true" WidthRequest="50" HeightRequest="50"/>
<StackLayout Orientation="Vertical">
<Label Text="{Binding Name}" FontSize="20" x:Name="BtnClub"
TextColor="Black" />
<Label HorizontalOptions="Start" Text="Select for more info" FontSize="10"/>
<!--<Button BackgroundColor="White" TextColor="Black" HorizontalOptions="Start" x:Name="btnInfo"
Text="Select for more info" FontSize="10" Clicked="OnInfoClicked" CommandParameter="{Binding Id}"/>-->
</StackLayout>
</StackLayout>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<ContentView x:Name="overlay" HorizontalOptions="CenterAndExpand" VerticalOptions="CenterAndExpand" AbsoluteLayout.LayoutFlags="All" IsVisible="false">
<ActivityIndicator IsRunning="True" IsVisible="True" Color="Black" HorizontalOptions="CenterAndExpand" VerticalOptions="CenterAndExpand"/>
</ContentView>
It looks like this code is placed on the OnAppearing method of your ContentPage. If that's the case, it's only going to be called 1 time as the page is shown. Assuming that Clublistview.ItemsSource is not null, then this code gets executed:
overlay.IsVisible = true;
Clublistview.IsVisible = false;
This means that your overlay is visible and the ActivityIndicator will be spinning. If this is not in OnAppearing then I am not sure when you are calling the method it is in.
You might want to do something like this instead:
public override async void OnAppearing()
{
base.OnAppearing();
// Show your overlay
overlay.IsVisible = true;
Clublistview.IsVisible = false;
// Load the items into the ItemsSource
await setClubs(Clublistview);
// Hide the overlay
overlay.IsVisible = false;
Clublistview.IsVisible = true;
}
You can achieve this type of behavior in a cleaner way with the MVVM pattern. With MVVM you can use a property binding to control when the overlay is shown. We have some guides on MVVM and Xamarin.Forms that can help get you started here. Here is a blog post that shows an example too.
This is what worked for me:
protected override void OnAppearing()
{
base.OnAppearing();
this.layoutLoadingSpinner.IsVisible = true;
this.layoutContent.IsVisible = false;
// Load slow-loading model on a separate thread
MySlowLoadingModel model = null;
await Task.Run(() =>
{
model = new MySlowLoadingModel();
});
this.BindingContext = model;
this.layoutLoadingSpinner.IsVisible = false;
this.layoutContent.IsVisible = true;
}
(Another option that avoids async/await is to call MainThread.BeginInvokeOnMainThread() inside the Task.Run)
An unfortunate side-effect is that any code run on the second thread becomes very difficult to debug. It seems the Xamarin debugger doesn't work right with multiple threads.

How to access StackLayout from the backend?

I have been using Xamarin Forms to develop iOS and Android applications. I want to access a StackLayout that is within a TabbedPage so I can make it visible or hidden whenever the user changes tabs, but when I try to access the StackLayout I get "This does not exist in the current context". Here is my XAML code and my CS code.
CS
using System;
using System.Collections.Generic;
using Xamarin.Forms;
namespace DebuggerTestAndroidIOS
{
public partial class PatientTabPage : TabbedPage
{
public PatientTabPage ()
{
InitializeComponent ();
ItemsSource = PatientDataModel.tabs;
//vitalSignsStack.IsVisible = true;
this.CurrentPageChanged += (object sender, EventArgs e) => {
var i = this.Children.IndexOf(this.CurrentPage);
System.Diagnostics.Debug.WriteLine("Page No:"+i);
if (i == 1){
vitalSignsStack.IsVisible = true;
}
};
}
}
}
XAML
<?xml version="1.0" encoding="UTF-8"?>
<TabbedPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="DebuggerTestAndroidIOS.PatientTabPage">
<TabbedPage.ItemTemplate>
<DataTemplate>
<ContentPage Title ="{Binding TabName}">
<!--Parent Wrapper layout-->
<StackLayout Orientation="Vertical" BackgroundColor="White">
<StackLayout x:Name="vitalSignsStack" Orientation="Horizontal" IsVisible="false">
<Image Source="VitalSigns.png" HorizontalOptions="Center"/>
</StackLayout>
</StackLayout><!--End parent wrapper-->
</ContentPage>
</DataTemplate>
</TabbedPage.ItemTemplate>
</TabbedPage>
An element is only going to be accesible within the context of the page that created it - in this case, the ContentPage.
If you want to reach it from outside of the ContentPage, you will need to add a public method or property to the ContentPage that exposes it.
You cannot access a control inside a DataTemplate with its name. The problem is, that it will be repeated and so this name would exist multiple times, what is not allowed.
But why don't you create a new Page like this:
public partial class PatientTabContentPage : TabbedPage
{
public PatientTabContentPage ()
{
InitializeComponent ();
}
public HideVitalSignsStack(bool true){
vitalSignsStack.IsVisible = true;
}
}
And change DataTemplate to
<DataTemplate>
<PatientTabContentPage Title ="{Binding TabName}">
</DataTemplate>
Then hide the stackpanel with
this.CurrentPageChanged += (object sender, EventArgs e) => {
var page = CurrentPage as PatientTabContentPage;
var i = this.Children.IndexOf(this.CurrentPage);
System.Diagnostics.Debug.WriteLine("Page No:"+i);
if (i == 1){
page.HideVvitalSignsStack(true);
}
};
Thanks for your efforts. I tried them, still was not able to access the StackLayouts. I modified a little bit my code, this helped a lot and made everything easier: Creating different layouts for each tab

Categories

Resources