1

I am working on WPF Windows application. I am using ListBox to view/edit the content. In that I am doing calculation stuff. So I want that If I change the value of one Item it automatic change the calculation without adding extra buttons to regenerate it.

<ListBox ItemsSource="{Binding CustomSalesProducts, Mode=TwoWay}" HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch">
        <ItemsControl.Template>
            <ControlTemplate TargetType="ItemsControl">
                <Border>
                    <ScrollViewer VerticalScrollBarVisibility="Auto">
                        <ItemsPresenter/>
                    </ScrollViewer>
                </Border>
            </ControlTemplate>
        </ItemsControl.Template>
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <VirtualizingStackPanel CanHorizontallyScroll="True" CanVerticallyScroll="True" Orientation="Vertical"/>
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <Grid x:Name="SalesGrid" Background="White">
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="Auto"/>
                        <ColumnDefinition Width="Auto"/>
                        <ColumnDefinition Width="Auto"/>
                        <ColumnDefinition Width="Auto"/>
                        <ColumnDefinition Width="Auto"/>
                        <ColumnDefinition Width="Auto"/>
                    </Grid.ColumnDefinitions>
                    <Grid.RowDefinitions>
                        <RowDefinition Height="Auto"/>
                        <RowDefinition Height="Auto"/>
                        <RowDefinition Height="Auto"/>
                    </Grid.RowDefinitions>
                    <controls:HeaderedContentControl Header="{Binding ProductName, Mode=TwoWay}" Margin="{DynamicResource Margin4}" Style="{DynamicResource HeaderedContentControlStyle}" HorizontalContentAlignment="Right">
                    </controls:HeaderedContentControl>
                    <TextBox Text="{Binding OrderQty, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Grid.Row="1" Margin="{StaticResource Margin4}" Style="{DynamicResource MiniTextBoxStyle}" ToolTip="Quantity" />
                    <TextBlock Text="{Binding UnitSalePrice, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Grid.Column="1" Grid.Row="1" Margin="{StaticResource Margin4}" ToolTip="Price"/>
                    <TextBox Text="{Binding Discount, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Grid.Column="2" Grid.Row="1" Margin="{StaticResource Margin4}" Style="{DynamicResource MiniTextBoxStyle}" ToolTip="Discount"/>
                    <TextBlock Text="{Binding TaxAmount, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Grid.Column="3" Grid.Row="1" Margin="{StaticResource Margin4}" ToolTip="Tax Amount"/>
                    <TextBlock Text="{Binding LineTotal, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Grid.Column="4" Grid.Row="1" Margin="{StaticResource Margin4}" ToolTip="Total"/>

                </Grid>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ListBox>

Edit:

I tried trigger but it doesnt work in the listbox

like:

<TextBox Text="{Binding OrderQty, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Margin="{StaticResource Margin4}" Style="{DynamicResource MiniTextBoxStyle}" ToolTip="Quantity" >
                            <i:Interaction.Triggers>
                                <i:EventTrigger EventName="LostFocus">
                                    <i:InvokeCommandAction Command="{Binding RefreshProduct}"/>
                                </i:EventTrigger>
                            </i:Interaction.Triggers>
                        </TextBox>

Thanks

R76
  • 446
  • 6
  • 25

1 Answers1

1

So this is what I suggest:

  • Make sure your Model class (e.g. CustomSalesProduct) is implementing INotifyPropertyChanged interface.
  • When your OrderQty property value changes (e.g. When user types another qty amount in TextBox) then call your method to calculate total in the Property Set. This will automatically refresh your LineTotal value in the View.

EDIT: If you decide to use the MVVM Design Pattern then:

Create a ViewModel class like:

public class CustomSalesViewModel
{
   public ObservableCollection<CustomSalesProduct> CustomSalesProducts {get;set;}

   public CustomSalesViewModel()
  {
    //Initialize your collection in constructor
    CustomSalesProducts = new ObservableCollection<CustomSalesProduct>();
    //Populate list
    CustomSalesProducts.Add(new CustomSalesProduct(){....});
    //.... Add rest of items
  }
}

Then set the DataContext of your View to an instance of your CustomSalesViewModel. You can do that in the Constructor of the code-behind of your View (XAML) like:

DataContext = new CustomSalesViewModel();

Here the sample class:

public class CustomSalesProduct : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        private int _orderQty;

        public int OrderQty
        {
            get { return _orderQty; }
            set
            {
                _orderQty = value;
                OnPropertyChanged("OrderQty");
                CalcTotal();
            }
        }

        private double _unitSalePrice;

        public double UnitSalePrice
        {
            get { return _unitSalePrice; }
            set
            {
                _unitSalePrice = value;
                OnPropertyChanged("UnitSalePrice");
            }
        }

        private double _discount;

        public double Discount
        {
            get { return _discount; }
            set
            {
                _discount = value;
                OnPropertyChanged("Discount");
            }
        }

        private double _taxAmount;

        public double TaxAmount
        {
            get { return _taxAmount; }
            set
            {
                _taxAmount = value;
                OnPropertyChanged("TaxAmount");
            }
        }

        private double _lineTotal;

        public double LineTotal
        {
            get { return _lineTotal; }
            set
            {
                _lineTotal = value;
                OnPropertyChanged("LineTotal");
            }
        }

        private string _productName;

        public string ProductName
        {
            get { return _productName; }
            set
            {
                _productName = value;
                OnPropertyChanged("ProductName");
            }
        }

        public void CalcTotal()
        {
            LineTotal = OrderQty*UnitSalePrice*(1 - Discount);
        }

        protected void OnPropertyChanged(string name)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(name));
            }
        }
    }
Community
  • 1
  • 1
Adolfo Perez
  • 2,834
  • 4
  • 41
  • 61
  • But in this i'll get the collection e.g(customSaleProduct ) is a collection object. Then how can I find the Updated object in this. – R76 Jun 11 '12 at 03:04
  • 1
    Your View (ListBox XAML) will be bound to a ViewModel that exposes a Collection property of type CustomSaleProduct. When you change the ItemQty in the ListBox then Property Set of OrderQty property in the Model (CustomSaleProduct) will fire. There you can call your method to Calculate Total. If you need to track updates you could add a boolean (e.g. HasChanged) property to your CustomSaleProduct and set it to true when something changed. – Adolfo Perez Jun 11 '12 at 11:39
  • If you follow my advice and you don't need any other thing than automatically re-calculating on OrderQty modification that's all you need to do. WPF Two-Way binding will take care of everything :) – Adolfo Perez Jun 11 '12 at 12:15