I'm trying to add items to a listview from an Entry that is in a frame of its own though the listview won't update. The entry for reference, is added to the UI using the code behind. Here's the listview:
<ListView ItemsSource="{Binding TodoListItems}" x:Name="todoList" HeightRequest="400">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<FlexLayout JustifyContent="SpaceBetween" Padding="20,0">
<ContentView>
<FlexLayout AlignItems="Center" >
<input:CheckBox IsChecked="{Binding Complete}"
CheckChangedCommand="{Binding Path=BindingContext.CompleteTodoCommand, Source={x:Reference todoList}}"
CommandParameter="{Binding .}"
/>
<Label Text="{Binding TodoText}" Padding="10,0,0,0" FontSize="Large"/>
</FlexLayout>
</ContentView>
<ImageButton Source="trash_icon.png"
Command="{Binding Path=BindingContext.RemoveTodoCommand, Source={x:Reference todoList}}"
CommandParameter="{Binding .}"
Scale="1.2" BackgroundColor="White"
/>
</FlexLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
The frame:
<Frame x:Name="bottomSheet" HasShadow="true" CornerRadius="8" Padding="1,4,1,0" BackgroundColor="DarkSlateGray"
RelativeLayout.YConstraint="{ConstraintExpression Type=RelativeToParent,Property=Height,Factor=.85,Constant=0}"
RelativeLayout.WidthConstraint="{ConstraintExpression Type=RelativeToParent,Property=Width,Factor=1,Constant=0}"
RelativeLayout.HeightConstraint="{ConstraintExpression
Type=RelativeToParent,Property=Height,Factor=1,Constant=0}"
>
<StackLayout x:Name="bottomSheetStackLayout">
<Button Text="Add new Todo" x:Name="addNewTodoButton" Clicked="AddNewTodoButton_Clicked"/>
</StackLayout>
</Frame>
The ViewModel:
public ObservableCollection<TodoItem> TodoListItems { get; set; }
public ObservableCollection<TodoItem> CompletedTodoItems { get; set; }
public TodoListViewModel()
{
TodoListItems = new ObservableCollection<TodoItem>();
TodoListItems.Add(new TodoItem("Walk the duggo", false));
TodoListItems.Add(new TodoItem("Do the washing", false));
TodoListItems.Add(new TodoItem("Brush off Cheeto dust", false));
CompletedTodoItems = new ObservableCollection<TodoItem>();
//CompletedTodoItems.Add(new TodoItem("Do the dishes",true));
}
public ICommand AddTodoCommand => new Command(AddTodoItem);
public string NewTodoInputValue { get; set; }
void AddTodoItem()
{
TodoListItems.Add(new TodoItem(NewTodoInputValue, false));
}
And the code behind:
private void AddNewTodoButton_Clicked(object sender, System.EventArgs e)
{
Entry addTodoEntryField = new Entry();
bottomSheetStackLayout.Children.Remove(addNewTodoButton);
bottomSheetStackLayout.Children.Add(addTodoEntryField);
addTodoEntryField.Completed += AddTodoEntryField_Completed;
}
private void AddTodoEntryField_Completed(object sender, EventArgs e)
{
Entry addTodoEntryField = (Entry)sender;
Console.WriteLine("The text in the entry field: "+addTodoEntryField.Text);
addTodoEntryField.BindingContext = ViewModel;
ShowTodoItemsText(ViewModel.TodoListItems);
addTodoEntryField.SetBinding(Entry.TextProperty, "NewTodoInputValue");
Console.WriteLine(value: ViewModel.NewTodoInputValue==null);
ViewModel.AddTodoCommand.Execute(null);
Console.WriteLine(ViewModel.TodoListItems.Count);
//Console.WriteLine(ViewModel.TodoListItems.Last().TodoText==null);
ViewModel.TodoListItems.Add(new TodoItem("Added manually", false));
}
Edit: To clarify, I have a frame with a button, which when clicked is replaced with an Entry, the completed text of which, I want to bind to the TodoListItems observable collection, which is displayed by the listView.
I've checked that there are objects being put into the observable collection. I'm not implementing INotifyPropertyChanged on the ViewModel yet though as the collection has that. (Also, the Entry at the top of the page does work fine.) Any help appreciated.
Related
How to use viewmodel get data and draw graphic,Can I send data from mainpageviewmodel to use on graphicviewmodel and show on graphicpage
MainPage.xaml
<CollectionView
BackgroundColor="Transparent"
ItemsSource="{Binding graphiclist}"
SelectionMode="None">
<CollectionView.ItemTemplate>
<DataTemplate x:DataType="model:GRAPHICModel">
<Grid Padding="0">
<Frame HeightRequest="100">
<Frame.GestureRecognizers>
<TapGestureRecognizer Command="{Binding Source={RelativeSource AncestorType={x:Type viewmodel:MainViewModel}}, Path=DrawGRAPHCommand}" CommandParameter="{Binding .}" />
</Frame.GestureRecognizers>
<Grid Padding="0">
<VerticalStackLayout>
<Label Style="{StaticResource BoldLabel}" Text="{Binding GraphicNamae}" />
</VerticalStackLayout>
</Grid>
</Frame>
</Grid>
</DataTemplate>
</CollectionView.ItemTemplate>
mainpageviewmodel.cs
public partial class MainpageViewModel : ObservableObject
{
public ObservableCollection<GRAPHICModel> graphiclist { get; set; }
public MainpageViewModel()
{
graphiclist = new ObservableCollection<GRAPHICModel>
{
new GRAPHICModel { GraphicName= "Name1", Path = "somecoordinate" },
new GRAPHICModel { GraphicName= "Name2", Path = "somecoordinate" },
new GRAPHICModel { GraphicName= "Name3", Path = "somecoordinate" },
new GRAPHICModel { GraphicName= "Name4", Path = "somecoordinate" }
};
}
[ICommand]
async Task DrawGRAPHCommand(GRAPHICModel glist)
{
await Shell.Current.GoToAsync(nameof(DrawPage), true, new Dictionary<string, object>
{
["GRAPHICModel"] = glist
});
}
}
graphicpage.xaml
<VerticalStackLayout>
<Label Text="{Binding Graphiclist.GraphicName}" />
<FlexLayout
AlignItems="Center"
Direction="Column"
JustifyContent="SpaceEvenly">
<VerticalStackLayout>
<GraphicsView
Drawable="{StaticResource drawable}"
HeightRequest="1000"
WidthRequest="1000" />
</VerticalStackLayout>
</FlexLayout>
</VerticalStackLayout>
graphicviewmodel.cs
[QueryProperty(nameof(Graphiclist), "GRAPHICModel")]
public partial class GraphicViewModel : ObservableObject, IDrawable
{
[ObservableProperty]
GRAPHICModel graphiclist;
public void Draw(ICanvas canvas, RectF dirtyRect)
{
something.load(graphiclist.Path)
canvas.StrokeColor = Colors.Red;
canvas.StrokeSize = 4;
canvas.DrawPath();
}
}
After tap , can not get graphiclist.path for canvas.DrawPath(-somepoint-); after tap
but can show <Label Text="{Binding Graphiclist.GraphicName}" />
In MVVM for communication between View Models common practice is to use Mediator Design Pattern !! There are a lot articles around it as much as yt videos.
I am currently making a note-taking app. I am new so excuse my lack of knowledge.
I am using the default flyout menu template given with changes made to cater for my needs. I am using a SwipeView in my CollectionView so when you swipe on a 'note' the item will delete on execute.
I have the swipe working but I cannot get the item to delete once swiped.
This is my ItemsPage.xaml
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="xamarinMobileTest.Views.ItemsPage"
Title="{Binding Title}"
xmlns:local="clr-namespace:xamarinMobileTest.ViewModels"
xmlns:model="clr-namespace:xamarinMobileTest.Models"
x:Name="BrowseItemsPage">
<ContentPage.ToolbarItems>
<ToolbarItem Text="Add Note" Command="{Binding AddItemCommand}" />
</ContentPage.ToolbarItems>
<ContentPage.BindingContext>
<local:ItemsViewModel/>
</ContentPage.BindingContext>
<RefreshView x:DataType="local:ItemsViewModel" Command="{Binding LoadItemsCommand}" IsRefreshing="{Binding IsBusy, Mode=TwoWay}">
<CollectionView x:Name="ItemsListView"
ItemsSource="{Binding Items}"
SelectionMode="None">
<CollectionView.ItemTemplate>
<DataTemplate>
<SwipeView>
<SwipeView.RightItems>
<SwipeItems Mode="Execute">
<SwipeItem Text="Delete"
BackgroundColor="Red"
Command="{Binding DeleteItemCommand}"
CommandParameter="{Binding .}"/>
</SwipeItems>
</SwipeView.RightItems>
<StackLayout Padding="10" x:DataType="model:Item">
<Label Text="{Binding Text}"
LineBreakMode="NoWrap"
Style="{DynamicResource ListItemTextStyle}"
FontSize="16"
FontAttributes="Bold"
TextColor="Black"/>
<Label Text="{Binding Description}"
LineBreakMode="NoWrap"
Style="{DynamicResource ListItemDetailTextStyle}"
FontSize="13"
TextColor="Black"/>
<Label Text="{Binding DueDate}"
Style="{DynamicResource ListItemDetailTextStyle}"
FontSize="13"
TextColor="Black"/>
<StackLayout.GestureRecognizers>
<TapGestureRecognizer
NumberOfTapsRequired="1"
Command="{Binding Source={RelativeSource AncestorType={x:Type local:ItemsViewModel}}, Path=ItemTapped}"
CommandParameter="{Binding .}">
</TapGestureRecognizer>
</StackLayout.GestureRecognizers>
</StackLayout>
</SwipeView>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</RefreshView>
</ContentPage>
ItemsViewModel:
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using Xamarin.Forms;
using xamarinMobileTest.Models;
using xamarinMobileTest.Views;
namespace xamarinMobileTest.ViewModels
{
public class ItemsViewModel : BaseViewModel
{
private Item _selectedItem;
public ObservableCollection<Item> Items { get; }
public Command LoadItemsCommand { get; }
public Command AddItemCommand { get; }
public Command<Item> ItemTapped { get; }
public Command<Item> DeleteItemCommand { get; }
public ItemsViewModel()
{
Title = "Notes";
Items = new ObservableCollection<Item>();
LoadItemsCommand = new Command(async () => await ExecuteLoadItemsCommand());
ItemTapped = new Command<Item>(OnItemSelected);
AddItemCommand = new Command(OnAddItem);
DeleteItemCommand = new Command<Item>(OnDeleteItem);
}
async Task ExecuteLoadItemsCommand()
{
IsBusy = true;
try
{
Items.Clear();
var items = await DataStore.GetItemsAsync(true);
foreach (var item in items)
{
Items.Add(item);
}
}
catch (Exception ex)
{
Debug.WriteLine(ex);
}
finally
{
IsBusy = false;
}
}
public void OnAppearing()
{
IsBusy = true;
SelectedItem = null;
}
public Item SelectedItem
{
get => _selectedItem;
set
{
SetProperty(ref _selectedItem, value);
OnItemSelected(value);
}
}
private async void OnAddItem(object obj)
{
await Shell.Current.GoToAsync(nameof(NewItemPage));
}
async void OnItemSelected(Item item)
{
if (item == null)
return;
// This will push the ItemDetailPage onto the navigation stack
await Shell.Current.GoToAsync($"{nameof(ItemDetailPage)}?{nameof(ItemDetailViewModel.ItemId)}={item.Id}");
}
private void OnDeleteItem(Item item)
{
Items.Remove(item);
}
}
}
*Other code needed can be found by opening up default flyout menu template
How do I delete an Item on a swipe in the observable collection so that when I delete the Item it automatically is seen that the item is deleted?
Items.Remove(item); does not seem to work (no error, just does not remove the item from the CollectionView) Why is this?
await DataStore.DeleteItemAsync(item); has the same issue of nothing happening when the item is swiped.
Any help is appreciated.
Change your parameter to this
CommandParameter="{Binding Source={RelativeSource Self}, Path=BindingContext}"
the code you have in OnDeleteItem is nonsensical. It should look something like this
private void OnDeleteItem(Item item)
{
Items.Remove(item);
}
Trying same thing with Tabbed page from default project.
Noticed that Command is not running at all not matter what I do. (using Debug)
Try putting delete button in ItemDetailPage.
In ItemDetailPageViewModel put this code.
public Command DeleteCommand { get; set; }
public ItemDetailViewModel()
{
DeleteCommand = new Command(OnDelete);
}
private async void OnDelete()
{
await DataStore.DeleteItemAsync(Id);
await Shell.Current.GoToAsync("..");
}
with ItemDetailPageViewModel you have the Id to delete
ItemDetailPage code here
<?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:XamarinDeleteItem.ViewModels"
x:Class="XamarinDeleteItem.Views.ItemDetailPage"
Title="{Binding Title}">
<ContentPage.BindingContext>
<local:ItemDetailViewModel />
</ContentPage.BindingContext>
<StackLayout Spacing="20" Padding="15">
<Label Text="Text:" FontSize="Medium" />
<Label Text="{Binding Text}" FontSize="Small"/>
<Label Text="Description:" FontSize="Medium" />
<Label Text="{Binding Description}" FontSize="Small"/>
<Button Text="Delete" Command="{Binding DeleteCommand}" />
</StackLayout>
Is SwipeView even supported by Command?
Goto page 221 in this PDF
found this in Xamarin.Forms Documentation. download here
https://opdhsblobprod03.blob.core.windows.net/contents/332e36c8b2484d748610a3dd6b6e98d6/190868cccec033e90406d3cafdb40d3d?skoid=29100048-1fa1-4ada-b0e0-e2aa294fc66a&sktid=975f013f-7f24-47e8-a7d3-abc4752bf346&skt=2022-09-18T13%3A52%3A55Z&ske=2022-09-25T13%3A57%3A55Z&sks=b&skv=2020-10-02&sv=2020-08-04&se=2022-09-20T23%3A36%3A35Z&sr=b&sp=r&sig=0myHYJIb3aEzMUIuCtmXn4VN%2F0MC8gzG1k7%2BQCMZVno%3D
To allow ViewModels to be moreindependent of particular user interface objects but still allow methods to be
called within the ViewModel,a command interfaceexists.This command interface is supported by the following
elements in Xamarin.Forms:
Button
MenuItem
ToolbarItem
SearchBar
TextCell (and hencealso ImageCell )
ListView
TapGestureRecognizer
With theexception of the SearchBar and ListView element, theseelements definetwo properties:
Command of type System.Windows.Input.ICommand
CommandParameter of type Object
The SearchBar defines SearchCommand and SearchCommandParameter properties, whilethe ListView defines a
RefreshCommand property of type ICommand .
The ICommand interface defines two methods and oneevent:
void Execute(object arg)
bool CanExecute(object arg)
event EventHandler CanExecuteChange
Instead use CollectionView Selection with multiple.
use OnCollectionViewSelectionChanged event in codebehind to delete items
<CollectionView ItemsSource="{Binding Monkeys}"
SelectionMode="Multiple"
SelectionChanged="OnCollectionViewSelectionChanged">
...
</CollectionView>
CollectionView collectionView = new CollectionView
{
SelectionMode = SelectionMode.Multiple
};
collectionView.SetBinding(ItemsView.ItemsSourceProperty, "Monkeys");
collectionView.SelectionChanged +=
OnCollectionViewSelectionChanged;
void OnCollectionViewSelectionChanged(object sender, SelectionChangedEventArgs e)
{
var previous = e.PreviousSelection;
var current = e.CurrentSelection;
...
}
So I have a xamarin forms app that currently only implemented for android. I am attempting to implement a tap event. When tapped though this never hits the command in the ViewModel. I'm not sure if I have something the matter with my code or I am just implementing it wrong.
ViewModel Code:
private RelayCommand<object> _OnClickableLabel;
public RelayCommand<object> OnClickableLabel
{
get { return _OnClickableLabel ?? (_OnClickableLabel = new RelayCommand<object>((currentObject) => Test(currentObject))); }
}
private void Test(object currentObject)
{
Application.Current.MainPage.DisplayAlert("Alert", "were going down cap", "OK");
}
Page Xaml:
<ListView Grid.Row="1" ItemsSource="{Binding Notifications}" RowHeight="100">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Orientation="Vertical" BackgroundColor="{Binding BackgroundColor}">
<StackLayout.GestureRecognizers>
<TapGestureRecognizer Command="{Binding OnClickableLabel }" />
</StackLayout.GestureRecognizers>
<Label FontSize="Large" Text="{Binding Title}"></Label>
<Label FontSize="Small" Text="{Binding Text}"></Label>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
I have tested it using a method in the page's cs code and that works fine but it has to be implemented in the ViewModel because it affects that data.
From your description, you want to add a tap gesture recognizer in ListView, and want to pass ListView current row data to TapGestureRecognizer event, am I right?
If yes, as Jason's opinion, you need to take a look Xamarin.Forms Relative Bindings firstly,name ListView as listview1, then take a look the following code:
<ListView
x:Name="listview1"
Grid.Row="1"
ItemsSource="{Binding Notifications}"
RowHeight="100">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout BackgroundColor="{Binding BackgroundColor}" Orientation="Vertical">
<StackLayout.GestureRecognizers>
<TapGestureRecognizer Command="{Binding BindingContext.OnClickableLabel, Source={x:Reference listview1}}" CommandParameter="{Binding .}" />
</StackLayout.GestureRecognizers>
<Label FontSize="Large" Text="{Binding Title}" />
<Label FontSize="Small" Text="{Binding Text}" />
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
public partial class Page16 : ContentPage
{
public ObservableCollection<Notclass> Notifications { get; set; }
public ICommand OnClickableLabel { get; set; }
public Page16()
{
InitializeComponent();
Notifications = new ObservableCollection<Notclass>()
{
new Notclass(){Title="title 1",Text="notification 1"},
new Notclass(){Title="title 2",Text="notification 2"},
new Notclass(){Title="title 3",Text="notification 3"},
new Notclass(){Title="title 4",Text="notification 4"},
new Notclass(){Title="title 5",Text="notification 5"}
};
OnClickableLabel = new Command(n=> {
var vm = (Notclass)n;
Application.Current.MainPage.DisplayAlert("Alert",vm.Title , "OK");
});
this.BindingContext = this;
}
}
public class Notclass
{
public string Title { get; set; }
public string Text { get; set; }
public Color BackgroundColor { get; set; } = Color.White;
}
I have a CollectionView:
<CollectionView Grid.Row="10" Grid.Column="0" Grid.ColumnSpan="1" x:Name="SomeCollection"
ItemsLayout="VerticalList">
<CollectionView.ItemTemplate>
<DataTemplate>
<StackLayout Orientation="Horizontal" Padding="3" Spacing="0">
<Label WidthRequest="90" HeightRequest="20" Text="{Binding SomeItemText}" BackgroundColor="Black" TextColor="White"
VerticalTextAlignment="Center" HorizontalTextAlignment="Center" />
<Button WidthRequest="36" HeightRequest="36" CornerRadius="0" ImageSource="plus_thick.xml" BackgroundColor="Green"
Clicked="Duplicate_Clicked" />
<Button WidthRequest="36" HeightRequest="36" CornerRadius="0" ImageSource="close_thick.xml" BackgroundColor="Red"
Clicked="Remove_Clicked" />
</StackLayout>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
Every item in the collection has a duplicate and a remove button. By clicking the button I would like to duplicate/remove the item, but CollectionView doesn't have indexes on items.
Could you help me with a custom renderer or even something shorter and simpler?
About getting current collectionview item index by Button command, I do one sample that you can take a look:
<StackLayout>
<CollectionView
x:Name="SomeCollection"
ItemsLayout="VerticalList"
ItemsSource="{Binding items}">
<CollectionView.ItemTemplate>
<DataTemplate>
<StackLayout
Padding="3"
Orientation="Horizontal"
Spacing="0">
<Label
BackgroundColor="Black"
HeightRequest="20"
HorizontalTextAlignment="Center"
Text="{Binding SomeItemText}"
TextColor="White"
VerticalTextAlignment="Center"
WidthRequest="90" />
<Button
BackgroundColor="Green"
Command="{Binding BindingContext.duplicatecommand, Source={x:Reference SomeCollection}}"
CommandParameter="{Binding}"
CornerRadius="0"
HeightRequest="36"
Text="duplicate item"
WidthRequest="36" />
</StackLayout>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</StackLayout>
public partial class Page13 : ContentPage
{
public ObservableCollection<someitems> items { get; set; }
public ICommand duplicatecommand { get; set; }
public Page13()
{
InitializeComponent();
items = new ObservableCollection<someitems>()
{
new someitems(){SomeItemText="test 1"},
new someitems(){SomeItemText="test 2"},
new someitems(){SomeItemText="test 3"},
new someitems(){SomeItemText="test 4"},
new someitems(){SomeItemText="test 5"},
new someitems(){SomeItemText="test 6"}
};
duplicatecommand = new Command<someitems>(getindexfun);
this.BindingContext = this;
}
private void getindexfun(someitems item)
{
int index = items.IndexOf(item);
}
}
public class someitems
{
public string SomeItemText { get; set; }
}
Instead of using click events, I would bind the buttons to a Command<T>.
This way in the ViewModel where you have your ItemsSource, you can just check what the index is of the Item ViewModel you are passing into the command as parameter. So in the ViewModel add something like this:
public Command<ItemViewModel> RemoveItemCommand { get; }
ctor() // this is the ViewModel constructor
{
RemoveItemCommand = new Command<ItemViewModel>(DoRemoveItemCommand);
}
private void DoRemoveItemCommand(ItemViewModel model)
{
// do stuff to remove
// probably something like:
Items.Remove(model);
// or get the index like:
var index = Items.IndexOf(model);
}
Then you can bind this command like so:
<Button
WidthRequest="36"
HeightRequest="36"
CornerRadius="0"
ImageSource="close_thick.xml"
BackgroundColor="Red"
Command="{Binding Source={RelativeSource AncestorType={x:Type local:ItemViewModel}}, Path=RemoveItemCommand}"
CommandParameter="{Binding}" />
I'm using Xamarin.forms in visual studio. The problem that I have is that I named an Entry as x:Name="productQuantity" in my NuevaVenta.xaml file and when I'm trying to use that Entry in my NuevaVenta.xaml.cs file it says: The name 'productQuantity' does not exit in the current context. So I can't use it in anyway.
This is my .cs file:
using System;
using System.Collection.Generic;
using Xamarinin.Forms;
namespace Saansa.Views{
public partial class NuevaVenta : ContentPage
{
public Venta()
{
InitializeComponent();
}
protected async override void OnAppearing()
{
base.OnAppearing();
var articuloLista = await App.SQLiteDb.GetItemsAsync();
if (articuloLista != null)
{
listART.ItemsSource = articuloLista;
}
}
int pQuantity = 0;
void subButton_Clicked(System.Object sender, System.EventArgs e)
{
pQuantity--;
if (pQuantity == -1) {
pQuantity = 0;
}
productQuantity.Text = pQuantity.ToString();
}
void addButton_Clicked(System.Object sender, System.EventArgs e)
{
pQuantity++;
productQuantity.Text = pQuantity.ToString();
}
void addCart_Clicked(System.Object sender, System.EventArgs e)
{
}
void goToCart_Clicked(System.Object sender, System.EventArgs e)
{
Navigation.PushAsync(new CarritoDeVentas());
}
}
}
This is my xaml file:
<?xml version="1.0" encoding="UTF-8"?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Saansa.Views.NuevaVenta"
xmlns:local= "clr-namespace:Saansa">
<ContentPage.Content>
<StackLayout BackgroundColor="#f5cda2">
<ListView x:Name="listART" BackgroundColor="#f5cda2">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Orientation="Horizontal">
<StackLayout. HorizontalOptions="StartAndExpand">
<Label Text="{Binding Producto}"
Margin="5,0,0,0"
FontSize="Large"/>
</StackLayout>
<Button x:Name="subButton"
Text="-"
BackgroundColor="#b27b4b"
Margin="5,5,0,5"
Clicked="subButton_Clicked"
FontSize="Small"
TextColor="Black"
WidthRequest="30"/>
<StackLayout>
<Entry Text="0" x:Name="productQuantity"
Placeholder="0" MaxLength="2"
Margin="5,0,0,0" Keyboard="Numeric"
FontSize="Small"
HorizontalOptions="Center"/>
</StackLayout>
<Button x:Name="addButton"
Text="+"
BackgroundColor="#b27b4b"
Margin="5,5,0,5"
Clicked="addButton_Clicked"
FontSize="Small"
TextColor="Black"
WidthRequest="30"/>
<Button x:Name="addCart"
Text="Agregar"
BackgroundColor="#b27b4b"
Margin="5,3,5,3"
Clicked="addCart_Clicked"
FontSize="Small"
TextColor="Black"/>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<StackLayout VerticalOptions="EndAndExpand">
<Button x:Name="goToCart" Text="Ir al carrito" BackgroundColor="White" Clicked="goToCart_Clicked"
CornerRadius="5" Margin="1"/>
</StackLayout>
</StackLayout>
</ContentPage.Content>
Generally, you can't access any control inside the item template by name. giving any control inside ItemTemplate an x:Name will give you a compiler error if you tried to access this control on code behind, Instead assign the Click handler (or use a Command) in the XAML.
So I need to create method for Button click, in your code, I use subButton_Clicked method.
Then Object is Sender which is the handler for button click event. Next we have to find the parent layout or parent container for button by analyzing the xaml file, finally we can access all child element of parent element.
Using your code to do one sample:
<StackLayout>
<ListView
x:Name="listART"
BackgroundColor="#f5cda2"
HasUnevenRows="True"
ItemsSource="{Binding products}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Orientation="Horizontal">
<StackLayout HorizontalOptions="FillAndExpand">
<Label
Margin="5,0,0,0"
FontSize="Large"
Text="{Binding Producto}" />
<Button
x:Name="subButton"
Margin="5,5,0,5"
BackgroundColor="#b27b4b"
Clicked="subButton_Clicked"
FontSize="Small"
Text="-"
TextColor="Black"
WidthRequest="30" />
<StackLayout>
<Entry
x:Name="productQuantity"
Margin="5,0,0,0"
FontSize="Small"
HorizontalOptions="Center"
Keyboard="Numeric"
MaxLength="2"
Placeholder="0"
Text="0" />
</StackLayout>
<Button
x:Name="addButton"
Margin="5,5,0,5"
BackgroundColor="#b27b4b"
Clicked="addButton_Clicked"
FontSize="Small"
Text="+"
TextColor="Black"
WidthRequest="30" />
<Button
x:Name="addCart"
Margin="5,3,5,3"
BackgroundColor="#b27b4b"
Clicked="addCart_Clicked"
FontSize="Small"
Text="Agregar"
TextColor="Black" />
</StackLayout>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<StackLayout VerticalOptions="EndAndExpand">
<Button
x:Name="goToCart"
Margin="1"
BackgroundColor="White"
Clicked="goToCart_Clicked"
CornerRadius="5"
Text="Ir al carrito" />
</StackLayout>
</StackLayout>
public partial class Page7 : ContentPage
{
public ObservableCollection<Productmodel> products { get; set; }
public Page7()
{
InitializeComponent();
products = new ObservableCollection<Productmodel>()
{
new Productmodel(){Producto="product 1"},
new Productmodel(){Producto="product 2"},
new Productmodel(){Producto="product 3"},
new Productmodel(){Producto="product 4"},
new Productmodel(){Producto="product 5"},
new Productmodel(){Producto="product 6"}
};
this.BindingContext = this;
}
private void goToCart_Clicked(object sender, EventArgs e)
{
}
private void addButton_Clicked(object sender, EventArgs e)
{
}
private void addCart_Clicked(object sender, EventArgs e)
{
}
private async void subButton_Clicked(object sender, EventArgs e)
{
var buttonClickHandler = (Button)sender;
StackLayout parentstacklayout = (StackLayout)buttonClickHandler.Parent;
StackLayout stacklayout1 =(StackLayout)parentstacklayout.Children[2];
Entry productQuantity = (Entry)stacklayout1.Children[0];
await DisplayAlert("productQuantity detail","the productQuantity text is "+productQuantity.Text,"OK");
}
}
public class Productmodel
{
public string Producto { get; set; }
}
This is the screenshot: