Xamarin Forms 2.5
I have a ListView with a custom GroupHeaderTemplate that renders nicely:
<ListView.GroupHeaderTemplate>
<DataTemplate>
<ViewCell>
<templates:SummaryCellHeader />
</ViewCell>
</DataTemplate>
</ListView.GroupHeaderTemplate>
The GroupHeaderTemplate has a Grid with a TapGestureRecognizer.
<Grid>
<Grid.GestureRecognizers>
<TapGestureRecognizer Command="{Binding ListHeaderTappedCommand}" />
</Grid.GestureRecognizers>
</Grid>
The TapGestureRecognizer never fires. This template works if used outside a ListViewHeader.
Are TapGestureRecognizers allowed in a ListView GroupHeaderTemplate?
The issue is the binding context for the header is the data the list is showing, not the view model.
Give your list view a name then use that to change the binding context source for the command.
<ListView ItemsSource="{Binding ListOfPeople}"
IsGroupingEnabled="true"
x:Name="PersonList">
<Grid.GestureRecognizers>
<TapGestureRecognizer Command="{Binding Source={x:Reference PersonList}, BindingContext.ListHeaderTappedCommand}" />
</Grid.GestureRecognizers>
Thank you Steve Chadbourne. Seems you can also put a Command on the Key if the Key is a complex object rather than a simple string:
<Grid RowSpacing="0" >
<Grid.GestureRecognizers>
<TapGestureRecognizer Command="{Binding Key.ListHeaderTappedCommand}" />
</Grid.GestureRecognizers>
The benefit is that you get a reference to the Header POCO used to create the list. This is helpful to determine the action to take onHeaderClick
Related
I have a list view in my xamarin app and I need to put an option that when the list is empty, in the collection view we have <CollectionView.EmptyView> but when I search for list view there is no option for it and it's more complex, so, there is a quick fix or not? and what is the there standard solution for it ?
Actually,CollectionView is a better choice for empty view.However, if you insist on using listivew to achieve empty view effect,you could use this package Syncfusion.Xamarin.SfListView.Just binding IsVisible property when the listview is empty like below,for more details please refer to this repo.
<Grid>
<Button x:Name="ItemSource" Grid.Row="0"
Text="Change ItemSource"
HorizontalOptions="CenterAndExpand"
VerticalOptions="CenterAndExpand"
Command="{Binding ChangeItemsSource}"/>
<Grid IsVisible="{Binding IsVisible}" Grid.Row="1">
<Label x:Name="label"
Text = "No Items :(" />
</Grid>
<sync:SfListView x:Name="listView" Grid.Row="1"
ItemsSource="{Binding ContactsInfo}"
IsVisible="{Binding Path=IsVisible, Converter={StaticResource visibilityConverter}}"
ItemSize="30">
<sync:SfListView.ItemTemplate>
<DataTemplate>
<Label Text="{Binding ContactName}"/>
</DataTemplate>
</sync:SfListView.ItemTemplate>
</sync:SfListView>
</Grid>
Official reference link:https://learn.microsoft.com/en-us/xamarin/xamarin-forms/user-interface/collectionview/emptyview
the question might be quite confusing so I will try to clarify it, so basically I have one CollectionView inside another CollectionView, and I want to bind properties of views contained in the second CollectionView to properties of the individual object displayed by the dataTemplate of the first collectionView.
I can bind the ItemsSource of the second CollectionView to the same ObservableCollection that is binded to the first collectionView, that would give me access to the properties of each object contained in the mentioned ObservableCollection, but what I want is each dataTemplate of the second CollectionView to be binded ONLY to the object displayed by the DataTemplate of the first CollectionView in which the second CollectionView is displayed.
I hope I was able to explain it correctly.
XAML Code:
<ContentPage.Resources>
<ResourceDictionary>
<selectors:FirstSelector x:Key="First"/>
<selectors:SecondSelector x:Key="Second"/>
</ResourceDictionary>
</ContentPage.Resources>
<renderers:GradientLayout
ColorsList="#FFFFFF,#FFFFFF"
Mode="ToBottomLeft"
Padding="10,50,10,0">
<ScrollView>
<StackLayout>
<CollectionView
ItemsSource="{Binding FirstList}"
ItemTemplate="{StaticResource First}"
VerticalOptions="FillAndExpand"
HorizontalOptions="FillAndExpand"
Margin="0,0,0,15">
<CollectionView.ItemsLayout>
<LinearItemsLayout
Orientation="Vertical"
ItemSpacing="15"/>
</CollectionView.ItemsLayout>
<CollectionView.Resources>
<DataTemplate x:Key="Normal">
<Grid
HeightRequest="400"
HorizontalOptions="FillAndExpand"
ColumnDefinitions="20*,30*,25*,25*"
RowDefinitions="15*,70*,15*">
<Frame
Padding="0"
HasShadow="False"
BackgroundColor="Pink"
CornerRadius="30"
IsClippedToBounds="True"
Grid.Column="0"
Grid.Row="1"
Grid.ColumnSpan="4">
<CollectionView
ItemTemplate="{StaticResource Second}"
ItemsSource="{Binding Source={x:Reference home},Path=BindingContext.FirstList}"
BackgroundColor="Blue"
VerticalOptions="FillAndExpand"
HorizontalOptions="FillAndExpand">
<CollectionView.ItemsLayout>
<LinearItemsLayout
Orientation="Horizontal"
ItemSpacing="0">
</LinearItemsLayout>
</CollectionView.ItemsLayout>
<CollectionView.Resources>
<DataTemplate x:Key="NormalTwo">
<Grid
WidthRequest="392"
BackgroundColor="Orange"
ColumnDefinitions="100*"
RowDefinitions="100*"
VerticalOptions="FillAndExpand"
HorizontalOptions="FillAndExpand"
Padding="0">
<Frame
BackgroundColor="Purple"
HasShadow="False"
CornerRadius="20"
Padding="0"
Grid.Column="0"
Grid.Row="0">
<Image
Margin="-2,0,0,0"
Source="source.jpg"
Aspect="AspectFill"
HeightRequest="200">
</Image>
</Frame>
</Grid>
</DataTemplate>
</CollectionView.Resources>
</CollectionView>
</Frame>
</Grid>
</DataTemplate>
</CollectionView.Resources>
</CollectionView>
</StackLayout>
</ScrollView>
</renderers:GradientLayout>
The previous code shows a vertical collectionView with FirstList as the ItemsSource,and with a collectionView contained in it. This second CollectionView has FirstList as the ItemsSource, so it shows a horizontal list as long as the first CollectionView, and this is the problem, I just want it to access to the object of the DataTemplate in which is contained.
That is all, if you need more information I will provide it as soon as I see your request, thank you all so much for your time, have a good day.
it shows a horizontal list as long as the first CollectionView, and
this is the problem, I just want it to access to the object of the
DataTemplate in which is contained.
To solve this problem, I think your second CollectionView's itemSource should not bind to the ObservableCollection FirstList.
If they bind to the same itemsSoure, they definitely has the same length.
I want to bind properties of views contained in the second
CollectionView to properties of the individual object displayed by the
dataTemplate of the first collectionView.
Then there probably should have another ObservableCollection in the BindContext which contains individual object displayed by the dataTemplate of the first collectionView. The second collectionView should bind to this ObservableCollection.
I have a listview. This list view has 5 rows with two buttons namely A & B. When I tap on button A on a row, I want to change the image on A as well as B on the same row and vice-versa. I am able to individually tap and change the image on the same button but don't know how to change the image on the other button. Here is my listview:
<ListView x:Name="GroupedView" SeparatorColor="Transparent" GroupDisplayBinding="{Binding Title}" IsGroupingEnabled="true" HasUnevenRows="true" >
<ListView.GroupHeaderTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Orientation="Horizontal" Padding="5" BackgroundColor="#E2F5F9">
<Label Text="{Binding Title}" TextColor="{StaticResource NavyBlue}" />
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.GroupHeaderTemplate>
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Orientation="Horizontal" Spacing="2" Padding="5">
<StackLayout VerticalOptions="FillAndExpand">
<Label Text="{Binding QuestionName}" />
</StackLayout>
<StackLayout IsVisible="{Binding ShowYesNo}" Spacing="15" Orientation="Horizontal" HorizontalOptions="End">
<Button ClassId="Yes" Clicked="ChoiceSelected" CommandParameter="{Binding question_id}" Image="{Binding YesChoiceImg}" />
<Button ClassId="No" Clicked="ChoiceSelected" CommandParameter="{Binding question_id}" Image="{Binding NoChoiceImg}" />
</StackLayout>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
I am then using the sender to identify the class ID and change the image of the button.
Should I be using a command? Should I be doing something else? Please help. Thanks
If you want to use the CommandParameter you should be using a Command. At the moment you're mixing 2 different ways to handle the click.
One thing to note though is that if you use a command you usually want to bind it to a Command that is defined on your ViewModel but since inside the DataTemplate your BindingContext is the ListView item instead of the ViewModel so you have to reference around that. Something like this should work:
<DataTemplate>
<ViewCell>
<StackLayout Orientation="Horizontal" Spacing="2" Padding="5">
<StackLayout VerticalOptions="FillAndExpand">
<Label Text="{Binding QuestionName}" />
</StackLayout>
<StackLayout IsVisible="{Binding ShowYesNo}" Spacing="15" Orientation="Horizontal" HorizontalOptions="End">
<Button ClassId="Yes" Command="{Binding Path=BindingContext.ButtonCommand, Source={x:Reference MyQuestionPage}}" CommandParameter="{Binding .} Image="{Binding YesChoiceImg}" />
<Button ClassId="No" Clicked="ChoiceSelected" CommandParameter="{Binding question_id}" Image="{Binding NoChoiceImg}" />
</StackLayout>
</StackLayout>
</ViewCell>
</DataTemplate>
Note here that you have to give your ContentPage an x:Name (so you can reference it and call the BindingContext on it). And the "{Binding .}" binds to the current list item. So no need to search for it on id you can just plug it into the command directly!
I'm attempting to data bind a list of information to a ListView in Xamarin.forms, but I'm having issues because of how it is indexed. I need to get the string of information found in sortedList[0].Info[multiple indexes].CoverLink to display on my Image element inside of my Xamarin app, but I'm not sure how to go about it. My Xaml file is as follows:
<ListView RowHeight="100" x:Name="PinnedListView">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Orientation="Horizontal" HorizontalOptions="Start">
<Image Source="{Binding CoverLink}" HeightRequest="100"/>
<StackLayout Orientation="Vertical">
<Label Text="{Binding ID}"/>
<Label Text="{Binding SomeOtherBinding}"/>
</StackLayout>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
and I'm assigning the ItemSource via c# by stating:
PinnedListView.ItemsSource = sortedList;
Here is a screenshot of my list architecture:
How to data bind it? Thanks.
you need to specify which element of the Info array you want to use
<Image Source="{Binding Info[0].CoverLink}" HeightRequest="100"/>
As you can see, the CoverLink is in the Infonested array, so, in order to access to it try this:
<Image Source="{Binding Info[0].CoverLink}" HeightRequest="100"/>
I would like to add a command to my listview. When an item is clicked I would like to execute my relayCommand.
Now I have these solution, it works, but I think it is not so MVVM :)
<ListView ItemsSource="{Binding Taxons}" IsItemClickEnabled="True" ItemClick="ListViewBase_OnItemClick">
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}"/>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Code Behind:
private void ListViewBase_OnItemClick(object sender, ItemClickEventArgs e)
{
viewModel.TreeItemSelected.Execute(((Taxon)e.ClickedItem).Name);
}
I would like to use this way without any code behind, but it is not possible as the VS tells me:
<ListView ItemsSource="{Binding Taxons}" IsItemClickEnabled="True" ItemClick="{Binding TreeItemSelected}">
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}"/>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
I use the following extra dll-s, but i dont want to install anything else if it possible.
GalaSoft.MvvmLight.Extras.Win8
GalaSoft.MvvmLight.Win8
Can you suggest a solution to me?
Here's a working example :
<ListBox x:Name="name_here"
ItemsSource="{Binding your_item_source}"
SelectedItem="{Binding your_selected_item, UpdateSourceTrigger=PropertyChanged}"
...
>
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseDoubleClick">
<Command:EventToCommand Command="{Binding your_command_here}"
CommandParameter="{Binding ElementName=name_here, Path=SelectedItem}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</ListBox>
It make use of Blend's Interaction triggers (you don't have to install blend, the dll is enough if you don't have it).
also, if you're using the CommandParameter, bind the ElementName to the name of the control (in this example it's name_here )
For those who have the same problem, I would like to say that there is another way:
You can define a TapGestureRecognizer for the ListView items and bind it to a command in your ViewModel, as I'm showing here :
<StackLayout x:Name="StackLayout1" Orientation="Vertical" HorizontalOptions="StartAndExpand" VerticalOptions="FillAndExpand">
<StackLayout.BindingContext>
<viewModels:NotificationsViewModel />
</StackLayout.BindingContext>
<ListView ItemsSource="{Binding NotificationsList}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Orientation="Vertical">
<StackLayout.GestureRecognizers> <!-- here you bind the TAP event to your ViewModel -->
<TapGestureRecognizer Command="{Binding Path=BindingContext.OnListItemTapped, Source={x:Reference StackLayout1}}"
CommandParameter="{Binding}"/>
</StackLayout.GestureRecognizers>
<RelativeLayout HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand">
<Image x:Name="IsReadImage" StyleId="IsReadImage" WidthRequest="{StaticResource OptionImageSize}"
Source='{Binding IsRead, Converter={StaticResource BooleanToValueConverter}, ConverterParameter="Resources.emailOpenIcon,Resources.emailIcon"}'
RelativeLayout.YConstraint="{ConstraintExpression Type=Constant, Constant=0}"
RelativeLayout.HeightConstraint="{ConstraintExpression Type=RelativeToParent, Property=Height, Factor=0.8, Constant=0}"></Image>
<Label Text="{Binding Title}" x:Name="TitleLabel" HorizontalTextAlignment="Start" FontAttributes='{Binding IsRead, Converter={StaticResource BooleanToValueConverter}, ConverterParameter="Bold?!"}'
RelativeLayout.XConstraint="{ConstraintExpression Type=RelativeToView, ElementName=IsReadImage, Property=Width, Constant=5}"
RelativeLayout.YConstraint="{ConstraintExpression Type=RelativeToView, ElementName=IsReadImage, Property=Y, Constant=3}" /></RelativeLayout>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
And then you can define your command in the page's ViewModel
public ICommand OnListItemTapped
{
get
{
return new Command<Notification>(item =>
{
Debug.WriteLine(item.Title + " Cliked!");
});
}
}
You can accomplish this two ways.
One would be to bind the list views SelectedItem to a property on your viewmodel. (maybe call that property SelectedTaxon), then in the property setter you could take whatever action you wish on the viewmodel.
The other way, if you are really tied to executing a command on your viewmodel. You can use the mvvmlight EventToCommand behavior.
You can find info about that via Google or at this link is a description of its use. http://adammills.wordpress.com/2011/02/14/eventtocommand-action-mvvm-glue/
I believe that you already have that behavior as part of the mvvmlight extras dll you have.