Changing RowDefinition of a ListView item on Tap - c#

What I'm trying to implement is a message chat bubble wherein you tap the control/message and the message would expand showing details of the date and the seen / sent status below. I do have a DataTemplate Selector for the different controls I have for the Sender and the Receiver.
My problem is changing the Height of the message in the ListView. I tried implementing the Binding of the RowDefinition to whatever the Height variable is in my Message class (the class that holds info regarding the message). Although the height was updated, it didn't reflect on the ListView. I've scoured over the internet for existing chat UI templates but I think most of them are paid. Hence, I'm trying to do follow Change WPF DataTemplate for ListBox item if selected. But for Xamarin, there's no ListBoxItem as there's only a ListView.
On a further note, I am working on Android and iOS. An example that is cross-platform to solve this will be greatly appreciated. Below are parts of my code.
datatemplate.cs
class MessageTemplateSelector : DataTemplateSelector
{
public MessageTemplateSelector()
{
ReceiverDataTemplate = new DataTemplate(typeof(MessageReceiver));
SenderDataTemplate = new DataTemplate(typeof(MessageSender));
}
protected override DataTemplate OnSelectTemplate(object item, BindableObject container)
{
var message = item as Message;
if (message == null)
return null;
return message.isSender ? ReceiverDataTemplate : SenderDataTemplate;
}
private readonly DataTemplate ReceiverDataTemplate;
private readonly DataTemplate SenderDataTemplate;
}
MessageSender.xaml
<?xml version="1.0" encoding="UTF-8"?>
<ViewCell xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Project.layout.MessageSender">
<ViewCell.View>
<Grid HorizontalOptions="EndAndExpand">
<Grid.RowDefinitions>
<RowDefinition Height="{Binding Path=Height}"/>
<RowDefinition Height="*" />
<RowDefinition Height="{Binding Path=Height}" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="75" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="15" />
</Grid.ColumnDefinitions>
<Label Text="{Binding Path=timestamp}" Grid.Column="0" Grid.Row="0" Grid.ColumnSpan="3" HorizontalTextAlignment="Center" HorizontalOptions="Center" VerticalOptions="Center" IsVisible="{Binding Path=Selected}"/>
<Frame Padding="0" CornerRadius="20" Grid.Column="1" Grid.Row="1" HorizontalOptions="EndAndExpand" >
<Grid BackgroundColor="White" VerticalOptions="FillAndExpand">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Label Text="{Binding Path=text}" VerticalOptions="FillAndExpand" Margin="15,10"/>
</Grid>
</Frame>
<Label Text="Seen" Grid.Column="1" Grid.Row="2" HorizontalOptions="EndAndExpand" IsVisible="{Binding Path=Selected}"/>
</Grid>
</ViewCell.View>
</ViewCell>
Message.cs
class Message
{
public bool isSender { get; set; }
public sbyte status { get; set; }
public string text { get; set; }
public string timestamp { get; set; }
public Message(bool isSender, sbyte status, string text, string timestamp)
{
this.isSender = isSender;
this.status = status;
this.text = text;
this.timestamp = timestamp;
}
public sbyte height = 0;
public sbyte Height { get { return height; } set { height = value; } }
bool selected = false;
public bool Selected
{
get { return selected; }
set { selected = value;if (value) { Height = 25; } else { Height = 0; } }
}
}
Show mainpage.xaml
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:Project.model"
x:Class="Project.MainPage">
<ContentPage.Resources>
<ResourceDictionary>
<local:MessageTemplateSelector x:Key="MessageTemplateSelector"></local:MessageTemplateSelector>
</ResourceDictionary>
</ContentPage.Resources>
<StackLayout>
<ListView x:Name="conversation"
ItemTemplate="{StaticResource MessageTemplateSelector}"
ItemsSource="{Binding Message}"
HasUnevenRows="True"
SeparatorVisibility="None"
RelativeLayout.HeightConstraint="{ConstraintExpression Type=RelativeToParent,Property=Height,Factor=1,Constant=0}"
IsPullToRefreshEnabled="true"
ItemTapped="Conversation_ItemTapped"
Refreshing="Conversation_Refreshing">
</ListView>
</ContentPage>
MainPage.cs
private void Conversation_ItemTapped(object sender, ItemTappedEventArgs e)
{
if (e.Item == null) return;
Message selectedItem = (Message)e.Item;
Log.Debug("ItemTap","Height before:" + selectedItem.Height);
if (selectedItem.Selected) { ((ListView)sender).SelectedItem = null; selectedItem.Selected = false; }
else { selectedItem.Selected = true; }
Log.Debug("ItemTap", "Height after:" + selectedItem.Height);
}
This is a screenshot of my log that is present in the ItemTapped event in my ListView. As you can see, the height updates but it's not reflecting on the ListView.

Related

How to change Label color on Entry GotFocus from CollectionView

Is there a way to bind the state of FontColor of Label in Xamarin so that it highlights the Label when Entry(textbox) gets focus?
<CollectionView x:Name="documentsListView" ItemsSource="{Binding DocumentsList}">
<CollectionView.ItemsLayout>
<LinearItemsLayout Orientation="Vertical"
ItemSpacing="0" />
</CollectionView.ItemsLayout>
<CollectionView.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="3*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Label Grid.Column="0"
Margin="0,10,0,0"
Text="{Binding Name}" FontSize="Body"/>
<Entry Grid.Column="1" Grid.RowSpan="1"
IsPassword="False"
Keyboard="Numeric"
Placeholder="{Binding Count}"
Text="{Binding Count, Mode=OneWayToSource}"
Unfocused="{Binding OnTextboxLostFocus}"
Focused="{Binding OnTextboxGotFocus}"/>
</Grid>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
I need to highlight the element which is going to be changed when the user enters data to the Entry(textbox), and because the space between elements in CollectionView should be less so that I can show as much data per scroll as possible it might confuse the user which element exactly he is changing. I thought about passing a label as a parameter to the Events but could not find out how to bind the label.
Bind the textColor of label to a property in model and update that textColor when the entry focused/unfocused.
Here is an example I use:
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
this.BindingContext = new DncMvvmPageModel();
}
}
public class DncMvvmPageModel
{
public ObservableCollection<Document> DocumentsList { get; set; }
public Command OnTextboxLostFocus { get; }
public Command OnTextboxGotFocus { get; }
public DncMvvmPageModel()
{
OnTextboxLostFocus = new Command(OnTextboxLostFocusMethod);
OnTextboxGotFocus = new Command(OnTextboxGotFocusMethod);
DocumentsList = new ObservableCollection<Document>();
DocumentsList.Add(new Document() {TextColor = Color.Gray });
DocumentsList.Add(new Document() { TextColor = Color.Gray });
DocumentsList.Add(new Document() { TextColor = Color.Gray });
DocumentsList.Add(new Document() { TextColor = Color.Gray });
}
public void OnTextboxLostFocusMethod(object sender) {
FocusEventArgs args = sender as FocusEventArgs;
Entry entry = args.VisualElement as Entry;
Document docu = entry.BindingContext as Document;
docu.TextColor = Color.Red;
}
public void OnTextboxGotFocusMethod(object sender)
{
FocusEventArgs args = sender as FocusEventArgs;
Entry entry = args.VisualElement as Entry;
Document docu = entry.BindingContext as Document;
docu.TextColor = Color.Blue;
}
}
public class Document : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
Color textColor;
public Color TextColor
{
set
{
if (textColor != value)
{
textColor = value;
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs("TextColor"));
}
}
}
get
{
return textColor;
}
}
}
And in Xaml:
<CollectionView x:Name="documentsListView" ItemsSource="{Binding DocumentsList}">
<CollectionView.ItemsLayout>
<LinearItemsLayout Orientation="Vertical"
ItemSpacing="0" />
</CollectionView.ItemsLayout>
<CollectionView.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="3*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Label Grid.Column="0"
Margin="0,10,0,0"
Text="Name" FontSize="Body" TextColor="{Binding TextColor}"/>
<Entry Grid.Column="1" Grid.RowSpan="1"
IsPassword="False"
Keyboard="Numeric"
Placeholder="placeholder"
Text="Count">
<Entry.Behaviors>
<behaviors:EventToCommandBehavior EventName="Focused"
Command="{Binding BindingContext.OnTextboxGotFocus, Source={x:Reference MyPage}}" />
<behaviors:EventToCommandBehavior EventName="Unfocused"
Command="{Binding BindingContext.OnTextboxLostFocus, Source={x:Reference MyPage}}" />
</Entry.Behaviors>
</Entry>
</Grid>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
Result:
Feel free to ask me any question if you have:).

How to add select effect to an image button?

What I am trying to implement: I want to have four image buttons that if I click on one button then there will be a little check mark displayed showing that I select the check mark. And if I click on another button, then the check mark of the previous button will disappear and my newly selected button will show a little check mark.
The code I currently have:
<Grid HorizontalOptions="CenterAndExpand"
VerticalOptions="CenterAndExpand"
Margin="20, 80">
<Grid.RowDefinitions>
<RowDefinition Height="120" />
<RowDefinition Height="120" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="1*" />
</Grid.ColumnDefinitions>
<ImageButton Source="select_payment_placeholder.png"
Grid.Row="0"
Grid.Column="0" />
<ImageButton Source="select_payment_placeholder.png"
Grid.Row="0"
Grid.Column="1" />
<ImageButton Source="select_payment_placeholder.png"
Grid.Row="1"
Grid.Column="0" />
<ImageButton Source="select_payment_placeholder.png"
Grid.Row="1"
Grid.Column="1" />
</Grid>
This is the demo of the effect that I am trying to implement.
Here I used the Xamarin.Forms CollectionView as the parent layout .
Create the CheckItem :
public class CheckItem : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public string ContentImage { set; get; }
private bool isShow;
public bool IsShow
{
set
{
if (isShow != value)
{
isShow = value;
OnPropertyChanged("IsShow");
}
}
get
{
return isShow;
}
}
public ICommand TapCommand
{
get
{
return new Command((e) =>
{
var item = (e as CheckItem);
// logic on item
if (item.isShow)
{
PageMain.checkItems[0].IsShow = false;
PageMain.checkItems.Remove(PageMain.checkItems[0]);
PageMain.checkItems.Add(item);
}
else
{
item.IsShow = true;
if (PageMain.checkItems.Count == 0)
{
PageMain.checkItems.Add(item);
}
else
{
PageMain.checkItems[0].IsShow = false;
PageMain.checkItems.Remove(PageMain.checkItems[0]);
PageMain.checkItems.Add(item);
}
}
});
}
}
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
Then the CheckModel can be set a list data with four item :
public class CheckModel
{
public List<CheckItem> CheckItems { set; get; }
public CheckModel()
{
CheckItems = new List<CheckItem>();
CheckItems.Add( new CheckItem() { ContentImage = "XamarinLogo.png", IsShow = false});
CheckItems.Add( new CheckItem() { ContentImage = "XamarinLogo.png", IsShow = false});
CheckItems.Add( new CheckItem() { ContentImage = "XamarinLogo.png", IsShow = false});
CheckItems.Add( new CheckItem() { ContentImage = "XamarinLogo.png", IsShow = false});
}
}
In the ContentPage , the Xaml code contains a CollectionView and which contains the ImageButton and MarkIcon . And the MarkIcon default is invisible .
<?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="ImageButonSingleCheck.PageMain">
<ContentPage.Content>
<StackLayout>
<Label Text="Welcome to Xamarin.Forms!"
VerticalOptions="Start"
HorizontalOptions="Start" />
<CollectionView x:Name="MyCollectionView"
ItemsSource="{Binding CheckItems}"
SelectionMode="None"
SelectionChanged="CollectionView_SelectionChanged">
<CollectionView.ItemsLayout>
<GridItemsLayout Orientation="Vertical"
Span="2" />
</CollectionView.ItemsLayout>
<CollectionView.ItemTemplate>
<DataTemplate>
<RelativeLayout x:Name="Item" HorizontalOptions="CenterAndExpand"
VerticalOptions="CenterAndExpand" HeightRequest="120">
<ImageButton x:Name="MyImageButton"
BackgroundColor="LightYellow"
Source="{Binding ContentImage}"
Command="{Binding TapCommand}"
CommandParameter="{Binding Source={x:Reference Item}, Path=BindingContext}"
RelativeLayout.YConstraint="{ConstraintExpression Type=RelativeToParent,Property=Height,Factor=.15,Constant=0}"
RelativeLayout.WidthConstraint="{ConstraintExpression Type=RelativeToParent,Property=Width,Factor=1,Constant=0}"
RelativeLayout.HeightConstraint="{ConstraintExpression Type=RelativeToParent,Property=Height,Factor=.8,Constant=0}" />
<Image x:Name="CheckImage"
Source="Tick.png"
BackgroundColor="AliceBlue"
IsVisible="{Binding IsShow}"
RelativeLayout.YConstraint="{ConstraintExpression Type=RelativeToView,ElementName=MyImageButton,Property=Y,Factor=1,Constant=5}"
RelativeLayout.XConstraint="{ConstraintExpression Type=RelativeToView,ElementName=MyImageButton,Property=X,Factor=1,Constant=150}"
RelativeLayout.WidthConstraint="{ConstraintExpression Type=RelativeToParent,Property=Width,Factor=0,Constant=40}"
RelativeLayout.HeightConstraint="{ConstraintExpression Type=RelativeToParent,Property=Height,Factor=0,Constant=40}" />
</RelativeLayout>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</StackLayout>
</ContentPage.Content>
</ContentPage>
In ContentPage , invoked the CheckModel :
public partial class PageMain : ContentPage
{
CheckModel checkModel;
public static List<CheckItem> checkItems { set; get; }
public PageMain()
{
InitializeComponent();
checkModel = new CheckModel();
BindingContext = checkModel;
checkItems = new List<CheckItem>();
}
}
The effect :
Here is the Sample .

Binding image in listview

I am relatively new to xamarin, and I am currently trying to bind images to my listview, but no matter what I try, I can't seem to get them to display.
Here is my code:
Xaml:
<ListView x:Name="memDisplayGrid" BackgroundColor="Transparent" HeightRequest="575" WidthRequest="200" ItemsSource="{Binding Members}"
RelativeLayout.XConstraint="{ConstraintExpression Type=RelativeToParent, Property=X, Factor=1, Constant=40}"
RelativeLayout.YConstraint="{ConstraintExpression Type=RelativeToParent, Property=Y, Factor=1, Constant=330}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Grid Padding="10">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Image x:Name="memAVI" Grid.Column="0" Source="{x:Binding AviSource}" Aspect="AspectFill"/>
<Label Grid.Column="1" Text="{x:Binding name}" FontAttributes="Bold" />
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Code behind:
private void InitializeMembersBlank()
{
Members = new List<Member>();
for (int i = 0; i < App.UserDB.GetSpecificUser((int)App.Current.Properties["currentUser"]).MemeberNum; i++)
{
Members.Add(new Member
{
AviSource = new Image { Source = "defaultAVI_48x48.jpg" },
systemID = i,
name = "Member " + (i + 1)
}) ;
}
}
Member.cs:
public class Member
{
public string name { get; set; }
public string pro_noun { get; set; }
public string birthday { get; set; }
public string role { get; set; }
public int systemID { get; set; } // how is this being set???
public string description { get; set; }
public Image AviSource { get; set; }
public override string ToString()
{
return "" + name + " /" + pro_noun + " /" + role + " /" + systemID;
}
}
Please note that I have tried changing AviSource to ImageSource and a String, but neither was working for me. I can get other things to display but not the image.
Any suggestions?
Thanks
try like this example
<ListView ItemsSource="{Binding Monkeys}"
HasUnevenRows="true"
ItemSelected="OnListViewItemSelected"
ItemTapped="OnListViewItemTapped">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Grid Padding="10">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Image Grid.RowSpan="2"
Source="{Binding ImageUrl}"
Aspect="AspectFill"
HeightRequest="60"
WidthRequest="60" />
<Label Grid.Column="1"
Text="{Binding Name}"
FontAttributes="Bold" />
<Label Grid.Row="1"
Grid.Column="1"
Text="{Binding Location}"
VerticalOptions="End" />
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
or you can use xamarin.forms listview image cells
TableView tableView = new TableView
{
Intent = TableIntent.Form,
Root = new TableRoot
{
new TableSection
{
new ImageCell
{
// Some differences with loading images in initial release.
ImageSource =
Device.OnPlatform(ImageSource.FromUri(new Uri("http://xamarin.com/images/index/ide-xamarin-studio.png")),
ImageSource.FromFile("ide_xamarin_studio.png"),
ImageSource.FromFile("Images/ide-xamarin-studio.png")),
Text = "This is an ImageCell",
Detail = "This is some detail text",
}
}
}
};
https://learn.microsoft.com/en-us/xamarin/xamarin-forms/user-interface/listview/customizing-cell-appearance#imagecell[enter link description here]1
and I found same question in here
xamarin form listview image binding

Parallax Work, But ListView in PARALLAX not Work - Xamarin Forms

Personally I created a PARALLAX effect in my application, but within the effect (PARALLAX) I have a LISTVIEW that shows my content! only when the effect ends, the ListView SCROLL does not work and does not load all the content!
My Code
ParallaxControl.cs
public class ParallaxControl : ScrollView
{
public ParallaxControl()
{
Scrolled += (sender, e) => Parallax();
}
public static readonly BindableProperty ParallaxViewProperty =
BindableProperty.Create(nameof(ParallaxControl), typeof(View), typeof(ParallaxControl), null);
public View ParallaxView
{
get { return (View)GetValue(ParallaxViewProperty); }
set { SetValue(ParallaxViewProperty, value); }
}
double height;
public void Parallax()
{
if (ParallaxView == null || Device.RuntimePlatform == "Windows" || Device.RuntimePlatform == "WinPhone")
return;
if (height <= 0)
height = ParallaxView.Height;
ParallaxView.IsEnabled = false;
var y = -(int)((float)ScrollY / 2.5f);
if (y < 0)
{
//Move a imagem no eixo Y em uma fração da posição Y do ScrollView.
ParallaxView.Scale = 1;
ParallaxView.TranslationY = y;
}
else if (Device.RuntimePlatform == "iOS")
{
//Calcula uma escala que iguala a altura x scroll.
double newHeight = height + (ScrollY * -1);
ParallaxView.Scale = newHeight / height;
ParallaxView.TranslationY = -(ScrollY / 2);
}
else
{
ParallaxView.Scale = 1;
ParallaxView.TranslationY = 0;
}
}
}
Menu.XAML
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:DeLivre.Controls"
xmlns:cardView="clr-namespace:DeLivre"
xmlns:local1="clr-namespace:DeLivre.Controls"
xmlns:controls="clr-namespace:ImageCircle.Forms.Plugin.Abstractions;assembly=ImageCircle.Forms.Plugin"
x:Class="DeLivre.Views.Cardapio_Menu">
<ContentPage.ToolbarItems>
<ToolbarItem Name="MenuItem1" Order="Primary" Icon="ic_Carrinho" Clicked="MenuItem1_Clicked" Text="Carrinho" Priority="0" />
</ContentPage.ToolbarItems>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="200" x:Name="Row1Header"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid RowSpacing="0" ColumnSpacing="0" x:Name="HeaderView">
<StackLayout Padding="5,5,5,0" BackgroundColor="White" Orientation="Vertical">
<SearchBar x:Name="CardapioPesquisa" Placeholder="Pesquise por um lanche!" HeightRequest="40" BackgroundColor="White" TextChanged="CardapioPesquisa_TextChanged" />
<cardView:CardView x:Name="CardEstabelecimento" BackgroundColor="White" CardViewHasShadow="True" HeightRequest="220">
<cardView:CardView.CardViewContent>
<StackLayout x:Name="Stack"
Padding="2"
HorizontalOptions="Center"
Spacing="2"
VerticalOptions="Center">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="80"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="80"/>
</Grid.ColumnDefinitions>
<controls:CircleImage x:Name="ImagemEstab"
Grid.Column="1"
BorderColor="#EF5350"
BorderThickness="2"
Margin="1,0,1,0"
WidthRequest="100"
HeightRequest="100"
Aspect="AspectFit"/>
<Label x:Name="lblEntrega"
Grid.Column="0"
Text="ENTREGA"
TextColor="{StaticResource asphaltPrimary}"
FontSize="16" FontAttributes="Bold"/>
<Label x:Name="EstabLocal"
Grid.Column="0"
Margin="0,20"
TextColor="{StaticResource asphaltPrimary}"
FontSize="13"/>
<Label x:Name="EstabEntrega"
Grid.Column="0"
TextColor="{StaticResource asphaltPrimary}"
Margin="-15,35,0,0"
FontSize="13"
HorizontalTextAlignment="End"/>
<Label x:Name="EstabFuncionamento"
TextColor="{StaticResource asphaltPrimary}"
Grid.Column="2"
FontSize="13"/>
<Label x:Name="EstabFrete"
Grid.Column="2"
TextColor="{StaticResource asphaltPrimary}"
Margin="0,15,0,0"
FontSize="13" />
</Grid>
<Label x:Name="Descricao"
Text="Teste"
HorizontalTextAlignment="Center"
TextColor="{StaticResource asphaltPrimary}"
Margin="0,15,0,0"
FontSize="13" />
</StackLayout>
</cardView:CardView.CardViewContent>
</cardView:CardView>
</StackLayout>
</Grid>
<local:ParallaxControl x:Name="MainScroll" Grid.RowSpan="2">
<Grid RowSpacing="0" ColumnSpacing="0" >
<Grid.RowDefinitions>
<RowDefinition Height="200"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<StackLayout Grid.Row="1">
<ListView x:Name="ListaCardapio"
BackgroundColor="White"
SeparatorColor="{StaticResource grayPrimary}"
VerticalOptions="FillAndExpand"
HasUnevenRows="true"
ItemSelected="ListaCardapio_ItemSelected"
ItemsSource="{Binding Cardapios}"
CachingStrategy="RecycleElement">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout >
<StackLayout Orientation="Horizontal">
<controls:CircleImage x:Name="ImagemEstab"
Grid.Column="1"
Source="{Binding Icon_Lanche}"
BorderColor="#EF5350"
BorderThickness="2"
Margin="1,0,1,0"
WidthRequest="100"
HeightRequest="100"
Aspect="AspectFit"/>
<Label x:Name="NomeLanche" Text="{Binding Tipo}"
FontSize="13"
Margin="-5,7"
TextColor="{StaticResource asphaltPrimary}" />
</StackLayout>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</Grid>
</local:ParallaxControl>
</Grid>
Menu.XAML.CS
public Cardapio_Menu()
{
InitializeComponent ();
MainScroll.ParallaxView = HeaderView;
}
The effect works, the problem is that when the effect ends, the Listview scroll does not work and does not show the rest of my data!
Please Help
What you can do is replace the Xamarin.Forms ListView with the RepeaterView
RepeaterView is a control that inherits from stacklayout and works very much like ListView but does not have its own scroll, since you already have a scroll it should work great for you.
public class RepeaterView<T> : StackLayout where T : class
{
public static readonly BindableProperty HeaderTemplateProperty = BindableProperty.Create(nameof(HeaderTemplate), typeof(DataTemplate), typeof(RepeaterView<T>), default(DataTemplate));
public static readonly BindableProperty ItemTemplateProperty = BindableProperty.Create(nameof(ItemTemplate), typeof(DataTemplate), typeof(RepeaterView<T>), default(DataTemplate));
public static readonly BindableProperty ItemsSourceProperty = BindableProperty.Create(nameof(ItemsSource), typeof(IEnumerable<T>), typeof(RepeaterView<T>), null, defaultBindingMode: BindingMode.OneWay, propertyChanged: ItemsChanged);
public RepeaterView()
{
Spacing = 0;
}
public IEnumerable<T> ItemsSource
{
get { return (IEnumerable<T>)GetValue(ItemsSourceProperty); }
set { SetValue(ItemsSourceProperty, value); }
}
public DataTemplate ItemTemplate
{
get { return (DataTemplate)GetValue(ItemTemplateProperty); }
set { SetValue(ItemTemplateProperty, value); }
}
public DataTemplate HeaderTemplate
{
get { return (DataTemplate)GetValue(HeaderTemplateProperty); }
set { SetValue(HeaderTemplateProperty, value); }
}
protected virtual View ViewFor(T item)
{
View view = null;
if (ItemTemplate != null)
{
var content = ItemTemplate.CreateContent();
view = (content is View) ? content as View : ((ViewCell)content).View;
view.BindingContext = item;
}
return view;
}
protected View HeaderView()
{
View view = null;
if (HeaderTemplate != null)
{
var content = HeaderTemplate.CreateContent();
view = (content is View) ? content as View : ((ViewCell)content).View;
view.BindingContext = this.BindingContext;
}
return view;
}
private static void ItemsChanged(BindableObject bindable, object oldValue, object newValue)
{
var control = bindable as RepeaterView<T>;
if (control == null)
return;
control.Children.Clear();
IEnumerable<T> items = (IEnumerable<T>)newValue;
if (items.Any())
{
var header = control.HeaderView();
if (header != null)
control.Children.Add(header);
foreach (var item in items)
control.Children.Add(control.ViewFor(item));
}
}
}
For better understanding of how this control works you can check the guide here
Feel free to revert if you have queries

How to get a scrollviewer's scrollable height to update in an interaction request

EDIT: I discovered that it was in fact the items presenter in my items control within the scroll viewer that wasn't updating correctly rather than the scrollviewer. I added an answer to reflect this.
I have a simple set up for a custom view interaction request. The view contains a scroll viewer but the scroll viewers scrollable height doesn't update if the items control within it has an items source update. The relevant code is below.
Confirmation model:
public class ProfileImportConfirmation : Confirmation
{
public ObservableCollection<ProfileAcceptPair> PossibleProfiles { get; set; } = new ObservableCollection<ProfileAcceptPair>();
public ObservableCollection<Profile> ConfirmedProfiles { get; set; } = new ObservableCollection<Profile>();
}
ViewModel:
public class ProfileImportPopupViewModel : BindableBase, IInteractionRequestAware
{
ProfileImportConfirmation _profileImportConfirmation;
public InteractionRequest<Confirmation> YesNoConfirmationInteractionRequest { get; }
public DelegateCommand AcceptCommand { get; set; }
public DelegateCommand CancelCommand { get; set; }
public ProfileImportPopupViewModel()
{
AcceptCommand = new DelegateCommand(Accept);
CancelCommand = new DelegateCommand(Cancel);
YesNoConfirmationInteractionRequest = new InteractionRequest<Confirmation>();
}
public INotification Notification
{
get { return _profileImportConfirmation; }
set
{
if (value is ProfileImportConfirmation confirmation)
{
_profileImportConfirmation = confirmation;
OnPropertyChanged(nameof(Notification));
}
}
}
public Action FinishInteraction { get; set; }
void Cancel()
{
_profileImportConfirmation.Confirmed = false;
FinishInteraction();
}
void Accept()
{
_profileImportConfirmation.Confirmed = true;
_profileImportConfirmation.ConfirmedProfiles.Clear();
_profileImportConfirmation.ConfirmedProfiles.AddRange(_profileImportConfirmation.PossibleProfiles.Where(p => p.Accepted).Select(p => p.Profile).ToList());
if (_profileImportConfirmation.ConfirmedProfiles.Any(p => p.IsRootProfile))
YesNoConfirmationInteractionRequest.Raise(
new Confirmation
{
Title = DisplayStrings.AreYouSureLabel,
Content = "Proceed?"
},
confirmed => FinishInteraction());
else
{
FinishInteraction();
}
}
}
View:
<UserControl
MaxHeight="500"
MinWidth="400"
d:DataContext="{d:DesignInstance Type=viewModels:ProfileImportPopupViewModel, IsDesignTimeCreatable=False}"
Loaded="ProfileImportPopup_OnLoaded">
<i:Interaction.Triggers>
<mvvm:InteractionRequestTrigger SourceObject="{Binding YesNoConfirmationInteractionRequest, Mode=OneWay}">
<mvvm:PopupWindowAction IsModal="True" CenterOverAssociatedObject="True" WindowStyle="{StaticResource PopupWindow}" WindowStartupLocation="CenterOwner">
<mvvm:PopupWindowAction.WindowContent>
<popups:YesNoConfirmationPopup />
</mvvm:PopupWindowAction.WindowContent>
</mvvm:PopupWindowAction>
</mvvm:InteractionRequestTrigger>
</i:Interaction.Triggers>
<Grid Margin="30, 0, 30, 30">
<Grid.RowDefinitions>
<RowDefinition Height="50"/>
<RowDefinition Height="50"/>
<RowDefinition Height="*"/>
<RowDefinition Height="40"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Label Grid.ColumnSpan="2" Content="{Binding Notification.Title}" HorizontalAlignment="Left" FontFamily="{StaticResource 'Brandon Grotesque Bold'}" FontSize="{StaticResource LargeFontSize}"/>
<Label Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2" Content="{Binding Notification.Content}" HorizontalAlignment="Center" VerticalContentAlignment="Center" FontFamily="{StaticResource 'Brandon Grotesque Bold'}" FontSize="{StaticResource LargeFontSize}"/>
<ScrollViewer x:Name="aoeu" Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="2" CanContentScroll="True" VerticalScrollBarVisibility="Auto">
<ItemsControl ItemsSource="{Binding Notification.PossibleProfiles}" Margin="0, 0, 30, 0">
<ItemsControl.ItemTemplate>
<DataTemplate DataType="{x:Type models:ProfileAcceptPair}">
<CheckBox Style="{StaticResource RightAlignedCheckBox}" Content="{Binding Name}" IsChecked="{Binding Accepted}" HorizontalContentAlignment="Right"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
<Button Grid.Row="3" Grid.Column="0" HorizontalAlignment="Center" Content="{x:Static resources:DisplayStrings.CancelButton}" Style="{StaticResource ModalWindowButton}" Command="{Binding CancelCommand}" Margin="0" VerticalAlignment="Center"/>
<Button Grid.Row="3" Grid.Column="1" Content="{x:Static resources:DisplayStrings.OKButton}" Style="{StaticResource ModalWindowButton}" Command="{Binding AcceptCommand}" Margin="0" VerticalAlignment="Center" HorizontalAlignment="Center"/>
</Grid>
It seems the items source is updating fine and I can see the new item element hidden below the scroll viewer but I can't scroll down to it.
How can I get the scrollable height to update?
The problem wasn't with the scroll viewer. It was the items presenter from the items control inside the scroll viewer. It wasn't updating it's height on items changing.
My solution isn't ideal but it worked. I added a loaded event handler for the user control in the code behind. I then named the items control and using that found the items presenter child and called invalidate measure.
void Popup_OnLoaded(object sender, RoutedEventArgs e)
{
var itemsPresenter = (ItemsPresenter) FindChild(MyItemsControl, typeof(ItemsPresenter));
itemsPresenter.InvalidateMeasure();
}
public DependencyObject FindChild(DependencyObject o, Type childType)
{
DependencyObject foundChild = null;
if (o != null)
{
var childrenCount = VisualTreeHelper.GetChildrenCount(o);
for (var i = 0; i < childrenCount; i++)
{
var child = VisualTreeHelper.GetChild(o, i);
if (child.GetType() != childType)
{
foundChild = FindChild(child, childType);
}
else
{
foundChild = child;
break;
}
}
}
return foundChild;
}

Categories

Resources