Reputation: 57
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.
Upvotes: 0
Views: 4786
Reputation: 294
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;
...
}
Upvotes: 0
Reputation: 294
Is SwipeView even supported by Command?
Goto page 221 in this PDF found this in Xamarin.Forms Documentation. download here
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
Upvotes: 0
Reputation: 294
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>
Upvotes: 0
Reputation: 1781
Change your parameter to this
CommandParameter="{Binding Source={RelativeSource Self}, Path=BindingContext}"
Upvotes: 3
Reputation: 89129
the code you have in OnDeleteItem
is nonsensical. It should look something like this
private void OnDeleteItem(Item item)
{
Items.Remove(item);
}
Upvotes: 0