Problem I want to delete one article from a ObserableCollection when i Press the Red "X". But i don´t know how to get the Current Artcile. I have a class Artcile. and the list which saves the different Articles.
Xaml Code
<ItemsControl ItemsSource="{Binding CartArticles}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border BorderBrush="Black" BorderThickness="2" CornerRadius="30,30,30,30" Margin="0,15,0,30" MinWidth="100" MaxWidth="600" >
<Grid Margin="0,0,0,10" Grid.Row="0">
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Image Width="100" Height="70" Source="{Binding PathPic}" Margin="0,10,0,0"/>
<TextBlock FontWeight="Bold" Grid.Column="1" FontSize="17" HorizontalAlignment="Center" VerticalAlignment="Center" Text="{Binding Name}"/>
<StackPanel Grid.Column="2" HorizontalAlignment="Center" Orientation="Horizontal" VerticalAlignment="Center" >
<TextBlock FontWeight="Bold" FontSize="17" Foreground="DimGray" Text="{Binding Quantity}"/>
<TextBlock Text=" x " FontSize="16" Foreground="DimGray" />
<TextBlock FontWeight="Bold" FontSize="17" Foreground="DimGray" Text="{Binding Price}" />
<TextBlock FontWeight="Bold" FontSize="17" Foreground="DimGray" Text=" Euro" />
</StackPanel>
<StackPanel Grid.Column="2" HorizontalAlignment="Center" Orientation="Horizontal" VerticalAlignment="Bottom" >
<TextBlock FontWeight="Bold" Grid.Column="2" FontSize="17" HorizontalAlignment="Center" VerticalAlignment="Bottom" Text="{Binding CompleteArticlePrice}"/>
<TextBlock FontWeight="Bold" FontSize="17" Foreground="DimGray" Text=" Euro" />
</StackPanel>
<Button Name="DeleteCartArticle" Grid.Column="2" Width="20" Height="20" Margin="0,13,20,0" Content="X" FontSize="15" Foreground="Red" Background="Transparent" BorderThickness="0" HorizontalAlignment="Right" VerticalAlignment="Center" Click="DeleteCartArticle_Click"/>
</Grid>
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
ObserableCollection
public ObservableCollection<Article> CartArticles { get; set; } = new ObservableCollection<Article>();
public void GetCartArticles()
{
foreach (var article in _shoppingCartService.CartArticles.ToList())
{
CartArticles.Add(new Article
{
ArticleId = article.ArticleId,
Name = article.Name,
Price = article.Price,
Quantity = article.Quantity,
PathPic = article.PathPic,
CompleteArticlePrice = article.Price * article.Quantity,
});
}
}
Output
Nice to see you're keep progressing from previous question :)
As @Clemens suggested, for buttons in MVVM you should use bindings too, and commands, which will handle click actions. But in case you use ItemsControl
(not ListView
or ListBox
, which has SelectedItem
proeprty to simplify our life) there is a little trick with button binding (described in XAML example-part below).
So, first of all you need to create a custom class which implements ICommand
interface from System.Windows.Input
namespace. Custom command class should accept some object
as parameter, and that "object" is an item from ItemsControl
. So, let's call it ParameterizedCommand
:
using System;
using System.Windows.Input;
namespace YourNamespace.Commands
{
public sealed class ParameterizedCommand : ICommand
{
private readonly Action<object> _action;
public ParameterizedCommand(Action<object> action) => _action = action;
public bool CanExecute(object parameter) => true;
public void Execute(object parameter) => _action(parameter);
public event EventHandler CanExecuteChanged
{
add => CommandManager.RequerySuggested += value;
remove => CommandManager.RequerySuggested -= value;
}
}
}
Now in your ViewModel (which is CartViewModel
from previous answer) add command to remove CartArticle
from CartArticles
collection:
public class CartViewModel
{
// A collection, which stores articles in cart
public ObservableCollection<CartArticle> CartArticles { get; } = new ObservableCollection<CartArticle>();
private ICommand _removeCartArticle;
public ICommand RemoveCartArticle => _removeCartArticle ?? (_removeCartArticle = new ParameterizedCommand(parameter =>
{
// Ensure that received parameter is CartArticle
var cartArticle = parameter as CartArticle;
if (cartArticle == null)
return;
CartArticles.Remove(cartArticle);
}));
// ...
}
And finally, in your View bind button to that command. To allow button in item template "find" ViewModel and stored command, you can use RelativeSource
, which is parent ItemsControl
, and as CommandParameter
we passing the item itself:
<ItemsControl ItemsSource="{Binding CartArticles}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<!-- ... -->
<Button Command="{Binding RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}, Path=DataContext.RemoveCartArticle}"
CommandParameter="{Binding}"/>
<!-- ... -->
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
Now "delete" button in each CartArticle
on click will remove that item from a collection. Just don't forget again append some styling: