Xamarin Forms: handle multiple item per row - xamarin

In Xamarin Forms i want show multiple image (2) in a row: this is an example of what i'd like to do:
In many Q&A i've seen the use of XLabs gridview but the project is no longer maintained.
I think that i can create a custom cell with a stacklayout inside a row but the recycle policy work? And how can i handle the item tapped if i have two column per row?
Thanks

Alessandros answer should work, but if you want to roll something yourself without any third party controls, keep reading:
Recycling will still work if you use a Custom ViewCell. So I would suggest doing that and adding two items in a custom model and render them in one cell at a time.
Now for handling taps: Override the ItemSelected event on your ListView and set the ListView.SelectedItem to null. Then inside your custom ViewCell, add a TapGestureRecognizer to each of the separate models. One thing to note, is that the Command on your TapGestureRecognizer will bind to your individual list item, so you need to set it relative to the BindingContext of the ListView:
<ListView x:Name="MyListView" ...>
<ListView.ItemTemplate>
<DataTemplate>
<StackLayout Orientation="Horizontal>
<Image ...>
<Image.GestureRecognizers>
<TapGestureRecognizer Command="{Binding Source={x:Reference MyListView}, Path=BindingContext.Item1Command}"/>
</Image.GestureRecognizers>
</Image>
<Image ...>
<Image.GestureRecognizers>
<TapGestureRecognizer Command="{Binding Source={x:Reference MyListView}, Path=BindingContext.Item2Command}"/>
</Image.GestureRecognizers
</Image>
</StackLayout>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>

You can take a look to this FlowListView.
I have never used it but sounds good.
<flv:FlowListView.FlowColumnTemplate>
<DataTemplate>
<Label HorizontalOptions="Fill" VerticalOptions="Fill"
XAlign="Center" YAlign="Center" Text="{Binding Title}"/>
</DataTemplate>
</flv:FlowListView.FlowColumnTemplate>

Related

Object retain in memory when click on listview headertemplate in iOS device

I am developing an enterprise application using Xamarin.Forms. I am facing a memory leak issue in iOS specifically (working fine in Android).
Its regarding click over listview item header, I implemented gestures, then a transparent button as well, but it causes a memory leak - even if I comment out its functionality.
If I comment testbutton then its objects are disposing fine. What can I do to fix this issue?
```
<ListView
Style="{DynamicResource BaseListViewStyle}"
IsGroupingEnabled="True"
ItemsSource="{Binding Deliveries.ExpandedDeliveryItemModels}"
IsPullToRefreshEnabled="True"
IsRefreshing="{Binding Deliveries.IsRefreshing}"
RefreshCommand="{Binding RefreshCommand}"
SelectionMode="None">
<ListView.GroupHeaderTemplate>
<DataTemplate>
<ViewCell AutomationId="headerCell">
<StackLayout AutomationId="headerLayout" Orientation="Horizontal">
<Label Text="{Binding HeaderTitle}"
AutomationId="DeliveriesToday"
HorizontalOptions="StartAndExpand">
</Label>
<Button x:Name="testbutton"
HorizontalOptions="End"
Command="{Binding Source={x:Reference deliveriesPage}, Path=BindingContext.HeaderClickCommand}"
CommandParameter="{Binding .}">
</Button>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.GroupHeaderTemplate>
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell AutomationId="deliveriesCell">
<Label Text="Testing"></Label>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
```
Welcome to SO !
You can have a try with modifying CachingStrategy of ListView , there are three types of CachingStrategy value.
RecycleElement 1 Indicates that unneeded cells will have their binding contexts updated to that of a cell that is needed.
RecycleElementAndDataTemplate 3 Indicates that, in addition to the behavior specified by RecycleElement, DataTemplate objects that are selected by a DataTemplateSelector are cached by the data template type.
RetainElement 0 Indicates that for every item in the List View's ItemsSource property, a single unique element will be constructed from the DataTemplate.
The deflault value is RetainElement, the behavior is to retain item data in their generated cells when they are not needed.
For performance reasons, it is likely that the default behavior will be changed to RecycleElement in a future release. In the meantime, for memory and performance reasons, app developers should specify RecycleElement when constructing a new List View.
Therefore , you can modify code as follow :
<ListView CachingStrategy="RecycleElement" >
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<!-- ... -->
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>

Placing a ListView together with a VideoView add several blank lines between them

I created a page in Xamarin.Forms that should display some items, coming from an IList data source, and a video after them.
List of items will be displayed using ListView. The video is displayed using VideoView.
This is the actual page code:
<?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:mm="clr-namespace:Plugin.MediaManager.Forms;assembly=Plugin.MediaManager.Forms"
x:Class="MyApp.Views.ItemDetailPage"
Title="{Binding Title}">
<ScrollView>
<StackLayout Orientation="Vertical" Padding="15">
<ListView
ItemsSource="{Binding Item.Properties}"
HasUnevenRows="true">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Padding="10">
<Label Text="{Binding .}"
LineBreakMode="NoWrap"
Style="{DynamicResource ListItemTextStyle}"
FontSize="16" />
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<mm:VideoView x:Name="MyVideo" WidthRequest="320" HeightRequest="190" HorizontalOptions="FillAndExpand" />
<Button x:Name="BtnPlayStop" Text="Iniciar" Clicked="PlayStop_Clicked" BackgroundColor="Silver" TextColor="White"/>
</StackLayout>
</ScrollView>
</ContentPage>
The problems I have when I run the app are:
The page initially appears scrolled down so that the video is initially seen.
The space between the last element of the list view and the video is very big
It´s difficult to do the scroll up or down by using the finger.
Is my XAML code correct? what changes can I apply to fix this weird behaviour?
EDIT: I have found that between the listview and video is nothing. That is why it is difficult to scroll. If I place the finger inside the list view, I can scroll, the same if I place the finger inside the video or button. But if I place the finger between the list view and the video no scroll is performed. Weird, isn't it?
Thanks
Jaime
Finally, I have used solution in this page: https://xamarinsharp.com/2017/05/16/listview-height-issue-in-xamarin-forms-how-to-solve-it/
Basicly, it is to set the HeightRequest of the ListView in code behind according to the number of bound elements.
Regards
Jaime

Is there any reason to specify a x:Name in a Xamarin Forms XAML page?

I have XAML code that looks like this;
<?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:local="clr-namespace:Japanese;assembly=Japanese"
x:Class="Japanese.GettingStarted"
x:Name="gettingStarted"
Title="Getting Started">
<ContentPage.Content>
My C#
using System;
using System.Collections.Generic;
using Xamarin.Forms;
namespace Japanese
{
public partial class GettingStarted : ContentPage
{
public GettingStarted()
{
The code works fine but I would like to know if there is any advantage or if it is normal to specify x:Name in the XAML?
Yes, there are reasons. But if you haven't found them yet, you probably don't need it right now.
The most obvious reason is if you need to refer to it from your XAML. For example, you are working with data-binding and use a ListView. On the ListView, you use a simple TextCell which has context actions. The XAML could look like this (taken from here and tweaked a bit):
<ListView ItemsSource="{Binding YourItems}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<ViewCell.ContextActions>
<MenuItem Command="{Binding DeleteCommand}" CommandParameter="{Binding .}" Text="Delete" IsDestructive="True" />
</ViewCell.ContextActions>
<StackLayout Padding="15,0">
<Label Text="{Binding title}" />
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Now, if you have worked with data-binding before, you will know that the bindings of the MenuItems in there are bound to each instance of the object that is in the YourItems collection.
But, it doesn't make sense to implement a delete command on an instance in that collection. You would want that on your view model. To do this, you will have to give your page a name, and refer to the command like this: <MenuItem Command="{Binding Source={x:Reference MyPage}, Path=BindingContext.DeleteCommand}" CommandParameter="{Binding .}" Text="Delete" IsDestructive="True" /> where MyPage would be the value you put in the x:Name attribute.
Other examples are probably out there, but this is a prominent one. If you do not have to refer to the page in any way, giving it a name add no real value.

List of ContentViews in a CarouselView with PullToRefresh

I have a list of two ContentViews that have the PullToRefreshLayout plugin within them surrounding ScrollViews. I'm not sure what's going on, but when you pull to refresh, the refresh circle appears but the Refresh Command never gets hit nor does the refresh circle ever finish.
Here is my CarouselView
<cv:CarouselView
Margin="0, 0, 0, 0"
ItemsSource="{Binding ContentViews}"
Position="{Binding CarouselPosition}"
x:Name="ContentCarousel">
<cv:CarouselView.ItemTemplate>
<DataTemplate>
<ContentView Content="{Binding Content}"/>
</DataTemplate>
</cv:CarouselView.ItemTemplate>
</cv:CarouselView>
And here is an example of one of my ContentViews.
<ContentView.Content>
<controls:PullToRefreshLayout
IsPullToRefreshEnabled="True"
RefreshCommand="{Binding BindingContext.RefreshReceivingCommand, Source={x:Reference Name=ReceivingContentView}}"
IsRefreshing="{Binding IsBusy}"
RefreshColor="#4ABDAC">
<ScrollView
HorizontalOptions="FillAndExpand"
VerticalOptions="FillAndExpand"
Style="{StaticResource cardScrollViewBackgroundColor}">
<StackLayout
Padding="0,0,0,0"
VerticalOptions="StartAndExpand"
x:Name="MainStackLayout">
</StackLayout>
</ScrollView>
</controls:PullToRefreshLayout>
</ContentView.Content>
I'm honestly not sure what's going on. I have tried different binding contexts on the refresh command but the command is never hit. Any ideas is greatly appreciated!
EDIT: I sorta found a solution but not a huge fan.
I created an empty Constructor in my ViewModel that sets my Refreshing Commands. Then in the ContentView, I sent the BindingContext to the ViewModel. Seems redundant, but eh, works for now until I figure out the xaml binding.

Windows Phone 7 Linking to events inside DataTemplates

I have a listbox where I create a Itemtemplate with a DataTemplate. I want to be able to write events for the checkboxes and buttons in the datatemplate but they do not seem to be firing.
Here is my xaml and basically I just tried to display a messagebox.show("worked") in the event function.
<ListBox x:Name="ListBox_Items" Margin="0,91,0,8" Foreground="#FF4BE5DB">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" Width="700">
<CheckBox IsChecked="{Binding needPurchase}" Click="NeedPurchase_Click" Name="CheckBox_NeedPurchase"/>
<CheckBox IsChecked="False" Name="InCart"/>
<StackPanel Orientation="Vertical">
<TextBlock Text="{Binding name}"/>
<TextBlock Text="{Binding storeLocation}"/>
</StackPanel>
<Button HorizontalAlignment="Right" Content="DELETE" Click="Button_Click" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Because the items are defined within a DataTemplate they are not hooked up to the code-behind for the parent class. If you want to handle events for templated items, then you should consider using commands instead. If you don't know what commands are (and therefore unlikely to know what MVVM is), then you should check out an explanation like this by Jeremy Likness.
I agree that using commands is the best approach.
However if you still want to assess controls placed inside the ItemTemplate/DataTemplate (and subscribe to some events), then you can do this by using the VisualTreeHelper.
For starters you need to remove the name from all the controls in the template. If you have 10 items in the list you will have 10 sets of controls with the same name which won't work.

Resources