Xamarin forms listview context action doesn't work with details - xaml

I use XF listview with menu context action and viewcell selected by tap.
The context actions don't work when I implemented TapGestureReconizer.
My code is here:
<ListView x:Name="PaymentCardsListView"
CachingStrategy="RecycleElement"
ItemsSource="{Binding PaymentCardsList}"
SelectedItem="{Binding SelectedPaymentCard, Mode=TwoWay}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<ViewCell.ContextActions>
<MenuItem Command="{Binding Path=BindingContext.EditCommand, Source={x:Reference PaymentCardsListView}"
CommandParameter="{Binding .}"
Text="Edit"/>
<MenuItem Command="{Binding Path=BindingContext.DeleteCommand, Source={x:Reference PaymentCardsListView}"
CommandParameter="{Binding .}"
IsDestructive="true"
Text="Delete"/>
</ViewCell.ContextActions>
<StackLayout Orientation="Horizontal">
<StackLayout.GestureRecognizers>
<TapGestureRecognizer Command="{Binding Path=BindingContext.DetailCommand, Source={x:Reference PaymentCardsListView}"
CommandParameter="{Binding .}"/>
</StackLayout.GestureRecognizers>
<StackLayout Orientation="Vertical">
<Label Text="{Binding Name}"/>
<Label Text="{Binding Number}"/>
<StackLayout Orientation="Horizontal">
<Label Text="Expiry Date: "/>
<Label Text="{Binding ExpMonth}"/>
<Label Text="/"/>
<Label Text="{Binding ExpYear}"/>
</StackLayout>
</StackLayout>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
I need to work with context menu and stacklayout tap.
How should I implement this?
It works on iOS.
The issue is only on Android.

I found confirmed bug on bugzilla.
https://bugzilla.xamarin.com/show_bug.cgi?id=46363
I'm thinking about walkthrough.
One of them it create custom renderer for view cell for android and override LongPress for display custom menu.

Related

Carousal view with multiple items without databinding

How do I set static text as Carousal view items instead of doing data binding? Here in the below code I am trying to have Page 2 appear when the user swipes to the left. This code says The property ItemTemplate is set more than once
<StackLayout Margin="10">
<CarouselView>
<CarouselView.ItemTemplate>
<DataTemplate>
<Grid>
<Label Text="Page 1"/>
</Grid>
</DataTemplate>
</CarouselView.ItemTemplate>
<CarouselView.ItemTemplate>
<DataTemplate>
<Grid>
<Label Text="Page 2"/>
</Grid>
</DataTemplate>
</CarouselView.ItemTemplate>
</CarouselView>
</StackLayout>
If you want to set the items statically in xaml itself without data binding you can use Array markup extension of type string:
<StackLayout Margin="10">
<CarouselView>
<CarouselView.ItemsSource>
<x:Array Type="{x:Type sys:String}">
<sys:String>Page 1</sys:String>
<sys:String>Page 2</sys:String>
</x:Array>
</CarouselView.ItemsSource>
<CarouselView.ItemTemplate>
<DataTemplate>
<Grid>
<Label Text="{Binding .}" />
</Grid>
</DataTemplate>
</CarouselView.ItemTemplate>
</CarouselView>
</StackLayout>
PS: Don't forget to add the required xaml namespace:
xmlns:sys="clr-namespace:System;assembly=mscorlib"

Xamarin Forms ignore Button binding from DataType on StackLayout

I have got the following xaml code:
<StackLayout Padding="10" x:DataType="model:Light">
<StackLayout HorizontalOptions="FillAndExpand" Grid.Column="0" Grid.Row="1">
<Label Text="{Binding Name}" LineBreakMode="NoWrap" Style="{DynamicResource ListItemTextStyle}" FontSize="24" HorizontalOptions="StartAndExpand" VerticalOptions="StartAndExpand"/>
</StackLayout>
<StackLayout HorizontalOptions="FillAndExpand" Grid.Column="1" Grid.Row="1" >
<Button Text="{Binding Enabled}" Command="{Binding ToggleLight}" CommandParameter="{Binding .}" HorizontalOptions="CenterAndExpand"></Button>
</StackLayout>
</StackLayout>
How do I exclude Command="{Binding ToggleLight}" on my Button form the x:DataType="model:Light" defined on my StackLayout?
Use binding-path.
Define "x:Name" outside the StackLayout (StackLayout, Grid, ListView and etc.)
Add "x:Reference" for your Command binding inside the StackLayout
The command is excluded.
Like:
<Grid x:Name="WhateverParent">
<StackLayout x:DataType="model:Light">
<Button ... Command="{Binding Path=BindingContext.ToggleLight, Source={x:Reference WhateverParent}}" />
</StackLayout>
</Grid>

Keep ListView.Header anchored/sticky/frozen to top when scrolling

How to keep the built-in Header of a ListView frozen to the top when scrolling vertically down through the ListView items?
Before flagging as duplicate: I tried to apply answers in Keep ListView.HeaderTemplate visible/static/sticky in UWP for Xamarin.Forms targeting Android without success.
Short code sample:
<ListView ItemsSource="{Binding MyList}"
HasUnevenRows="True"
SeparatorVisibility="Default"
CachingStrategy="RecycleElement">
<ListView.Header>
<Label HorizontalTextAlignment="Center"
FontAttributes="Bold"
Text="Header Title"/>
</ListView.Header>
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Label Text="{Binding Name}"/>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Here is an alternative approach to this if the list isn't long
<StackLayout>
<Label HorizontalTextAlignment="Center"
FontAttributes="Bold"
Text="Header Title"/>
<StackLayout BindableLayout.ItemsSource="{Binding MyList}">
<BindableLayout.ItemTemplate>
<DataTemplate>
<StackLayout>
<Label Text="{Binding Name}"/>
<!-- boxview as separator -->
<BoxView HeightRequest="1" Color="Aqua" HorizontalOptions="FillAndExpand"/>
</StackLayout>
</DataTemplate>
</BindableLayout.ItemTemplate>
</StackLayout>
</StackLayout>

Get SelectedItem from a nested RepeaterView

I am using DottorPagliaccius repeater view thats nested inside another repeaterview. The command RSSFeedSelectedCommand doesnt work unless on top repeater, which in theory makes sense but how can i get it to work?
I have looked into using Converters and bindtoeventcommand but cant see to get them working.
<repeater:RepeaterView x:Name="MainRepeater" SeparatorHeight="25" ItemsSource={Binding Feeds}">
<repeater:RepeaterView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Spacing="10">
<Label Text="{Binding Title}" TextColor="Blue" />
<Label Text="{Binding Description}" TextColor="Red" FontSize="12" />
<repeater:RepeaterView x:Name="MainRepeater2" EmptyText="No elements" ShowSeparator="true" SeparatorHeight="2" SeparatorColor="Silver" ItemsSource="{Binding Items}" SelectedItemCommand="{Binding RSSFeedSelectedCommand}">
<repeater`enter code here`:RepeaterView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Orientation="Horizontal">
<Image Source="{Binding Image.Url}"></Image>
<StackLayout Orientation="Vertical">
<Label Text="{Binding Title}" TextColor="Black" />
<Label Text="{Binding Description}" TextColor="Black" FontSize="12" />
</StackLayout>
</StackLayout>
</ViewCell>
</DataTemplate>
</repeater:RepeaterView.ItemTemplate>
</repeater:RepeaterView>
</StackLayout>
</ViewCell>
</DataTemplate>
</repeater:RepeaterView.ItemTemplate>
</repeater:RepeaterView>
The Repeater was trying to find the command in Feeds however exists in the ViewModel.
<repeater:RepeaterView x:Name="MainRepeater2" EmptyText="No elements" ShowSeparator="true" SeparatorHeight="2" SeparatorColor="Silver" ItemsSource="{Binding Items}" SelectedItemCommand="{Binding Source={x:Reference RSSPage}, Path=BindingContext.RSSFeedSelectedCommand}">
and you have to name the page:
<ContentPage x:Name="PageName" />
If my assumption is correct, your class structure should be something like,
ViewModel
|__List of Feeds
|__List of Items
|__RSSFeedSelectedCommand
So, DataContext of your inner repeater control (MainRepeater2) will be Feed. So, try with DataContext of outer repeater control. Like,
<repeater:RepeaterView x:Name="MainRepeater2" ItemsSource="{Binding Items}"
SelectedItemCommand="{Binding DataContext.RSSFeedSelectedCommand,
ElementName=MainRepeater}"/>
For Xamarin:
<repeater:RepeaterView x:Name="MainRepeater2" ItemsSource="{Binding Items}"
SelectedItemCommand="{Binding DataContext.RSSFeedSelectedCommand,
Source={x:Reference MainRepeater}}"/>

Set platform specific control to only one platform in xamarin forms

I have a page that contains a listview and Search bar control. There is a custom listview for android. My code as following:
<ContentPage.Content>
<ContentView>
<OnPlatform x:TypeArguments="View">
<OnPlatform.iOS>
<StackLayout Spacing="0">
<SearchBar x:Name="IosSearch"
Placeholder="Search"
TextChanged="IosSearchBar_OnTextChanged"
SearchButtonPressed="OnSearch" BackgroundColor="#19588F">
</SearchBar>
<ListView x:Name="EmpListViewIos"
ItemsSource="{Binding EmpModel.GroupedItems}"
ItemSelected="OnItemSelected"
SeparatorVisibility="Default">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Padding="8">
<StackLayout Spacing="4" Orientation="Horizontal">
<Label Text="{Binding FullName}" FontSize="15" TextColor="Gray" LineBreakMode="NoWrap"/>
</StackLayout>
<StackLayout Spacing="4" Orientation="Horizontal">
<Label Text="{Binding Department}" FontSize="Small" TextColor="#F68933" LineBreakMode="WordWrap"/>
</StackLayout>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</OnPlatform.iOS>
<OnPlatform.Android>
<StackLayout x:Name="androidListView">
<SearchBar x:Name="DroidSearch"
Placeholder="Search"
TextChanged="DroidSearchBar_OnTextChanged"
SearchButtonPressed="OnSearch" BackgroundColor="#19588F">
</SearchBar>
<local:CustomListView x:Name="customListView"
Items="{Binding EmpModel.Items}"
VerticalOptions="FillAndExpand" MyListItemSelected="nativeListView_ItemSelected"
SeparatorColor="Black">
</local:MyListView>
</StackLayout>
</OnPlatform.Android>
<OnPlatform.WinPhone>
<StackLayout Spacing="0">
<SearchBar x:Name="WinSearch"
Placeholder="Search"
TextChanged="WinSearchBar_OnTextChanged"
SearchButtonPressed="OnSearch" BackgroundColor="#19588F">
</SearchBar>
<ListView x:Name="EmpListViewWin"
ItemsSource="{Binding EmpModel.GroupedItems}"
ItemSelected="OnItemSelected"
SeparatorVisibility="Default">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Padding="8">
<StackLayout Spacing="4" Orientation="Horizontal">
<Label Text="{Binding FullName}" FontSize="15" TextColor="Gray" LineBreakMode="NoWrap"/>
</StackLayout>
<StackLayout Spacing="4" Orientation="Horizontal">
<Label Text="{Binding Department}" FontSize="Small" TextColor="#F68933" LineBreakMode="WordWrap"/>
</StackLayout>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</OnPlatform.WinPhone>
</OnPlatform>
</ContentView>
</ContentPage.Content>
</ContentPage>
As the representation of data is different due to that I am required custom listview for android according to it's layout defined. The above code works fine. The only problem is the redundancy, the search bar control is common for all platform but when I put the search bar control above the <ContentView> it doesn't work throws exception. Similarly the ListView is common for ios and windows only there is custom listview for android but I am forced to repeat the code for windows also same as android.
Can anyone suggest a more efficient way to achieve this. How can I apply platform specific condition only for android and common for windows and ios.
You could share the iOS and WinPhone views using a static resource:
<ContentPage>
<ContentPage.ResourceDictionary>
<StackLayout x:Key="iosOrWpView">
...
</StackLayout>
</ContentPage.ResourceDictionary>
<ContentView>
<OnPlatform x:TypeArguments="View" iOS="{StaticResource iosOrWpView}"
WinPhone="{StaticResource iosOrWpView}">
<OnPlatform.Android>
<StackLayout x:Name="androidListView">
...
</StackLayout>
</OnPlatform.Android>
</OnPlatform>
</ContentView>
<ContentPage>