I've build a semi-working app on C# and Xamarin.Forms, grocery list of sorts.
My issue is (me) when user deletes any item on his display (clicks on ImageButton (Trash Icon)), ImageButton is binded withfunction, wich through TodoItems.Remove, removes that specific clicked "item" if u will but I would love to somehow get int Price of that ObservableCollection<TodoItem before it's removed and substract that specific price from my Total: price. Currently my substraction from Total price works in the dumbest way. Let's say I click on ImageButton delete Broccoli (which cost 6.5). But Total price will be substracted by 3, not 6.5. That's because i implemented INotifyPropertyChanged which updates Total price label and since my price of each item is binded to Entry, Total price is being substracted by number which is currently in the entry (Entry under bananas). Help me fix this issue, is there a way to implement id system for each ObservableCollection which consists of three elements: string - name, bool - checkbox, double - price of item.
Here's how my xaml looks like
<ContentPage.BindingContext>
<local:TodoListViewModel/>
</ContentPage.BindingContext>
<StackLayout Margin="10,50,10,10">
<Button
x:Name="start"
Text="Start"
Clicked="Start_Clicked"/>
<Entry
x:Name="recon"
Text="{Binding NewTodoInputValue}"
ReturnCommand="{Binding AddTodoCommand}">
</Entry>
<Entry x:Name="cashrecon" Text="{Binding Price}" ReturnCommand="{Binding AddTodoCommand}">
</Entry>
<Label x:Name="amount" >
</Label>
<ListView x:Name="TodoList" ItemsSource="{Binding TodoItems}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<FlexLayout JustifyContent="SpaceBetween" AlignContent="Center" Padding="10, 0">
<ContentView>
<FlexLayout AlignItems="Center">
<input:CheckBox
IsChecked="False"
/>
<Label Text="{Binding ToDoText}" FontSize="Large" Padding="10, 0"/>
<StackLayout>
<Stepper Minimum="1"
Scale="0.5"
Maximum="10"
Increment="1"
HorizontalOptions="Center"
VerticalOptions="Center"
ValueChanged="Stepper_ValueChanged"
/>
<Label x:Name="cena" Text="{Binding Price}" Margin="20,-40,0,10">
</Label>
</StackLayout>
</FlexLayout>
</ContentView>
<ImageButton
Source="delete.png"
Command="{Binding Path=BindingContext.RemoveTodoCommand, Source={x:Reference TodoList}}"
CommandParameter="{Binding .}"
BackgroundColor="Transparent"
/>
</FlexLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<Label
x:Name="Total"
Text="{Binding DisplayName}"
TextColor="Black"
Padding="250,0,0,0">
</Label>
</StackLayout>
Here's TodoItem class
namespace XFSpeechDemo
public class TodoItem
{
public string ToDoText { get; set; }
public bool Complete { get; set; }
public double Price { get; set; }
public TodoItem(string ToDoText, bool Complete, double Price)
{
this.ToDoText = ToDoText;
this.Complete = Complete;
this.Price = Price;
}
}
And here's ViewModel, which Is the core issue of mine
namespace XFSpeechDemo
public class TodoListViewModel : INotifyPropertyChanged
{
public ObservableCollection<TodoItem> TodoItems { get; set; }
public TodoListViewModel()
{
TodoItems = new ObservableCollection<TodoItem>();
TodoItems.Add(new TodoItem("todo 1", false, 0));
TodoItems.Add(new TodoItem("todo 2", false, 0));
TodoItems.Add(new TodoItem("todo 3", false, 0));
}
public ICommand AddTodoCommand => new Command(AddTodoItem);
public string NewTodoInputValue { get; set; }
public double Amount { get; set; }
public double Price { get; set; }
double name=0;
public double TotalPrice
{
get => name;
set
{
if (name == value)
{
return;
}
name = value;
OnPropertyChanged(nameof(Price));
OnPropertyChanged(nameof(DisplayName));
}
}
public event PropertyChangedEventHandler PropertyChanged;
void OnPropertyChanged(string name)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
void AddTodoItem()
{
TodoItems.Add(new TodoItem(NewTodoInputValue, false, Price));
TotalPrice = Price;
}
public ICommand RemoveTodoCommand => new Command(RemoveTodoItem);
void RemoveTodoItem(object o)
{
TodoItem todoItemBeingRemoved = o as TodoItem;
TodoItems.Remove(todoItemBeingRemoved);
TotalPrice -= Price;
}
public string DisplayName => $"Total: {TotalPrice} Blr";
}
I'm not well spoken in all the terms. I can read documentation, but it's all confusing about ObservableCollection so if I'll be glad to a reply with technical solution, not a reply w technical terms n smart phrases which i simply won't understand. Ty BTW addition to Total: price works totally fine. It's just substraction that I'm struggling with. Don't see obvious solution on how to create id system which will track each item added n can be called when user clicks any Trash icon ImageButton, correctly identify the deleted price and ofcourse substract from Total Price of all items.
CodePudding user response:
instead of doing this
void RemoveTodoItem(object o)
{
TodoItem todoItemBeingRemoved = o as TodoItem;
TodoItems.Remove(todoItemBeingRemoved);
TotalPrice -= Price;
}
do this
void RemoveTodoItem(object o)
{
TodoItem todoItemBeingRemoved = o as TodoItem;
TodoItems.Remove(todoItemBeingRemoved);
TotalPrice -= todoItemBeingRemoved.Price;
}
CodePudding user response:
Perhaps changing the command to be one that allows and expects a parameter would help:
public ICommand RemoveTodoCommand => new Command(RemoveTodoItem);
would be switched to
public Command<TodoItem> RemoveTodoCommand => new Command<TodoItem>(RemoveTodoItem);
And your RemoveTodoItem
would have to have its signature changed to:
void RemoveTodoItem(TodoItem item)
Which you can then use to subtract from your total:
void RemoveTodoItem(TodoItem item)
{
TodoItems.Remove(item);
TotalPrice -= item.Price;
}
You could also cast your object coming into your current RemoveTodoCommand
to a TodoItem
and subtract from your price that way (the way you have started), but you need to ensure you are subtracting the current item's price -- something like TotalPrice -= todoItemBeingRemoved.Price;