-2

I have a wpf application in C# which is used to book houses. I want to calculate the total price of a reservation. I have 2 datetimes: Check in & Check Out. The calculation I need to use = (CheckOut - CheckIn).TotalDays * BnB.Price BnB.Price is the price per night.

I want the totalprice to update live in the guest View.

Image of where totalprice is

So whenever I change the check in and out dates the total price automatically changes.

This is my Reservation Model:

    private double _totalprice { get; set; }
    private DateTime _checkIn { get; set; }
    private DateTime _checkOut { get; set; }

    public double TotalPrice
    { get => _totalprice; set { _totalprice = value; Notify("TotalPrice"); } }

    public DateTime CheckIn
    { get => _checkIn; set { if (value < _checkOut) { _checkIn = value; }; Notify("CheckIn"); } }

    public DateTime CheckOut
    { get => _checkOut; set { if (value > _checkIn) { _checkOut = value; }; Notify("CheckOut"); } }

If I missed something please let me know!

1 Answers1

0

Based on the comments in your question, BnB is a member of the reservation model. Given that, you can change TotalPrice to a readonly property, a property without a set method, and just caluclate the total in the get method. Then, in the setters for CheckIn and CheckOut, call Notify("TotalPrice") to update the UI. You also need to call Notify("TotalPrice") in the setter for BnB, since that member participates in the calculation of TotalPrice.

This assumes that the Reservation Model implements INotifyPropertyChanged and that Notify invokes the PropertyChanged event.

public class Reservation : INotifyPropertyChanged
{
    private BnB? _bnb;
    private DateTime _checkIn;
    private DateTime _checkOut;
    
    public double TotalPrice
    {
        // Instead of using a field, just calculate TotalPrice on the fly.
        get 
        {
            // Check for nulls - since _bnb is the only thing that is
            // is nullable in the calculation, it is the only thing we
            // need to check.
            if (BnB== null)
            {
                return 0;
            }
            return (CheckOut - CheckIn).TotalDays * BnB.Price;
        }
    }

    public BnB BnB
    {
        get => _bnb;
        set
        {
            if (_bnb != value)
            {
                _bnb = value;
                Notify(nameof(BnB));
                Notify(nameof(TotalPrice));
            }
        }
    }

    public DateTime CheckIn
    {
        get => _checkIn;
        set
        {
            if (value != _checkIn && value < _checkOut)
            {
                // I've changed the check to ensure that the new value isn't the
                // same as the current value. No sense running this code if nothing
                // has actually changed.
                _checkIn = value;                
            }

            // Without knowing what Notify does exactly, I can't say for sure. But
            // if it is only invoking the PropertyChanged event then these two lines
            // should probably be placed inside the if statement. There isn't any
            // point to notifying the UI that a change happened if a change didn't
            // actually happen.
            Notify(nameof(CheckIn));

            // You can notify the UI to update TotalPrice within a setter for a
            // different property.
            Notify(nameof(TotalPrice));
        }
    }

    public DateTime CheckOut
    {
        get => _checkOut;
        set
        {
            if (value != _checkOut&& value > _checkIn)
            {
                _checkOut = value;                
            }

            // These might make more sense inside the if statement as well.
            Notify(nameof(CheckOut));
            Notify(nameof(TotalPrice));
        }
    }

    // Other members of the Reservation model.
}

If you really need to have TotalPrice be a property with a getter / setter and a backing field, then just set the TotalPrice property when you set CheckIn, CheckOut, or BnB.

public class Reservation
{
    private BnB? _bnb;
    private DateTime _checkIn;
    private DateTime _checkOut;
    private double _totalPrice;

    public double TotalPrice
    {
        get => _totalPrice;
        set
        {
            if (_totalPrice != value)
            {
                _totalPrice = value;
                Notify("TotalPrice");
            }
        }
    }

    public BnB BnB
    {
        get => _bnb;
        set
        {
            if (_bnb != value)
            {
                _bnb = value;
                Notify(nameof(BnB));
                TotalPrice = CalculateTotalPrice();
            }
        }
    }

    public DateTime CheckIn
    {
        get => _checkIn;
        set
        {
            if (value != _checkIn && value < _checkOut)
            {
                // I've changed the check to ensure that the new value isn't the
                // same as the current value. No sense running this code if nothing
                // has actually changed.
                _checkIn = value;                
            }

            // Without knowing what Notify does exactly, I can't say for sure. But
            // if it is only invoking the PropertyChanged event then these two lines
            // should probably be placed inside the if statement. There isn't any
            // point to notifying the UI that a change happened if a change didn't
            // actually happen.
            Notify(nameof(CheckIn));

            // You can notify the UI to update TotalPrice within a setter for a
            // different property.
            TotalPrice = CalculateTotalPrice();
        }
    }

    public DateTime CheckOut
    {
        get => _checkOut;
        set
        {
            if (value != _checkOut&& value > _checkIn)
            {
                _checkOut = value;                
            }

            // These might make more sense inside the if statement as well.
            Notify(nameof(CheckOut));
            TotalPrice = CalculateTotalPrice();
        }
    }

    private double CalculateTotalPrice()
    {
        if (BnB== null)
        {
            return 0;
        }
        return (CheckOut - CheckIn).TotalDays * BnB.Price;
    }

    // Other members of the Reservation model.   
}

Also, on a side note you might want to consider switching from double to decimal to represent currency.

Joshua Robinson
  • 3,399
  • 7
  • 22
  • You have to check for `null` in the `TotalPrice` getter and return an appropriate value, such as `0`, if any of the members participating in the calculation are `null`. I've updated the answer to account for this, and added an example of what to do if you really want a property with a get/set and a backing field for `TotalPrice`. – Joshua Robinson Apr 21 '22 at 15:56
  • I made the column table nullable so it kinda works now. the problem I now have is the incorrect date. it shows a date of 1-1-0001 instead of todays date. whenever adding a new reservation the default date is todays date. CheckOut = DateTime.Today. Here is a link to an image showing the problem: https://ibb.co/nD8p1gG – Abdullah Altun Apr 21 '22 at 15:59
  • It looks like you're setting `CheckOut = DateTime.Today` but `CheckIn` to `default(DateTime)` or `DateTime.MinValue`, but I don't know because I can't see the code where you're setting them. You need to set `CheckIn` to an appropriate value when you create a new reservation. – Joshua Robinson Apr 21 '22 at 16:06