Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to Add a Quantity Column on a DataGrid from ListView selection in WPF

I've a ListView whose data I select and send to a DataGrid. I am having trouble with the quantity column of the DataGrid which I would want to calculate how many times a ListView item has been added to the said DataGrid (I'm currently displaying a success message when the same item is selected). I would also want to calculate the price and the quantity and display them on one column named 'price' the DataGrid.

Here is the Datagrid

 <ListView x:Name="ItemGridView" ItemsSource="{Binding Items}" SelectedItem="{Binding SelectedItem}" PreviewMouseDoubleClick="ItemGridView_PreviewMouseDoubleClick">    
     <ListView.View>
        <GridView AllowsColumnReorder="False">
           <GridViewColumn>                                                        
               <GridViewColumn.CellTemplate>
                  <DataTemplate>
                     <StackPanel HorizontalAlignment="Center" VerticalAlignment="Center" Orientation="Horizontal">
                         <Grid Margin="5">
                             <Grid.RowDefinitions>
                                 <RowDefinition Height="Auto" />
                             </Grid.RowDefinitions>
                             <Grid.ColumnDefinitions>
                                 <ColumnDefinition Width="Auto" />
                             </Grid.ColumnDefinitions>

                             <Image Source="{Binding ItemImage}" Width="225" Height="157" Stretch="UniformToFill" StretchDirection="DownOnly" />

                             <StackPanel Margin="0,100,0,0">
                               <Border Margin="-0,-7,0,0"  Height="63" Width="225" Background="{x:Null}" BorderBrush="{x:Null}" BorderThickness="0">
                                   <TextBlock Margin="8" FontWeight="Heavy" Foreground="White" FontSize="16" Text="{Binding ItemName}"/>
                               </Border>
                                <TextBlock Margin="15,-28,0,0" FontSize="15" Text="{Binding SellingPrice}" Foreground="White"/>
                             </StackPanel>
                         </Grid>                                                                    
                     </StackPanel>
                  </DataTemplate>
               </GridViewColumn.CellTemplate>
            </GridViewColumn>
         </GridView>
    </ListView.View>                                               
</ListView>

The DataGrid to which the data is sent looks like this:

<DataGrid x:Name="DGItems" ItemsSource="{Binding}" VerticalAlignment="Top" VerticalContentAlignment="Center" HorizontalContentAlignment="Center" Grid.Row="0" MinHeight="350" MaxHeight="350" ScrollViewer.CanContentScroll="True" ScrollViewer.VerticalScrollBarVisibility="Auto" ScrollViewer.HorizontalScrollBarVisibility="Auto" CanUserSortColumns="True" CanUserAddRows="False" AutoGenerateColumns="False">
    <DataGrid.Columns>
        <DataGridTextColumn MinWidth="3" Header="#" Width="Auto" Binding="{Binding RelativeSource={RelativeSource AncestorType=DataGridRow}, Converter={global:RowToIndexConverter}}" />
        <DataGridTextColumn Header="Items" Binding="{Binding ItemName}" />
        <DataGridTextColumn Header="Cost" Binding="{Binding SellingPrice}" />
        <DataGridTextColumn Header="Qty"  />           
    </DataGrid.Columns>
</DataGrid>

The code behind to send the datan following a ListView double click event is as below:

 private void ItemGridView_PreviewMouseDoubleClick(object sender, MouseButtonEventArgs e)
 {
      var selectedItem = ItemGridView.SelectedItem;

      if (!DGItems.Items.Contains(selectedItem))
      {
          DGItems.Items.Add(selectedItem);
      }
      else
      {
          utilityMethods.InformationMessage("Attempted to add item successfully");                
      }

 }

I've included screenshots to preview how the application looks just to put the question in context.

Sale Screen Screenshot

like image 345
alvinchesaro Avatar asked Oct 15 '22 04:10

alvinchesaro


1 Answers

Here's a working sample. I made slight modifications to your xaml and bindings to show how it can be done. Whenever you double-click an item in the ListView, it will update both the Quantity and Total columns in the DataGrid.

enter image description here

MyItem.cs: This is a simple model to replicate your food item

namespace UpdateQuantityColumnTest
{
    public class MyItem
    {
        public string ItemName { get; set; }
        public double SellingPrice { get; set; }
    }
}

ListViewItemViewModel.cs: This is a view model representation of your MyItem for the ListView

namespace UpdateQuantityColumnTest
{
    public class ListViewItemViewModel : ViewModelBase
    {
        public ListViewItemViewModel(MyItem model)
        {
            this.Model = model;
        }

        public MyItem Model { get; private set; }

        public string ItemName { get => this.Model.ItemName; set { this.Model.ItemName = value; OnPropertyChanged(); } }
        public string SellingPrice { get => this.Model.SellingPrice.ToString("c"); }
    }
}

DGItemViewModel: This is a slightly different view model representation of your MyItem for the DataGrid, but includes a Quantity and a TotalPrice

namespace UpdateQuantityColumnTest
{
    public class DGItemViewModel : ViewModelBase
    {
        private int quantity;

        public DGItemViewModel(MyItem model)
        {
            this.Model = model;
            this.quantity = 1; // always start at 1
        }

        public MyItem Model { get; private set; }
        public string ItemName { get => this.Model.ItemName; set { this.Model.ItemName = value; OnPropertyChanged(); } }
        public string SellingPrice { get => this.Model.SellingPrice.ToString("c"); }
        public int Quantity { get => this.quantity; set { this.quantity = value; OnPropertyChanged(); OnPropertyChanged(nameof(TotalPrice)); } }
        public string TotalPrice { get => (this.Model.SellingPrice * this.Quantity).ToString("c"); }
    }
}

ViewModelBase.cs: This is the base class that simply handles the INotifyPropertyChanged to update the UI whenever one of the property values change in your view model

using System.ComponentModel;
using System.Runtime.CompilerServices;

namespace UpdateQuantityColumnTest
{
    public class ViewModelBase : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        public void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

MainWindow.xaml: I made slight changes, mainly to your bindings so that my sample could work

<Window x:Class="UpdateQuantityColumnTest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition/>
            <RowDefinition/>
        </Grid.RowDefinitions>
        <ListView x:Name="ItemGridView" ItemsSource="{Binding Items}" SelectedItem="{Binding SelectedItem}" PreviewMouseDoubleClick="ItemGridView_PreviewMouseDoubleClick">
            <ListView.View>
                <GridView AllowsColumnReorder="False">
                    <GridViewColumn>
                        <GridViewColumn.CellTemplate>
                            <DataTemplate>
                                <StackPanel HorizontalAlignment="Center" VerticalAlignment="Center" Orientation="Horizontal">
                                    <Grid Margin="5">
                                        <Grid.RowDefinitions>
                                            <RowDefinition Height="Auto" />
                                        </Grid.RowDefinitions>
                                        <Grid.ColumnDefinitions>
                                            <ColumnDefinition Width="Auto" />
                                        </Grid.ColumnDefinitions>

                                        <Image Source="{Binding ItemImage}" Width="225" Height="157" Stretch="UniformToFill" StretchDirection="DownOnly" />
                                        <StackPanel Margin="0,100,0,0">
                                            <Border Margin="-0,-7,0,0"  Height="63" Width="225" Background="{x:Null}" BorderBrush="{x:Null}" BorderThickness="0">
                                                <TextBlock Margin="8" FontWeight="Heavy" Foreground="White" FontSize="16" Text="{Binding ItemName}"/>
                                            </Border>
                                            <TextBlock Margin="15,-28,0,0" FontSize="15" Text="{Binding SellingPrice}" Foreground="White"/>
                                        </StackPanel>
                                    </Grid>
                                </StackPanel>
                            </DataTemplate>
                        </GridViewColumn.CellTemplate>
                    </GridViewColumn>
                </GridView>
            </ListView.View>
        </ListView>
        <DataGrid x:Name="DGItems" ItemsSource="{Binding CheckoutItems}" VerticalAlignment="Top" VerticalContentAlignment="Center" HorizontalContentAlignment="Center" Grid.Row="1" MinHeight="350" MaxHeight="350" ScrollViewer.CanContentScroll="True" ScrollViewer.VerticalScrollBarVisibility="Auto" ScrollViewer.HorizontalScrollBarVisibility="Auto" CanUserSortColumns="True" CanUserAddRows="False" AutoGenerateColumns="False">
            <DataGrid.Columns>
                <DataGridTextColumn Header="Items" Binding="{Binding ItemName}" />
                <DataGridTextColumn Header="Cost" Binding="{Binding SellingPrice}" />
                <DataGridTextColumn Header="Qty"  Binding="{Binding Quantity}"/>
                <DataGridTextColumn Header="Total"  Binding="{Binding TotalPrice}"/>
            </DataGrid.Columns>
        </DataGrid>
    </Grid>
</Window>

MainWindow.xaml.cs: The code-behind that does all the work

using System.Collections.ObjectModel;
using System.Linq;
using System.Windows;
using System.Windows.Input;

namespace UpdateQuantityColumnTest
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        private ObservableCollection<ListViewItemViewModel> items;
        private ObservableCollection<DGItemViewModel> checkoutItems;

        public MainWindow()
        {
            InitializeComponent();
            this.Loaded += OnLoaded;
            this.DataContext = this;
        }

        public ObservableCollection<ListViewItemViewModel> Items
        {
            get
            {
                if (this.items == null)
                    this.items = new ObservableCollection<ListViewItemViewModel>();
                return this.items;
            }
        }

        public ObservableCollection<DGItemViewModel> CheckoutItems
        {
            get
            {
                if (this.checkoutItems == null)
                    this.checkoutItems = new ObservableCollection<DGItemViewModel>();
                return this.checkoutItems;
            }
        }

        private void OnLoaded(object sender, RoutedEventArgs e)
        {
            // Populate with dummy data
            this.Items.Add(new ListViewItemViewModel(new MyItem() { ItemName = "Beef Steak", SellingPrice = 1000 }));
            this.Items.Add(new ListViewItemViewModel(new MyItem() { ItemName = "Bacon Brie", SellingPrice = 1200 }));
            this.Items.Add(new ListViewItemViewModel(new MyItem() { ItemName = "Bread and Sausage", SellingPrice = 700 }));
        }

        private void ItemGridView_PreviewMouseDoubleClick(object sender, MouseButtonEventArgs e)
        {
            var selectedItem = ItemGridView.SelectedItem as ListViewItemViewModel;
            var checkoutItem = this.CheckoutItems.SingleOrDefault(o => o.ItemName == selectedItem.ItemName);

            if (checkoutItem == null)
            {
                this.CheckoutItems.Add(new DGItemViewModel(selectedItem.Model));
            }
            else
            {
                //utilityMethods.InformationMessage("Attempted to add item successfully");
                checkoutItem.Quantity++;
            }

        }
    }
}
like image 148
Tam Bui Avatar answered Oct 27 '22 00:10

Tam Bui