So.. How do i validate a private instance variable (field) with a property inside of a constructor?
I have this code that works, but I have a strong feeling this is not how it is supposed to be done:
class Account
{
private decimal acctBalance = 0;
public decimal AcctBalance
{
get
{
return acctBalance;
}
set
{
if (acctBalance >= 0)
acctBalance = value;
else
{
Console.WriteLine("Invalid balance, balance set to 0");
acctBalance = 0;
}
}
}
public Account(decimal balance)
{
acctBalance = balance;
AcctBalance = acctBalance;
}
}
I just want to make sure that this is the correct way to do it
thanks!
Your approach is mostly right, although there are a couple of issues. I fixed them and annotated the code with comments where I did.
class Account
{
private decimal acctBalance = 0;
public decimal AcctBalance
{
get
{
return acctBalance;
}
set
{
//modified to check value instead of acctBalance
if (value >= 0)
acctBalance = value;
else
{
Console.WriteLine("Invalid balance, balance set to 0");
acctBalance = 0;
}
}
}
public Account(decimal balance)
{
//redundant! Changing AcctBalance changes acctBalance
//acctBalance = balance;
AcctBalance = balance;
}
}
Related
I have the following business logic:
public decimal Price
{
get {
if (OrderSize == Size.Small)
{
_price = decimal.Multiply(_price, (decimal)0.8);
}
else if (OrderSize == Size.Large)
{
_price = decimal.Multiply(_price, (decimal)1.2);
}
return _price;
}
set {
_price = value;
}
}
The price should be only changed once based on the chosen OrderSize. When this order is retrieved it calculates the price again which is obviously not what i want. What is the best way to make this only execute once?
You're not far off. Don't assign the _price variable again, just return the calculation.
public decimal Price
{
get
{
if (OrderSize == Size.Small)
{
return decimal.Multiply(_price, (decimal)0.8);
}
else if (OrderSize == Size.Large)
{
return decimal.Multiply(_price, (decimal)1.2);
}
else
{
return _price;
}
}
set
{
_price = value;
}
}
I am using DataAnnotations for validation of my ViewModel (WPF) so I can control the enable state of some buttons if the user type in a something that is not a float and if the value is outside of a range.
[Range(0, float.MaxValue, ErrorMessage = "StepSize must be more than 0")]
public float StepSize
{
get { return model.StepSize; }
set
{
model.StepSize = value;
RaisePropertyChangedAndRevalidate(nameof(StepSize));
}
}
private void RaisePropertyChangedAndRevalidate(string propertyName)
{
RaisePropertyChanged(propertyName);
if (_fieldBindingErrors == 0)
{
RaisePropertyChanged(nameof(IsValid));
}
}
private int _fieldBindingErrors = 0;
public ICommand RegisterFieldBindingErrors
{
get
{
return new RelayCommand<ValidationErrorEventArgs>(e =>
{
if (e.Action == ValidationErrorEventAction.Added)
{
_fieldBindingErrors++;
}
else
{
_fieldBindingErrors--;
}
RaisePropertyChanged(nameof(IsValid));
});
}
}
public bool IsValid
{
get
{
bool valid = Validator.TryValidateObject(this,
new ValidationContext(this, null, null),
new List<System.ComponentModel.DataAnnotations.ValidationResult>())
&& _fieldBindingErrors == 0;
return valid;
}
}
Problem is, when I convert the the textbox.Text string to a float I have to set the value to something not valid (should work for general cases also when the Range attribute is not in use). So I set the value to float.NaN.
The problem is that NaN seems to be a valid float, and it even passes the Range validation above.
Is there an attribute I could use to validate that the value is not NaN?
Found a solution, I created a custom validation rule instead and applied it in the XAML.
class StepSizeValidationRule : ValidationRule
{
private int _min;
private int _max;
public StepSizeValidationRule()
{
}
public int Min
{
get { return _min; }
set { _min = value; }
}
public int Max
{
get { return _max; }
set { _max = value; }
}
public override ValidationResult Validate(object value, CultureInfo cultureInfo)
{
float stepSize = 0;
try
{
if (!float.TryParse(value.ToString(), out stepSize))
{
return new ValidationResult(false, "Not a float");
}
}
catch (Exception e)
{
return new ValidationResult(false, "Not a float " + e.Message);
}
if (float.IsNaN(stepSize))
{
return new ValidationResult(false, "Not a float ");
}
if ((stepSize < Min) || (stepSize > Max))
{
return new ValidationResult(false,
"Please enter a stepSize in the range: " + Min + " - " + Max + ".");
}
else
{
return new ValidationResult(true, null);
}
}
}
I'm getting the error:
cannot implicitly convert type decimal to string
when I'm setting the value for a property and I'm not sure how to remedy this.
There are two forms. I'm passing information from one form to the other to display it. The error is in Form Price
Form (Calculator):
public partial class Calculator : Form
{
decimal dorm = 0;
decimal meal = 0;
public Calculator()
{
InitializeComponent();
}
public decimal _price
{
get { return _price; }
}
private void getPriceButton_Click(object sender, EventArgs e)
{
decimal price = 0;
getInput();
price = dorm + meal;
Price myPrice = new Price();
myPrice._priceLabel = _price;
myPrice.ShowDialog();
}
private void getInput()
{
if(allenRadioButton.Checked)
{
dorm = 1500;
}
if(pikeRadioButton.Checked)
{
dorm = 1600;
}
if(farthingRadioButton.Checked)
{
dorm = 1800;
}
if(universityRadioButton.Checked)
{
dorm = 2500;
}
if(sevenRadioButton.Checked)
{
meal = 600;
}
if(fourteenRadioButton.Checked)
{
meal = 1200;
}
if(unlimitedRadioButton.Checked)
{
meal = 1700;
}
}
Form (Price):
public partial class Price : Form
{
public Price()
{
InitializeComponent();
}
public decimal _priceLabel
{
set { priceLabel.Text = value; } // error
}
priceLabel.Text = price.ToString("c"); //this is messed up too
}
}
You cannot assign a String value to decimal. You need to convert it.
Try this:
public decimal _priceLabel
{
set { priceLabel.Text = decimal.Parse(value); } // error
}
You can use the Convert helper class defined here:
Convert
Takes a string and converts to the decimal value
For reverse try
Convert.ToString(decimalValue) Convert
So this is what the final product needs to look like.
I have to use a getter and setter which I don't really understand how to use.
Once the User hits Calc Payroll it will show up in the listbox to the right, and then when the user clicks show list, the label down below will update with just the name and the gross pay.
private void calcButton_Click(object sender, EventArgs e)
{
double rate = 0;
double hours = 0;
double withhold = 0;
if (this.nameTextBox.Text != "")
{
infoListBox.Items.Add("Name: " + this.nameTextBox.Text);
}
if (this.hoursTextBox.Text != "")
{
infoListBox.Items.Add("Hours: " + this.hoursTextBox.Text);
}
if(this.rateTextBox.Text != "")
{
infoListBox.Items.Add("Rate: " + this.rateTextBox.Text);
}
if (this.withHoldingTextBox.Text != "") ;
{
infoListBox.Items.Add("Withholding Amount: " + this.withHoldingTextBox.Text);
}
}
}
}
So basically I just printed all the information from the user to the list box
here is the new class so far
class Employees
{
//Fields
private double _hours;
private double _rate;
private double _withhold;
private string _name;
// Constructor
public Employees(double rate, double hours, double withhold, string name)
{
_hours = hours;
_rate = rate;
_withhold = withhold;
_name = name;
}
//Rate Property
public double rate
{
get { return _rate; }
set { _rate = value; }
}
public double hours
{
get { return _hours; }
set { _hours = value; }
}
public double withhold
{
get { return _withhold; }
set { _withhold = value; }
}
//get gross pay
public double grosspay
{
get { return _hours * _rate + _withhold; }
}
}
}
Try to bind your Properties (getter and setter) to the content of your controls.
Like this:
private string name;
public string Name
{
get { return name; }
set { name = value; }
}
And in your xaml code you use:
<Label Name="Name" Content="{Binding Name}" />
you have to bind the name of your property in the content as shown above.
If you need more information about Databinding look here:
http://www.codeproject.com/Articles/140621/WPF-Tutorial-Concept-Binding
In this context, you may have a look at the MVVM-Pattern:
http://www.codeproject.com/Articles/100175/Model-View-ViewModel-MVVM-Explained
Let me know if this helps you!
I have a question. How can i validate my price in property to be positive number, else to throw a new exception.
I have already tried it that way, but still doesn't work:
public decimal Price
{
get
{
{ return this.price; }
}
set
{
if (this.price < 0)
{
throw new ArgumentException("The price should be positive!");
}
else
{
this.price = value;
}
}
}
Now i see, you are checking against the backing field in the setter of the property which has the last value or the default value 0 if it was not yet initialized. Use the value instead:
private decimal price;
public decimal Price
{
get
{
{ return this.price; }
}
set
{
if (value < 0)
{
throw new ArgumentException("The price should be positive!");
}
else
{
this.price = value;
}
}
}
The part this.price is the current value. You need to check the value that is passed in the setter using the value variable.
public decimal Price
{
get
{
{ return this.price; }
}
set
{
if (value < 0)
{
throw new ArgumentException("The price should be positive!");
}
else
{
this.price = value;
}
}
}