0

I have created a SubPODetailView.xaml that includes a SubPoDetailViewModel.cs, which in turn this Model contain a SubInvoice.cs for a datagrid and the SubPO.cs for other details. What I wnat is every time I added a row, the sum of "Amount" columns displayed in the total TextBlock.

The Screenshot of View Page of running Program

SubPODetailView.xaml

<DataGrid ItemsSource="{Binding Invoices}" 
            SelectedItem="{Binding SelectedInvoice,Mode=TwoWay}"
            AutoGenerateColumns="False" RowHeaderWidth="0" >
            
            <DataGrid.Columns>
                <DataGridTextColumn Header="Invoices" Width="*"
                Binding="{Binding InvoiceName,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"/>

            <DataGridTemplateColumn Header="Date" Width="*">
                    <DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                            <DatePicker SelectedDate="{Binding Date,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" />
                        </DataTemplate>
                    </DataGridTemplateColumn.CellTemplate>
            </DataGridTemplateColumn>

            <DataGridTextColumn Header="Amount" Width="*" Binding="{Binding Amount,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"/>

            <DataGridTemplateColumn Header="Status" Width="*">
                    <DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                            <ComboBox ItemsSource="{Binding Status,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" />
                        </DataTemplate>
                    </DataGridTemplateColumn.CellTemplate>
                </DataGridTemplateColumn>
            </DataGrid.Columns>
            
        </DataGrid>

                <TextBlock Text="{Binding Total}" Margin="10,0" Background="#FFC9CD7D" Foreground="Black"/>

SubPODetailViewModel.cs

public class SubPODetailViewModel : DetailViewModelBase, ISubPODetailViewModel
{
    private ISubPORepository _subPORepository;
    private IMessageDialogService _messageDialogService;
    private SubPOWrapper _subPO;
    private SubInvoiceWrapper _selectedInvoice;

    public SubPODetailViewModel(IEventAggregator eventAggregator,
        IMessageDialogService messageDialogService,
        ISubPORepository subPORepository) : base(eventAggregator)
    {
        _subPORepository = subPORepository;
        _messageDialogService = messageDialogService;

        AddInvoiceCommand = new DelegateCommand(OnAddInvoiceExecute);
        RemoveInvoiceCommand = new DelegateCommand(OnRemoveInvoiceExecute, OnRemoveInvoiceCanExecute);

        Invoices = new ObservableCollection<SubInvoiceWrapper>();

    }
// SubPOWrapper for SubPO.cs class
    public SubPOWrapper SubPO
    {
        get { return _subPO; }
        private set
        {
            _subPO = value;
            OnPropertyChanged();
        }
    }

// SubInvoiceWrapper for SubInvoice.cs class
    public SubInvoiceWrapper SelectedInvoice
    {
        get { return _selectedInvoice; }
        set
        {
            _selectedInvoice = value;
            OnPropertyChanged();
            ((DelegateCommand)RemoveInvoiceCommand).RaiseCanExecuteChanged();
        }
    }

    public ICommand AddInvoiceCommand { get; }
    public ICommand RemoveInvoiceCommand { get; }
    public ObservableCollection<SubInvoiceWrapper> Invoices { get; }

    public override async Task LoadAsync(int? subPOId)
    {
        var subPO = subPOId.HasValue
            ? await _subPORepository.GetByIdAsync(subPOId.Value)
            : CreateNewSubPO();
        InitializeSubPO(subPO);
        InitializeSubInvoice(subPO.Invoices);
    }

    private SubPO CreateNewSubPO()
    {
        var subPO = new SubPO();
        _subPORepository.Add(subPO);
        return subPO;
    }

    private void InitializeSubInvoice(ICollection<SubInvoice> invoices)
    {
        foreach (var wrapper in Invoices)
        {
            wrapper.PropertyChanged -= SubInvoiceWrapper_PropertyChanged;
        }
        Invoices.Clear();
        foreach (var subInvoice in invoices)
        {
            var wrapper = new SubInvoiceWrapper(subInvoice);
            Invoices.Add(wrapper);
            wrapper.PropertyChanged += SubInvoiceWrapper_PropertyChanged;
        }
    }

    private void SubInvoiceWrapper_PropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        if (!HasChanges)
        {
            HasChanges = _subPORepository.HasChanges();
        }
        if (e.PropertyName == nameof(SubInvoiceWrapper.HasErrors))
        {
            ((DelegateCommand)SaveCommand).RaiseCanExecuteChanged();
        }
    }

    private void InitializeSubPO(SubPO subPO)
    {
        SubPO = new SubPOWrapper(subPO);
        SubPO.PropertyChanged += (s, e) =>
        {
            if (!HasChanges)
            {
                HasChanges = _subPORepository.HasChanges();
            }
            if (e.PropertyName == nameof(SubPO.HasErrors))
            {
                ((DelegateCommand)SaveCommand).RaiseCanExecuteChanged();
            }
        };
        ((DelegateCommand)SaveCommand).RaiseCanExecuteChanged();
        if (SubPO.Id == 0)
        {
            // Little trick to trigger the validation
            SubPO.Title = "";
        }
    }

    protected override void OnDeleteExecute()
    {
        var result = _messageDialogService.ShowOkCancelDialog($"Do you really want to delete the Subcontractor {SubPO.Title}?", "Question");
        if (result == MessageDialogResult.OK)
        {
            _subPORepository.Remove(SubPO.Model);
            _subPORepository.SaveAsync();
            RaiseDetailDeletedEvent(SubPO.Id);
        }
    }

    protected override bool OnSaveCanExecute()
    {
        return SubPO != null
           && !SubPO.HasErrors
           && Invoices.All(i=>!i.HasErrors)
           && HasChanges;
    }

    protected override async void OnSaveExecute()
    {
        await _subPORepository.SaveAsync();
        HasChanges = _subPORepository.HasChanges();
        RaiseDetailSavedEvent(SubPO.Id, SubPO.Title);
    }

    private void OnAddInvoiceExecute()
    {
        var newInvoice = new SubInvoiceWrapper(new SubInvoice());
        newInvoice.PropertyChanged += SubInvoiceWrapper_PropertyChanged;
        Invoices.Add(newInvoice);
        SubPO.Model.Invoices.Add(newInvoice.Model);
        //newInvoice.InvoiceName = "";
        newInvoice.Date = DateTime.Now.Date;
        // Trigger validation :-) 
    }

    private void OnRemoveInvoiceExecute()
    {
        SelectedInvoice.PropertyChanged -= SubInvoiceWrapper_PropertyChanged;
        _subPORepository.RemoveInvoice(SelectedInvoice.Model);
        Invoices.Remove(SelectedInvoice);
        SelectedInvoice = null;
        HasChanges = _subPORepository.HasChanges();
        ((DelegateCommand)SaveCommand).RaiseCanExecuteChanged();
    }

    private bool OnRemoveInvoiceCanExecute()
    {
        return SelectedInvoice !=null;
    }
}
}

Note: for checking the whole program as zip file, here you go(just click slow dowload then continue): http://www.filefactory.com/file/681du53ow7us/SubBVZip.zip

Update

Screenshot of the problem I got when running the program, How to sum the rows without adding another new one.

Maya
  • 59
  • 6

1 Answers1

0

The last TextBlock of SubPODetailView is already bound to Total property in view model. Create the property Total on view model and add CollectionChanged handler to Invoices:

public SubPODetailViewModel(IEventAggregator eventAggregator,
    IMessageDialogService messageDialogService,
    ISubPORepository subPORepository) : base(eventAggregator)
   {
        ...
        Invoices.CollectionChanged += Invoices_CollectionChanged;
    }

    private void Invoices_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
    {
        Total = Invoices.Sum(x => x.Amount);
    }

    private decimal _total;
    public decimal Total
    {
        get => _total;
        set {
            _total = value;
            OnPropertyChanged();
        }
    }
  • it works but I have a small problem, I added an update to the question for that problem, can you check it, please? Thanks. – Maya Dec 06 '20 at 06:02
  • @Macro Segurini, also I updated the SubPODetailViewModel.cs class that includes code for save button, we may add command to save code, once adding new row then user click save button, after that the sum comes up. – Maya Dec 06 '20 at 19:50
  • for the update you may try https://stackoverflow.com/a/50930262/9714619 – Marco Segurini Dec 07 '20 at 19:13