Hide View cell in ListView - xamarin.forms

I have a listview grouped, and everytime i touch the group header, all the items in the group hide, but for some reason the cells remain
I have tried to set a binded IsVisible property to all elements in the ViewCell, but still cant make it work
Heres my ListView xaml code:
<ListView x:Name="GroupsList"
ItemsSource="{Binding Dishes}"
IsGroupingEnabled="True"
SeparatorColor="Black"
SeparatorVisibility="Default"
HasUnevenRows="True"
GroupShortNameBinding="{Binding Key}">
<ListView.GroupHeaderTemplate>
<DataTemplate>
<ViewCell Height="50">
<StackLayout
VerticalOptions="FillAndExpand"
BackgroundColor="LightSlateGray">
<Button BackgroundColor="Transparent"
BorderColor="Transparent"
BorderWidth="0"
Text="{Binding Key}"
TextColor="White"
HorizontalOptions="StartAndExpand"
Command="{Binding BindingContext.SelectGroupHeader, Source={x:Reference DishesPage}}"
CommandParameter="{Binding Key}"
ContentLayout="Right, 300"
ImageSource="next_disclosure"></Button>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.GroupHeaderTemplate>
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<ContentView Padding="2, 5, 5, 0"
IsVisible="{Binding IsVisible}">
<Frame Padding="2"
HasShadow="False"
BackgroundColor="White">
<StackLayout Orientation="Horizontal">
<Label Margin="10"
Text="{Binding Name}"
TextColor="Black"
FontSize="Medium"
HorizontalOptions="StartAndExpand"></Label>
</StackLayout>
</Frame>
</ContentView>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Here is my ViewModel code:
private async Task SelectedGroupHeader(string item)
{
foreach(var group in Dishes)
{
if(item == group.Key)
{
foreach(var dish in group)
{
if (dish.IsVisible)
{
dish.IsVisible = false;
}
else
{
dish.IsVisible = true;
}
}
}
}
}
before hiding:
after hiding

The problem is that you are setting ContentView.IsVisible to false when you want to hide the items, but when you do that you hide the ContentView and the items remain in the list, so you still see the items, but without a ContentView (blanks)!
One way i found out you can achieve your purpose is to store somewhere the items of the tapped group and clear its content when you tap on it. When you do that the group becomes empty, and thus the items in the ListView are not visible anymore. When you tap again in the group header you add again the items to the group so that the ListView displays again your items.
The code i got working is more or less as follows:
In XAML i only removed the binding to ContentView.IsVisible:
<ListView x:Name="GroupsList"
ItemsSource="{Binding Dishes}"
IsGroupingEnabled="True"
SeparatorColor="Black"
SeparatorVisibility="Default"
HasUnevenRows="True"
GroupShortNameBinding="{Binding Key}">
<ListView.GroupHeaderTemplate>
<DataTemplate>
<ViewCell Height="50">
<StackLayout
VerticalOptions="FillAndExpand"
BackgroundColor="LightSlateGray">
<Button BackgroundColor="Transparent"
BorderColor="Transparent"
BorderWidth="0"
Text="{Binding Key}"
TextColor="White"
HorizontalOptions="StartAndExpand"
Command="{Binding BindingContext.SelectGroupHeader, Source={x:Reference DishesPage}}"
CommandParameter="{Binding Key}"
ContentLayout="Right, 300"
ImageSource="next_disclosure"></Button>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.GroupHeaderTemplate>
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<ContentView Padding="2, 5, 5, 0">
<Frame Padding="2"
HasShadow="False"
BackgroundColor="White">
<StackLayout Orientation="Horizontal">
<Label Margin="10"
Text="{Binding Name}"
TextColor="Black"
FontSize="Medium"
HorizontalOptions="StartAndExpand"></Label>
</StackLayout>
</Frame>
</ContentView>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
In your ViewModel you would have to do something like:
private async Task SelectedGroupHeader(string item)
{
foreach(var group in Dishes)
{
if(item == group.Key)
{
if(!group.IsHidden)
{
group.Clear();
group.IsHidden = true; // This is simply a flag you can set in your group class to keep track of if the group is collapsed or not
}
else
{
AddItemsToGroup(group)// Add this group all the elements that belongs to it.
group.IsHidden = false;
}
}
}
}
I hope this helps!
Note: this only works if your collection of items is an ObservableCollection, so that the ListView gets notified when the collection changes!

Related

change a listview orinentation, when the devices change orientation

I am trying to do this
When the device orientation changes to landscape layout, the list should scroll horizontally, not vertically. I know that I can use a ColectionView, but I HAVE to us a list
in the specification I have
Using the ListView Page:
When the device orientation changes to landscape layout, the list should scroll horizontally, not vertically (long-press to present the user with a "do you want to delete? dialog")
I don't know how to change the orientation of a listview
I used the synfusion list, but I think, they want me to use the Xamarin List
protected override void OnSizeAllocated(double width, double height)
{
base.OnSizeAllocated(width, height);
{
base.OnSizeAllocated(width, height);
if (width < height)
{
// portrait orientation
}
else if (height < width)
{
// landscape orientation
}
}
<ListView
x:Name="CarsList"
Grid.Row="1"
HasUnevenRows="True"
ItemsSource="{Binding Cars}"
SelectionMode="None"
SeparatorVisibility="Default">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<SwipeView>
<SwipeView.RightItems>
<SwipeItems Mode="Execute">
<SwipeItem BackgroundColor="Red"
Command="{Binding Source={x:Reference ListPage}, Path=BindingContext.DeleteCommand}"
CommandParameter="{Binding .}"
Text="Delete" />
</SwipeItems>
</SwipeView.RightItems>
<local:CarView
Padding="0,10,0,0"
xct:TouchEffect.Command="{Binding Source={x:Reference ListPage}, Path=BindingContext.PressedCommand}"
xct:TouchEffect.CommandParameter="{Binding .}"
xct:TouchEffect.LongPressCommand="{Binding Source={x:Reference ListPage}, Path=BindingContext.LongPressedCommand}"
xct:TouchEffect.LongPressCommandParameter="{Binding .}" />
</SwipeView>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</ContentPage.Content> <ListView
x:Name="CarsList"
Grid.Row="1"
HasUnevenRows="True"
ItemsSource="{Binding Cars}"
SelectionMode="None"
SeparatorVisibility="Default">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<SwipeView>
<SwipeView.RightItems>
<SwipeItems Mode="Execute">
<SwipeItem BackgroundColor="Red"
Command="{Binding Source={x:Reference ListPage}, Path=BindingContext.DeleteCommand}"
CommandParameter="{Binding .}"
Text="Delete" />
</SwipeItems>
</SwipeView.RightItems>
<local:CarView
Padding="0,10,0,0"
xct:TouchEffect.Command="{Binding Source={x:Reference ListPage}, Path=BindingContext.PressedCommand}"
xct:TouchEffect.CommandParameter="{Binding .}"
xct:TouchEffect.LongPressCommand="{Binding Source={x:Reference ListPage}, Path=BindingContext.LongPressedCommand}"
xct:TouchEffect.LongPressCommandParameter="{Binding .}" />
</SwipeView>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</ContentPage.Content>v
I cannot find anything related to making a horizontal listview, and I don't think is possible

How to display nested DataTemplate data in Xamarin

I have a post here. Everything works fine when I use CollectionView to Group data. However I want to display the Data Group without using the CollectionView. Specifically I use BindableLayout.ItemsSource in StackLayout.
I thought of nesting
PageOne.xaml
<StackLayout x:Name="stdata">
<BindableLayout.ItemTemplate>
<DataTemplate>
<StackLayout>
<Label Text="{Binding SupplierName}"/>
<StackLayout BindableLayout.ItemsSource="{Binding BindingContext.SupplierList, Source={x:Reference stdata}}">
<BindableLayout.ItemTemplate>
<DataTemplate>
<Label Text="{Binding NameProduct}"/>
</DataTemplate>
</BindableLayout.ItemTemplate>
</StackLayout>
</StackLayout>
</DataTemplate>
</BindableLayout.ItemTemplate>
</StackLayout>
PageOne.xaml.cs
var getcart = JsonConvert.DeserializeObject<List<CartUser>>(mycart);
cartUsers = getcart;
foreach (var item in cartUsers)
{
if (!SupplierList.Any(supplierid => supplierid.SupplierName == item.SupplierName))
{
SupplierList.Add(new SupplierIDGrouping(item.SupplierName, item.SupplierID, item.IsVisibleShippingBrand, item.NameShippingBrand));
}
SupplierList.Single(supplierid => supplierid.SupplierName == item.SupplierName).Add(item);
}
BindableLayout.SetItemsSource(stdata, SupplierList);
The data I received
UI display data
It shows a list of 2 SupplierName. However the product list it does not display.
Am I wrong about binding {Binding BindingContext.SupplierList, Source={x:Reference stdata}}. Hoping for any help. Thank you

Xamarin CollectionView - Scroll Programatically

I have collection view . See below code
<CollectionView ItemsSource="{Binding photos}" HeightRequest="300"
ItemSizingStrategy="MeasureAllItems" Margin="10,0,10,0"
x:Name="photosView"
ItemsUpdatingScrollMode="KeepScrollOffset">
<CollectionView.ItemsLayout>
<GridItemsLayout Orientation="Vertical" Span="3" />
</CollectionView.ItemsLayout>
<CollectionView.ItemTemplate>
<DataTemplate>
<StackLayout Padding="2">
<Frame BackgroundColor="Red" HeightRequest="79" WidthRequest="53" Padding="0" Margin="0"
IsClippedToBounds="True" HasShadow="False" CornerRadius="10">
<Image Aspect="AspectFill" Source="{Binding imageUrl}"/>
</Frame>
</StackLayout>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
I am showing 3 rows and 3 columns of the images. If I have more than 9 images then I am showing Button which says Scroll for more photos. Now On click on the imageI have below code
void OnScrollMore(System.Object sender, System.EventArgs e)
{
//photosView.SendScrolled(new ItemsViewScrolledEventArgs() { FirstVisibleItemIndex = 0 });
photosView.ScrollTo(photosView.Y + 10, position: ScrollToPosition.MakeVisible, animate: true);
}
But nothing is happening . It is not getting scrolled to next row.
Any suggestions?
The reason your ScrollTo method is not working is because the photosView can't find the item 'photosView.Y + 10' in your photosView itemssource. The method you're invoking is trying to find an item in the ItemsSource. It is not scrolling to a y-position like you're trying to do. You can see it in the description of the method when going to the definition. It is waiting for an 'object item'.
public void ScrollTo(object item, object group = null, ScrollToPosition position = ScrollToPosition.MakeVisible, bool animate = true);
If what you're trying to do is scroll to the last added item of the collectionview, then try this working approach and build it up from there. Here everytime you press the button, an item (string) gets added. This item is set as the ScrollTo object at the end of the button click handler.
MainPage.xaml
<StackLayout Orientation="Vertical">
<CollectionView ItemsSource="{Binding photos}" HeightRequest="300"
ItemSizingStrategy="MeasureAllItems" Margin="10,0,10,0"
x:Name="photosView"
ItemsUpdatingScrollMode="KeepLastItemInView">
<CollectionView.ItemsLayout>
<GridItemsLayout Orientation="Vertical" Span="3" />
</CollectionView.ItemsLayout>
<CollectionView.ItemTemplate>
<DataTemplate>
<StackLayout Padding="2">
<Frame BackgroundColor="Red" HeightRequest="79" WidthRequest="53" Padding="0" Margin="0"
IsClippedToBounds="True" HasShadow="False" CornerRadius="10">
<Label Text="{Binding}" TextColor="White"
HorizontalOptions="Center" VerticalOptions="Center"
HorizontalTextAlignment="Center" VerticalTextAlignment="Center"/>
</Frame>
</StackLayout>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
<Button Text="scroll more" HorizontalOptions="Center" VerticalOptions="End" Clicked="OnScrollMore"/>
</StackLayout>
MainPage.xaml.cs
public partial class MainPage : ContentPage
{
ObservableCollection<string> ObservableItems { get; set; }
public MainPage()
{
InitializeComponent();
ObservableItems = new ObservableCollection<string>(new List<string>() { "een", "twee", "drie" });
photosView.ItemsSource = ObservableItems;
}
void OnScrollMore(System.Object sender, System.EventArgs e)
{
var item = (ObservableItems.Count + 1).ToString();
ObservableItems.Add(item);
photosView.ScrollTo(item, position: ScrollToPosition.MakeVisible, animate: true);
}
}
Resulting in:

Xamarin Switch Toggled event : get bound item of list

Latest Xamarin on Mac as of writing:
<ContentPage.Content>
<StackLayout>
<ListView x:Name="ItemsListView" ItemsSource="{Binding Items}" VerticalOptions="FillAndExpand" HasUnevenRows="true" RefreshCommand="{Binding LoadItemsCommand}" IsPullToRefreshEnabled="true" IsRefreshing="{Binding IsBusy, Mode=OneWay}" CachingStrategy="RecycleElement" ItemSelected="OnItemSelected">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Orientation="Horizontal">
<StackLayout Padding="10">
<Label Text="{Binding Summary}" LineBreakMode="NoWrap" Style="{DynamicResource ListItemTextStyle}" FontSize="Medium" />
<Label Text="{Binding Reporter}" LineBreakMode="NoWrap" Style="{DynamicResource ListItemDetailTextStyle}" FontSize="Micro" />
</StackLayout>
<StackLayout Orientation="Horizontal" HorizontalOptions="EndAndExpand">
<Label Text="{Binding Start}" FontSize="Medium" VerticalOptions="Center"/>
<Switch IsToggled="{Binding Result}" Toggled="Handle_Toggled" VerticalOptions="Center"/>
</StackLayout>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</ContentPage.Content>
How do I get the bound item to a Switch control in a ListView. The item is in the list of items bound to the ListView, provided by the ViewModel. You can 'switch' the item's toggle without selecting the row.
void Handle_Toggled(object sender, Xamarin.Forms.ToggledEventArgs e)
{
// In this event handler, how do I get the bound item from the ListView??
}
Normally, what you'd need to do, is to react to the changes of property "Result" in your item class, and keep your logic out of the Page class.
If you need to handle in the event, you can do it this way:
void Handle_Toggled(object sender, Xamarin.Forms.ToggledEventArgs e)
{
var switch = sender as Switch;
var item = switch.Parent.BindingContext as ItemViewModel;
}
Replace ItemViewModel by your item's type.

How to implement an ItemTemplate within a ListView using XAML

How do I implement an ItemTemplate within a ListView using XAML?
If I do not use ItemTemplate, then my binding works and I receive no errors.
However, I want to format my list view.
As a result, I am attempting to use ItemTemplate but continue to hit a runtime exception:
Xamarin.Forms.Xaml.XamlParseException: Position 30:30. Cannot assign property "View": type mismatch between "Xamarin.Forms.TextCell" and "X…
I receive a runtime exception with the following XAML:
<ListView Grid.Row="1" Grid.Column="0" ItemsSource="{Binding Services}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<ViewCell.View>
<TextCell Text="{Binding Name}" Detail="{Binding Description}" />
</ViewCell.View>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Any suggestions?
ViewCell is a class which you can use to create custom cells layouts
TextCell is a predefined cell with predefined layout.
You cannot use a Cell inside another Cell (eg. TextCell in a ViewCell).
You can create a custom cell like this:
<ListView Grid.Row="1" Grid.Column="0" ItemsSource="{Binding Services}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<ViewCell.View>
<StackLayout Orientation="Vertical">
<Label Text="{Binding Name}" />
<Label Text="{Binding Description}" />
</StackLayout>
</ViewCell.View>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
OR use a predefined one:
<ListView Grid.Row="1" Grid.Column="0" ItemsSource="{Binding Services}">
<ListView.ItemTemplate>
<DataTemplate>
<TextCell Text="{Binding Name}" Detail="{Binding Description}" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
A list of predefined cells is here: http://developer.xamarin.com/guides/cross-platform/xamarin-forms/controls/cells/

Resources