When using ViewCell with TableView it shows a right arrow > (circled in red) and the whole cell can be touched - I suppose to select it and slide a new page from right to left to "drill into details".
Can someone advise on how to disable the display of > ?
Looks that ViewCell.IsEnabled = false turns off the touch action.
Here is some code in my class deriving from ContentPage that creates the table section:
public class SamplePage : ContentPage
{
public SamplePage()
{
var gridLengthStar = new GridLength(1, GridUnitType.Star);
// GRIDSAMPLE CODE
var gridSample = new Grid
{
RowDefinitions =
{
new RowDefinition {Height = GridLength.Auto},
new RowDefinition {Height = GridLength.Auto}
},
Padding = new Thickness(20, 20, 20, 20),
ColumnDefinitions =
{
new ColumnDefinition {Width = gridLengthStar},
new ColumnDefinition {Width = gridLengthStar}
},
};
gridSample.Children.Add ( new Label() { Text = "Data1" }, 0, 0);
gridSample.Children.Add ( new Label() { Text = "Data2" }, 1, 0);
gridSample.Children.Add ( new Label() { Text = "Data3" }, 0, 1);
gridSample.Children.Add ( new Label() { Text = "Data4" }, 1, 1);
var tableView = new TableView
{
HasUnevenRows = true,
Intent = TableIntent.Form,
};
tableView.Root = new TableRoot
{
new TableSection("SECTION TITLE")
{
(new ViewCell {View = gridSample, IsEnabled = false})
}
};
Content = new StackLayout()
{
Children = { tableView } ,
Orientation = StackOrientation.Vertical,
VerticalOptions = LayoutOptions.Start,
Spacing = 10
};
}
}
That arrow can be shown on iOS if you set
Accessory = UITableViewCellAccessory.DisclosureIndicator;
in your UITableViewCell.
Xamarin.Forms usually doesn't set this, so the arrow should not be shown. If it is there, then you have some renderer, Effect or other component which sets it in the iOS code.
Related
I need to create a list view programmatically. This list view is populated from a sql server. The labels have their bindings set via a observable collection Shooters. I need this list view to change the number of columns based on a variable called rounds. Everything works as intended but this line of code causes the UI to be messed up.
var con = new CustomViewCell(Rounds);
var connect = await con.GetCellLayout(Rounds); // Returns a grid
var ShooterDataTemplate = new DataTemplate(() =>
{
return new ViewCell { View = connect }; // assigns grid to the viewcell view
});
I get duplicate rows with the same information and other rows are missing their labels. Microsoft called this an inline Data Template. Image below in hyperlink
bad ui
The second options they say is to do it like so..
ShooterListView.ItemTemplate = new DataTemplate(new Typeof(CustomViewCell));
When done this way The UI Looks normal. The problem though is that I cant pass the rounds variable to the customviewcell which determines which function to use to set all the columns.
Here is the exact same grid but done through typeof(CustomViewCell)
Good UI
In both cases I use the exact same grid layout design the only difference is I use inline code to create the data template and then a typeof(customViewCell) how can I get the inline code to not cause such a weird layout design since I cant pass a variable to typeof(CustomViewCell).
Grid code attached below
public async Task<Grid> Get_Round_7_Cell()
{
var column1 = new ColumnDefinition() { Width = new GridLength(15, GridUnitType.Star) };
var column2 = new ColumnDefinition() { Width = new GridLength(15, GridUnitType.Star) };
var column3 = new ColumnDefinition() { Width = new GridLength(10, GridUnitType.Star) };
var column4 = new ColumnDefinition() { Width = new GridLength(10, GridUnitType.Star) };
var column5 = new ColumnDefinition() { Width = new GridLength(10, GridUnitType.Star) };
var column6 = new ColumnDefinition() { Width = new GridLength(10, GridUnitType.Star) };
var column7 = new ColumnDefinition() { Width = new GridLength(10, GridUnitType.Star) };
var column8 = new ColumnDefinition() { Width = new GridLength(10, GridUnitType.Star) };
var column9 = new ColumnDefinition() { Width = new GridLength(10, GridUnitType.Star) };
var smallfont = Device.GetNamedSize(NamedSize.Micro, typeof(Label));
if (Device.Idiom == TargetIdiom.Tablet || Device.Idiom == TargetIdiom.Phone)
{
PaddingLeft = new Thickness(20, 0, 0, 0);
}
else
{
PaddingLeft = new Thickness(60, 0, 0, 0);
}
if (Device.Idiom == TargetIdiom.Tablet || Device.Idiom == TargetIdiom.Phone)
{
PaddingRight = new Thickness(0, 0, 20, 0);
}
else
{
PaddingRight = new Thickness(0, 0, 60, 0);
}
var shooterlabel = new Label() { HorizontalTextAlignment = TextAlignment.Start, FontSize = smallfont, Padding = PaddingLeft };
shooterlabel.SetBinding(Label.TextProperty, new Binding("Shooter_Name"));
var team_name_label = new Label() { HorizontalTextAlignment = TextAlignment.Center, FontSize = smallfont };
team_name_label.SetBinding(Label.TextProperty, new Binding("Team_Name"));
var round1_label = new Label() { HorizontalTextAlignment = TextAlignment.Center, FontSize = smallfont };
round1_label.SetBinding(Label.TextProperty, new Binding("Round_1"));
var round2_label = new Label() { HorizontalTextAlignment = TextAlignment.Center, FontSize = smallfont };
round2_label.SetBinding(Label.TextProperty, new Binding("Round_2"));
var round3_label = new Label() { HorizontalTextAlignment = TextAlignment.Center, FontSize = smallfont };
round3_label.SetBinding(Label.TextProperty, new Binding("Round_3"));
var round4_label = new Label() { HorizontalTextAlignment = TextAlignment.Center, FontSize = smallfont };
round4_label.SetBinding(Label.TextProperty, new Binding("Round_4"));
var round5_label = new Label() { HorizontalTextAlignment = TextAlignment.Center, FontSize = smallfont };
round5_label.SetBinding(Label.TextProperty, new Binding("Round_5"));
var round6_label = new Label() { HorizontalTextAlignment = TextAlignment.Center, FontSize = smallfont };
round6_label.SetBinding(Label.TextProperty, new Binding("Round_6"));
var round7_label = new Label() { HorizontalTextAlignment = TextAlignment.End, FontSize = smallfont, Padding = PaddingRight };
round7_label.SetBinding(Label.TextProperty, new Binding("Round_7"));
grid2.ColumnDefinitions.Add(column1);
grid2.ColumnDefinitions.Add(column2);
grid2.ColumnDefinitions.Add(column3);
grid2.ColumnDefinitions.Add(column4);
grid2.ColumnDefinitions.Add(column5);
grid2.ColumnDefinitions.Add(column6);
grid2.ColumnDefinitions.Add(column7);
grid2.ColumnDefinitions.Add(column8);
grid2.ColumnDefinitions.Add(column9);
grid2.Children.Add(shooterlabel, 0, 0);
grid2.Children.Add(team_name_label, 1, 0);
grid2.Children.Add(round1_label, 2, 0);
grid2.Children.Add(round2_label, 3, 0);
grid2.Children.Add(round3_label, 4, 0);
grid2.Children.Add(round4_label, 5, 0);
grid2.Children.Add(round5_label, 6, 0);
grid2.Children.Add(round6_label, 7, 0);
grid2.Children.Add(round7_label, 8, 0);
grid.Children.Add(boxview);
grid.Children.Add(grid2);
return grid;
}
Solution below. Not the best but its getting the job done. I never could get inline DataTemplate to work so I had to make custom view cells for each round and call them based on what Rounds value was.
public async Task<ListView> SetShooterListView(int Rounds)
{
var shooterlistview = new ListView() { HorizontalOptions = LayoutOptions.Fill };
var headergrid = Rounds == 1 ? await Get_Round_1() : Rounds == 2 ? await Get_Round_2() : Rounds == 3 ? await Get_Round_3() : Rounds == 4 ? await Get_Round_4() : Rounds == 5 ? await Get_Round_5() : Rounds == 6 ? await Get_Round_6() : Rounds == 7 ? await Get_Round_7() : Rounds == 8 ? await Get_Round_8() : Rounds == 9 ? await Get_Round_9() : await Get_Round_10();
var viewcellgrid = Rounds == 1 ? new DataTemplate(typeof(Round_1_View)) : Rounds == 2 ? new DataTemplate(typeof(Round_2_View)) : Rounds == 3 ? new DataTemplate(typeof(Round_3_View)) : Rounds == 4 ? new DataTemplate(typeof(Round_4_View)) : Rounds == 5 ? new DataTemplate(typeof(Round_5_View)) : Rounds == 6 ? new DataTemplate(typeof(Round_6_View)) : Rounds == 7 ? new DataTemplate(typeof(Round_7_View)) : Rounds == 8 ? new DataTemplate(typeof(Round_8_View)) : Rounds == 9 ? new DataTemplate(typeof(Round_9_View)) : new DataTemplate(typeof(Round_10_View));
shooterlistview.Header = headergrid;
shooterlistview.ItemTemplate = viewcellgrid;
return shooterlistview;
}
I've been working on a Xamarin Forms project and I'm having trouble loading data into the Android application. It loads fine for iOS and UWP, but on Android it takes forever. This is happening on two different screens but I'm assuming the problem is the same. I'm sure there are better ways to load the data than what I am using.
This is the first screen I'm having trouble with on Android (screenshot from UWP):
It loads 15 products in each category into a horizontal scroller. The "See All" link loads all of the products in that category into a vertical scrolling grid. That's the second screen I'm having trouble with.
The code to load this view is:
var scroller = new TLScrollView
{
Orientation = ScrollOrientation.Horizontal,
ItemTemplate = new DataTemplate(() => ViewFactory.Merchandise.Invoke()),
HeightRequest = 320,
Padding = new Thickness(0, 0, 0, 10)
};
scroller.SetBinding(TLScrollView.ItemsSourceProperty, nameof(items));
scroller.ItemsSource = items.OrderByDescending(d => d.Cost).Take(15);
The ViewFactory code is:
public static Func<View> Merchandise { get; } = () =>
{
var mainGrid = new Grid() { WidthRequest = 250, Margin = 5 };
mainGrid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(1, GridUnitType.Star) });
mainGrid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(25, GridUnitType.Absolute) });
mainGrid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(25, GridUnitType.Absolute) });
mainGrid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(25, GridUnitType.Absolute) });
mainGrid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(35, GridUnitType.Absolute) });
var nameLabel = new Label() { Text = "Casket Name", LineBreakMode = LineBreakMode.TailTruncation, HorizontalTextAlignment = TextAlignment.Center };
var materialLabel = new Label() { Text = "MaterialName", HorizontalTextAlignment = TextAlignment.Center };
var costLabel = new Label() { Text = "Cost", HorizontalTextAlignment = TextAlignment.Center };
nameLabel.SetBinding(Label.TextProperty, "ItemName");
materialLabel.SetBinding(Label.TextProperty, "Material");
costLabel.SetBinding(Label.TextProperty, "CostFormatted");
GlobalModel globalModel = App.Current.MainPage.BindingContext as GlobalModel;
var catalogImage = new CachedImage
{
HorizontalOptions = LayoutOptions.FillAndExpand,
VerticalOptions = LayoutOptions.FillAndExpand,
Aspect = Aspect.AspectFit,
LoadingPlaceholder = "MAFSLoader.gif",
CacheDuration = TimeSpan.FromDays(10),
RetryCount = 1,
RetryDelay = 100
};
catalogImage.BindingContextChanged += (s, o) => {
catalogImage.Source = null;
var item = catalogImage.BindingContext as CatalogItem;
if (item == null) return;
catalogImage.Source = item.SmallURL;
};
var buttonStyle = (Style)Application.Current.Resources["ButtonStyle"];
var addToCartButton = new Button { Text = "Add to Cart", BackgroundColor = Color.FromHex("#486E8E"), WidthRequest = 250, Style = buttonStyle };
addToCartButton.SetBinding(Button.CommandParameterProperty, "ItemID");
var imgTapGesture = new TapGestureRecognizer()
{
Command = new Command(() =>
{
if (addToCartButton.CommandParameter == null)
{
addToCartButton.SetBinding(Button.CommandParameterProperty, "ItemId");
}
var dictionary = new Dictionary<string, string>();
dictionary.Add(globalModel.CurrentFuneralHomeKey, addToCartButton.CommandParameter.ToString());
globalModel.ProductDetail.Execute(dictionary);
})
};
catalogImage.GestureRecognizers.Add(imgTapGesture);
addToCartButton.Clicked += new EventHandler(async delegate (Object o, EventArgs a)
{
var button = ((Button)o);
globalModel.AddToCart.Execute(button.BindingContext);
if (button.BindingContext.GetType() == typeof(Data.Corner))
{
await App.Current.MainPage.DisplayAlert("Shopping Cart", "You've added " + (button.BindingContext as Data.Corner).ItemName + " to your cart.", null, "OK");
}
});
mainGrid.Children.Add(catalogImage, 0, 0);
mainGrid.Children.Add(nameLabel, 0, 1);
mainGrid.Children.Add(materialLabel, 0, 2);
mainGrid.Children.Add(costLabel, 0, 3);
mainGrid.Children.Add(addToCartButton, 0, 4);
return mainGrid;
};
If anyone could point me in the right direction I'd be very grateful!
Interesting. I've just gone through the implementation of the TLSrollview. It looks like there is no recycling of elements and maybe lack some optimization (I can see that only if I debug). I see two options :
option 1 : Create a listview with recycling strategy on. For better performance, set also the row height. One item of your listview would be one row. The advantage of a listview is the performance gain from the recycling strategy (especially on Android). Note that on iOS and Android, it might be better to set it on or not.
option 2 : Create a custom layout. That might be a little overkill.
There is a label in the page Account which when tapped on will create a new ContentPage with a list of premise addresses. Tapping on any of the addresses should pop the ContentPage and send back a value to the Account page to set certain fields within the Account page. I tried to use Messaging center but it doesn't seem to be able to get the value. What am I missing?
This is the code that creates the ContentPage with the premise addresses:
private void ddlPremisesAddNavigation()
{
PremiseListPage = CreatePAContentPage();
var tgrddlPremiseAddress = new TapGestureRecognizer();
NavigationPage.SetHasNavigationBar(PremiseListPage, false);
tgrddlPremiseAddress.Tapped += (s, e) =>
{
Navigation.PushAsync(PremiseListPage);
};
// ddlPremiseAddresses.GestureRecognizers.Add(tgrddlPremiseAddress);
lblpremiseAddress.GestureRecognizers.Add(tgrddlPremiseAddress);
}
private ContentPage CreatePAContentPage()
{
#region Containers
ContentPage content = new ContentPage();
StackLayout pageContent = new StackLayout();
ScrollView addressesView = new ScrollView()
{
// BackgroundColor = Color.White,
Padding = new Thickness(20, 10, 20, 10)
};
StackLayout addressContainer = new StackLayout();
#endregion
#region Header
RowDefinitionCollection RowDefinitions = new RowDefinitionCollection();
ColumnDefinitionCollection ColumnDefinitions = new ColumnDefinitionCollection();
RowDefinitions.Add(new RowDefinition { Height = new GridLength(50, GridUnitType.Absolute) });
Grid header = new Grid()
{
RowDefinitions = RowDefinitions,
};
BoxView bg = new BoxView() { HeightRequest = 50, WidthRequest = 250, BackgroundColor = Color.White };
header.Children.Add(bg, 0, 0);
Grid.SetColumnSpan(bg, 5);
Label title = new Label()
{
Text = "Premise Address",
FontSize = 15,
FontAttributes = FontAttributes.Bold,
VerticalOptions = LayoutOptions.CenterAndExpand,
HorizontalOptions = LayoutOptions.CenterAndExpand
};
header.Children.Add(title, 1, 0);
Grid.SetColumnSpan(title, 3);
Button back = new Button() { Image = "backArrow", BackgroundColor = Color.White };//
header.Children.Add(back, 0, 0);
Grid.SetColumnSpan(back, 1);
back.Clicked += back_Clicked;
#endregion
#region Address Frames
List<Frame> addrFrames = new List<Frame>();
if (premiseAddresses.Count <= 0)
{
foreach (PremisesModel premise in Premises)
{
premiseAddresses.Add(premise.PremiseId, premise.PremiseAddress);
}
}
foreach (KeyValuePair<int,string> item in premiseAddresses)
{
addrFrames.Add(CreatePAFrame(item));
}
#endregion
#region Add Content to Containers
foreach (Frame item in addrFrames)
{
addressContainer.Children.Add(item);
}
// < Button x: Name = "btnReqAmendment" Text = "Request amendment" Style = "{StaticResource buttonStyle}" Clicked = "btnReqAmendment_Clicked" />
Button addNew = new Button()
{
Text = "ADD NEW PREMISE ADDRESS",
Style = Application.Current.Resources["buttonStyle"] as Style,
HorizontalOptions = LayoutOptions.CenterAndExpand,
Margin = new Thickness(0, 20, 2, 15)
//FontSize = 12,
//WidthRequest = 220,
//HeightRequest = 40
};
addNew.Clicked += btnAddNewPremise_Clicked;
addressContainer.Children.Add(addNew);
addressesView.Content = addressContainer;
pageContent.Children.Add(header);
pageContent.Children.Add(addressesView);
content.Content = pageContent;
#endregion
return content;
}
private Frame CreatePAFrame(KeyValuePair<int, string> premiseAddress)
{
Frame frame = new Frame() { Padding = new Thickness(5, 5, 3, 5), HeightRequest = 60 };
StackLayout content = new StackLayout() { Padding = 0 };
content.Orientation = StackOrientation.Horizontal;
Label pAddress = new Label();
pAddress.Text = premiseAddress.Value;
pAddress.Style = Application.Current.Resources["LabelStart"] as Style;
pAddress.HeightRequest = 50;
pAddress.HorizontalOptions = LayoutOptions.StartAndExpand;
Image img = new Image()
{
Source = "rightArrow",
HorizontalOptions = LayoutOptions.End,
VerticalOptions = LayoutOptions.CenterAndExpand
};
content.Children.Add(pAddress);
content.Children.Add(img);
frame.Content = content;
var selectAddress = new TapGestureRecognizer();
selectAddress.Tapped += (s, e) =>
{
MessagingCenter.Send(this, "premiseId", premiseAddress.Key);
Navigation.PopAsync();
};
frame.GestureRecognizers.Add(selectAddress);
return frame;
}
And this is how it subscribes to Messaging center:
public Account()
{
MessagingCenter.Subscribe<ContentPage,int>(this, "premiseId", (sender,arg) =>
{
DisplayAlert("Premise Changed", "test", "OK");
selectedPremise = arg;
DisplaySelectedPremiseValues();
});
InitializeComponent();
}
One option could be using a global variable (e.g in App.cs) and setting this variable whenever a list item is tapped:
public static Address TappedAddress;
And before showing the listview reset that variable.
I'm using the following (test) code to dynamically create a Page Content. I'm expecting the Entry control to stay within the StackLayout bounds and clip its large Text value. Somehow this doesn't work like I want.
What am I doing wrong here?
public MyPage() {
InitializeComponent();
var stackMain = new StackLayout() {
Orientation = StackOrientation.Vertical,
Spacing = 2,
BackgroundColor = Color.Yellow
};
Content = stackMain;
Padding = new Thickness(15, Device.OnPlatform(25, 5, 5), 15, 10);
var label = new Label() {
Text = "Test:"
};
stackMain.Children.Add(label);
var stackEntry = new StackLayout() {
Orientation = StackOrientation.Horizontal
};
stackMain.Children.Add(stackEntry);
var entry = new Entry() {
Text = "Blaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
IsEnabled = false,
HorizontalOptions = LayoutOptions.FillAndExpand
};
stackEntry.Children.Add(entry);
var button = new Button() {
Text = "Click me"
};
stackEntry.Children.Add(button);
}
What you need is an editor, Entries are one line only, the code below is tested and it fixes the Height by the size of the text:
public class App : Application
{
public App()
{
// The root page of your application
var content = new ContentPage
{
Padding = new Thickness(15, Device.OnPlatform(25, 5, 5), 15, 10),
Title = "test",
Content = new StackLayout
{
Spacing = 2,
BackgroundColor = Color.Yellow,
Children = {
new Label {
Text = "Test:"
},
new Editor {
Text = "Blaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
IsEnabled = false,
HorizontalOptions = LayoutOptions.Fill,
VerticalOptions = LayoutOptions.Fill
},
}
}
};
MainPage = new NavigationPage(content);
}
}
Hope this helps.
I just solved the same problem on an editor control!
The problem is here Orientation = StackOrientation.Horizontal,
you need to set orientation as StackOrientation.Vertical and it will wrap properly.
Note that I'm using Editor instead of Entry.
How can I add Swipe to delete in my note list app.I am using xamarin forms. I have searched in xamarin forms samples but could not find it. I also tried the list view performance options with menuItem etc but I dont know how to adjust that in my code. Can anyone help me with this please?
My code is as follows:
public partial class MyPage
{
List<Note> notes;
string NotesFile {
get {
var documents = Environment.GetFolderPath (Environment.SpecialFolder.Personal);
return System.IO.Path.Combine (documents, "notes.json");
}
}
public MyPage()
{
BuildContent();
LoadNotes ();
ReloadListContents ();
AddNoteButton.Clicked += (sender, args) => {
var note = new Note("typ...");
notes.Add(note);
EditNote(note);
};
NoteListView.ItemTapped += (sender, row) =>
{
NoteListView.SelectedItem = null;
Note note = (Note)row.Item;
EditNote(note);
};
buttonDelete.Clicked += (sender, args) =>{
notes.RemoveAt(0);
DisplayAlert("Delete", "Row deleted", "OK");
};
}
}
MyPage.cs
{
public ListView NoteListView = new ListView ();
public Button AddNoteButton;
public Button buttonDelete;
private void BuildContent()
{
AddNoteButton = new Button
{
Text = "Add New Note",
TextColor = Color.White,
HorizontalOptions = LayoutOptions.Center,
VerticalOptions = LayoutOptions.Center
};
buttonDelete = new Button
{
Text = "Delete Note ",
TextColor = Color.White,
HorizontalOptions = LayoutOptions.Center,
VerticalOptions = LayoutOptions.Center
};
Content = new StackLayout
{
BackgroundColor = Color.Black,
Children = {
new Label {
Text = "Note Taker",
TextColor = Color.White
},
NoteListView,
AddNoteButton,
buttonDelete
}
};
}
Im responding to this question in CS code rather than XAML (My Preferred) if anyone would like the Xaml response please drop a comment below and I'll write the XAML alongside the CS.
So to complete what you have asked in Xamarin.Forms on ListView elements you must first create the ViewCell that you would like to display the data in each cell in the ListView and give it context actions. Here is an example:
public class CustomViewCell : ViewCell
{
public CustomViewCell()
{
//instantiate each element we want to use.
var image = new CircleCachedImage
{
Margin = new Thickness(20, 10, 0, 10),
WidthRequest = App.ScreenWidth * 0.15,
HeightRequest = App.ScreenWidth * 0.15,
Aspect = Aspect.AspectFill,
BorderColor = Color.FromHex(App.PrimaryColor),
BorderThickness = 2,
HorizontalOptions = LayoutOptions.Center
};
var nameLabel = new Label
{
Margin = new Thickness(20, 15, 0, 0),
FontFamily = "Lato",
FontAttributes = FontAttributes.Bold,
FontSize = 17
};
var locationLabel = new Label
{
Margin = new Thickness(20, 0, 0, 5),
FontFamily = "Lato",
FontSize = 13
};
//Create layout
var verticaLayout = new StackLayout();
var horizontalLayout = new StackLayout() { BackgroundColor = Color.White };
//set bindings
nameLabel.SetBinding(Label.TextProperty, new Binding("Name"));
locationLabel.SetBinding(Label.TextProperty, new Binding("Location"));
image.SetBinding(CircleCachedImage.SourceProperty, new Binding("Image"));
//Set properties for desired design
horizontalLayout.Orientation = StackOrientation.Horizontal;
horizontalLayout.HorizontalOptions = LayoutOptions.Fill;
image.HorizontalOptions = LayoutOptions.End;
//add views to the view hierarchy
horizontalLayout.Children.Add(image);
verticaLayout.Children.Add(nameLabel);
verticaLayout.Children.Add(locationLabel);
horizontalLayout.Children.Add(verticaLayout);
//HERE IS THE MOST IMPORTANT PART
var deleteAction = new MenuItem { Text = "Delete", IsDestructive = true }; // red background
deleteAction.Clicked += async (sender, e) => {
//Here do your deleting / calling to WebAPIs
//Now remove the item from the list. You can do this by sending an event using messaging center looks like:
//MessagingCenter.Send<TSender,string>(TSender sender, string message, string indexOfItemInListview)
};
// add to the ViewCell's ContextActions property
ContextActions.Add(deleteAction);
// add to parent view
View = horizontalLayout;
}
}
Now you must do the following to your ListView:
listView = new ListView();
lstView.ItemTemplate = new DataTemplate(typeof(CustomViewCell));
In the same Content Page that you have the ListView you must also subscirbe to the MessagingCenter listening to the same parameters as set in the custom view cell as above. Please read the link provided if you have not used the MessagingCenter before. Inside of this method you must then remove the item from the listview with the index sent to this method.
If anyone needs any further explanations drop a comment below and Ill edit this post.