How to get the index of a clicked CollectionView element? - c#

I have elements added inside a CollectionView. Inside this CollectionView, I have an ImageButton which make visible other ImageButton. I need to get the index of the element by clicking the first ImageButton and use it in the Command of the second ImageButton. Is that possible?
My xaml:
<StackLayout>
<CollectionView ItemSource="{Binding myItemSource}">
<CollectionView.ItemTemplate>
<DataTemplate>
<ContentView>
<ImageButton x:Name="FirstImageButton" Command={Binding MakeVisibleNewButton}/>
</ContentView>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
<ImageButton x:Name="SecondImageButton" Command={Binding xxxCommand} IsVisible={Binding VisibleByFirstButton} />
</StackLayout

As Jason said,you could get the index by looking up the selected item in the ItemSource.
For example:
public class YourViewModel
{
public List<yourmodel> myItemSource{ get; set; }
public ICommand MakeVisibleNewButton{ get; set; }
public YourViewModel()
{
... //fill the myItemSource
MakeVisibleNewButton= new Command<Productor>(ImageButtonClicked);
}
private void ImageButtonClicked(yourmodel obj)
{
int index = myItemSource.IndexOf(obj); //the index is what you want to get
}
}
the xaml:
<StackLayout>
<CollectionView x:Name ="collectionview" ItemSource="{Binding myItemSource}">
<CollectionView.ItemTemplate>
<DataTemplate>
<ContentView>
<ImageButton x:Name="FirstImageButton" Command="{Binding BindingContext.MakeVisibleNewButton,Source={x:Reference collectionview}}" CommandParameter="{Binding .}"/>
</ContentView>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
<ImageButton x:Name="SecondImageButton" Command={Binding xxxCommand} IsVisible={Binding VisibleByFirstButton} />
</StackLayout

Related

How to bind CommandParameter to viewCell Label in ListView (Xamarin Forms)

I'm trying to make grouped ListView for meals and foods with Add Food button for each meal. But when Add Food command is executed I don't know to which meal should I add the food. So I thought it would be good to pass the meal name as a parameter but I don't know how.
This is the ViewModel
public class ViewModel : BaseViewModel
{
public FoodViewModel()
{
this.AddFood = new Command<string>(this.OnAddFood);
this.MealGroups = new ObservableCollection<MealGroup>();
}
public ObservableCollection<MealGroup> MealGroups { get; set; }
public ICommand AddFood { get; private set; }
private void OnAddFood(string param)
}
This is the MealGroup
public class MealGroup : ObservableCollection<Food>
{
public string MealName { get; set; }
public ObservableCollection<Food> Foods => this;
}
This is the ListView
<StackLayout x:Name="MealLayout" HorizontalOptions="FillAndExpand">
<Button x:Name="AddMealButton" Text="Add Meal" Command="{Binding AddMeal}"/>
<ListView x:Name="MealGroupsListView" ItemsSource="{Binding MealGroups}" IsGroupingEnabled="true">
<ListView.GroupHeaderTemplate>
<DataTemplate>
<ViewCell>
<StackLayout x:Name="MealInfoLayout" Orientation="Horizontal">
<Label x:Name="MealNameLbl" Text="{Binding MealName}" />
<StackLayout>
<StackLayout.BindingContext>
<local:FoodViewModel/>
</StackLayout.BindingContext>
<Button x:Name="AddFoodCommand"
Text="Add Food"
Command="{Binding AddFood}"
CommandParameter="{Binding }"/>
</StackLayout>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.GroupHeaderTemplate>
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Label x:Name="FoodNameLbl" Text="{Binding Name}" />
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
Simply pass the name of the property as the Path of your Binding:
<Button x:Name="AddFoodCommand"
Text="Add Food"
Command="{Binding AddFood}"
CommandParameter="{Binding MealName}"/>
Your AddFood command will be called with the MealName property as parameter.
There's one more better way to access whole object(not only name)
<Button x:Name="AddFoodCommand"
Text="Add Food"
Command="{Binding AddFood}"
CommandParameter="{Binding .}"
/>
Through this,CommandParameter will return whole item
Firstly, I should add a foodId on the class. It's more efficient to find the item back with such an instruction :
Mg = MealGroups.First(o => o.Id == SearchedMealGroupId);
In such case, i personnaly use the ItemTapped functionnality of the listview without button (or maybe just an image for UI Experience).
<ListView x:Name="listElement" .... ItemTapped="listElement_ItemTapped" ..../>
and in the .xmal.cs :
private void listElement_ItemTapped(object sender, ItemTappedEventArgs e)
{
int SelectedMealGroupId = ((MealGroup)e.Item).Id; // You are sure of the type of e.Item !
....
// You can call methods of the VM with :
((ViewModel)BindingContext).OnAddFood(SelectedMealGroupId); // Int parameter, not string
}

BindingContext with command and parameter binding

I have a ViewModel, from which i construct a collection of objects. I want to be able to bind my objects on my view, while at the same time being able to use my button.
Currently, my properties are correctly bound to my labels (partnerLogo, partnerText, partnerLink). Unfortunately I'm not able to use my button command to send the command parameter that I bind.
ViewModel
Public class CarouselViewModel : INotifyPropertyChanged
{
public CarouselViewModel()
{
partners = new ObservableCollection<Carousel>()
{
new Carousel(){partnerText = "Test123", partnerLogo = "Test123", partnerLink = "Test123" },
};
openWebsite = new Command<string>((key) =>
{
Device.OpenUri(new Uri(key));
});
}
public ObservableCollection<Carousel> partners
{
get;
set;
}
public ICommand openWebsite
{
private set;
get;
}
}
XAML:
<CarouselView ItemsSource="{Binding partners}">
<CarouselView.ItemsLayout>
<GridItemsLayout/>
</CarouselView.ItemsLayout>
<CarouselView.ItemTemplate>
<DataTemplate>
<Frame>
<StackLayout>
<Image Source="{Binding partnerLogo}"/>
<Label Text="{Binding partnerText}"/>
<Button Text="Read" Command="{Binding openWebsite}" CommandParameter="{Binding partnerLink}"/>
</StackLayout>
</Frame>
</DataTemplate>
</CarouselView.ItemTemplate>
</CarouselView>
How do I access my button command, while at the same time being able to send the commandparameter?
For each item in the CarouselView, the binding context will be underlying data item which is bound to ItemsSource i.e., Carousel. And for CarouselView, the binding context will be your ViewModel class if you have defined it.
To resolve the issue, set the x:Name="mycaroselview" to CarouselView in the XAML and refer it's path reference to the Button command as like below code example.
<CarouselView x:Name="MyCarousel" ItemsSource="{Binding partners}">
<CarouselView.ItemsLayout>
<GridItemsLayout/>
</CarouselView.ItemsLayout>
<CarouselView.ItemTemplate>
<DataTemplate>
<Frame>
<StackLayout>
<Image Source="{Binding partnerLogo}"/>
<Label Text="{Binding partnerText}"/>
<Button Text="Read" Command="{Binding BindingContext.openWebsite, Source={x:Reference Name=MyCarousel}}" CommandParameter="{Binding partnerLink}"/>
</StackLayout>
</Frame>
</DataTemplate>
</CarouselView.ItemTemplate>
Make sure that you must set the binding context either to ContentPage or CarouselView.
Regards,
Dinesh
What you can do is, give a x:name to the content Page that you are using:-
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:MyProject;assembly= MyProject"
x:Class="MyProject.Views.MyPage"
x:Name="ThisPage">
And then give Source to the Command. Like this. This method will call the Command that is there in the ViewModel of the Current Page. Also, you can use a Command Parameter to know which Item has Triggered the Command.
<CarouselView ItemsSource="{Binding partners}">
<CarouselView.ItemsLayout>
<GridItemsLayout/>
</CarouselView.ItemsLayout>
<CarouselView.ItemTemplate>
<DataTemplate>
<Frame>
<StackLayout>
<Image Source="{Binding partnerLogo}"/>
<Label Text="{Binding partnerText}"/>
<Button Text="Read" Command="{Binding openWebsite, Source={x:Reference Name=ThisPage}}" CommandParameter="{Binding partnerLink}"/>
</StackLayout>
</Frame>
</DataTemplate>
</CarouselView.ItemTemplate>
</CarouselView>

How to Bind a command of child class object declared in Main context ViewMOdel xamarin forms

I am having a page(MyPage) and Corresponding view Model(MypageViewModel). I have another view model called(listItemLogicVM) and its declared as observable collection in MypageViewModel.
MyPage XAML
<ListView x:Name="lstvwItemSelected" ItemsSource="{Binding
LstlistItemLogicVM}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell >
<StackLayout>
<Entry Text="{Binding RequestingQty,Mode=TwoWay}"/>
<Image Source="ArrowUp.png"><Image.GestureRecognizers>
<TapGestureRecognizer Command="{Binding QtyDecrementCommand}"/>
</Image.GestureRecognizers>
</Image>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
MypageViewModel
public class MypageViewModel
{
ObservableCollection<listItemLogicVM> lstvwItemSelected = new ObservableCollection<listItemLogicVM>()
.
-- OtherLogics
.
}
listItemLogicVM
public class listItemLogicVM
{
public Command QtyDecrementCommand { get; set; }
public int RequestingQty
{
get { return _requestingQty; }
set { _requestingQty = value; OnPropertyChanged();}
}
}
Above Binding throws error. Can anyone help me to bind the command and property of listItemLogicVM to the list view in MyPage XAML
It looks to me like your listview XAML is incorrect. Try this (note the only changes are to the x:Name and ItemsSource attribute of your ListView):
<ListView x:Name="myUniqueListName" ItemsSource="{Binding
lstvwItemSelected}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell >
<StackLayout>
<Entry Text="{Binding RequestingQty,Mode=TwoWay}"/>
<Image Source="ArrowUp.png"><Image.GestureRecognizers>
<TapGestureRecognizer Command="{Binding QtyDecrementCommand}"/>
</Image.GestureRecognizers>
</Image>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
That should call the QtyDecrementCommand on the item that is tapped in the list. This assumes that you've correctly assigned some code to that command for each item in the list.
You need to add command in your MypageViewModel and your xaml code look like :
<TapGestureRecognizer Command="{Binding Source={x:Reference lstvwItemSelected}, Path=BindingContext.QtyDecrementCommand}"/>
</Image.GestureRecognizers>

Using Tap Gestures on images within listview

I am using Prism in my Xamarin forms app, I have a ListView where each Listitem has 2 images, an edit image and delete image.
I have usedTapGesturesRecognizers on these 2 images, and binded _DelegateCommands for these TapGestureRecognizers. However these DelegateCommands do not get called.
Thanks in advance
This is my XAML code
<ListView x:Name="lstAddress" HasUnevenRows="True" SeparatorVisibility="None" ItemsSource="{Binding ListItems}" CachingStrategy="RecycleElement" >
<ListView.Behaviors>
<b:EventToCommandBehavior EventName="ItemTapped"
Command="{Binding ListItemSelectCommand}" EventArgsParameterPath="Item"/>
</ListView.Behaviors>
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Orientation="Horizontal">
<Label Text="{Binding Description}" FontSize="15" TextColor="#959595">
</Label>
<Image Source="Edit.png" HeightRequest="50" WidthRequest="50" IsVisible="{Binding ShowEdit}">
<Image.GestureRecognizers>
<TapGestureRecognizer Command ="{Binding EditAddressCommand}"></TapGestureRecognizer>
</Image.GestureRecognizers>
</Image>
<Image Source="Delete.png" ClassId="{Binding ListID}" HeightRequest="30" WidthRequest="30" IsVisible="{Binding ShowIcon}">
<Image.GestureRecognizers>
<TapGestureRecognizer Command ="{Binding DeleteAddressCommand}"></TapGestureRecognizer>
</Image.GestureRecognizers>
</Image>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
In my ViewModel:
public class AddressBookViewModel : BindableBase
{
INavigationService _navigationService;
public DelegateCommand EditAddressCommand { get; set; }
public DelegateCommand DeleteAddressCommand { get; set; }
public ObservableCollection<ListModel> ListItems {get;set;} = new ObservableCollection<ListModel>();
public DelegateCommand<ListModel> ListItemSelectCommand { get; set; }
public MyZypListsViewModel(INavigationService navigationService)
{
_navigationService = navigationService;
EditAddressCommand = new DelegateCommand(EditAddress);
DeleteAddressCommand = new DelegateCommand(DeleteAddress);
ListItemSelectCommand = new DelegateCommand<ListModel>(ListItemSelected);
}
private void EditAddress()
{
//Edit listitem
}
private void DeleteAddress()
{
//Delete listitem
}
}
For each item on your list, your BindingContext is not the same as the ListView's BindingContext. Locally your BindingContext is the item itself, this is why you can obtain the 'Description' property, for example. Xamarin is searching for an ICommand called EditAddressCommand in your item, not in your view model.
You can make a Cross Binding reference if you want... Just replace your commands at item template to this way:
Command ="{Binding BindingContext.EditAddressCommand, Source={x:Reference lstAddress}"
It may work.

not able to toggle Switch

At the moment I am programming an application based on Xamarin. My goal is to toggle the switch based on values in a table. Problem is, Xamarin is not noticing my x:Name toggle_true connected to my switch.
Here is my script in xaml:
<ListView x:Name="defineBuildingItems">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Orientation="Horizontal">
<StackLayout Orientation="Vertical">
<Label Text="{Binding defineDescription}" x:Name="Current_item"/>
</StackLayout>
<Switch BindingContext ="{Binding defineId}" HorizontalOptions="EndAndExpand"
Toggled="Handle_Toggled" x:Name="toggled_true"/>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Here is my c# code in code behind:
var currentQuestions = _define.Where(s => DefineId.Contains(s.defineId));
//Remember what building was defined like last time defineBuilding was proceeded.
foreach (DefineTable i in currentQuestions)
{
toggled_true.IsToggled = true;
}
defineBuildingItems.ItemsSource = posts;
base.OnAppearing();
}
Notice how it recognizes the x:Name defineBuildingItems. The error i get on toggled_true is: The name toggled_true does not exist in the current namespace. Is there something I am doing wrong or missing?
Access to control by name inside datatemplate not working. You must using binding. This is simply example:
Model:
public class Data
{
public bool IsToggled {get;set;}
....
}
Code behind:
public YourPage
{
BindingContext = this;
}
....
private List<Data> _items;
public List<Data> Items
{
get { return _items;}
set
{
_items = value;
OnPropertyChanged();
}
}
Your xaml:
<ListView x:Name="defineBuildingItems" ItemSources={Binding Items}>
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Orientation="Horizontal">
<StackLayout Orientation="Vertical">
<Label Text="{Binding defineDescription}" />
</StackLayout>
<Switch IsToggled ="{Binding IsToggled, Mode =TwoWay}" HorizontalOptions="EndAndExpand" />
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>

Categories

Resources