Reputation: 135
I'm a beginner learning Windows Forms Applications in C# and I want to write a program that will prompt the user to enter the name of a place and to enter 2 digit temperature (F) between ranges 20 and 100. When the user presses the "OK" button on the form I want to have a messagebox displaying the name of the place they entered, and the temperature (F) they entered plus its Celsius conversion and an error message in case any of the fields is left blank or if the temp falls beyond the range.
I would like to have a class to handle the conversion and the logic.
I'm still learning guys and I've spent all day on this already only getting a few pieces of code working but I'm afraid I'm not understanding what I'm doing. I'm ok with the form design, what I have an issue with, is the c# code and using classes. I'd really appreciate if someone could show me code or good hints for what I want to do.
For your sake I'm not including my code because it may confuse you then we'll spend hours talking about "why did I do something" but if you really want to see it let me know.
Being a beginner I'd much appreciate beginner-like answers. Thank you guys !
// Form1.cs
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace airports
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void textBox1_TextChanged(object sender, EventArgs e)
{
}
private void label2_Click(object sender, EventArgs e)
{
}
private void label3_Click(object sender, EventArgs e)
{
}
private void btn_quit_Click(object sender, EventArgs e)
{
base.Close();
return;
}
public void btn_record_Click(object sender, EventArgs e)
{
string place;
place = Console.ReadLine();
Calculations name = new Calculations();
//double temp = Convert.ToDouble(txtTemperature.Text);
//Calculation ctemp = new Calculation();
MessageBox.Show(name.GetPlaceName("Calculations: " + txtPlaceName.Text));
//MessageBox.Show(string.Format("Temperature: {0}", (ctemp.GetTemp(celsiusTemp.text))));
}
//Class
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace Calculations
{
class Calculations
{
string placeName;
double celsiusTemp;
public string GetPlaceName(string place)
{
return placeName = place;
}
public double GetTemp(double temp)
{
return celsiusTemp = (temp + 10);
}
}
}
Upvotes: 1
Views: 1340
Reputation: 101184
What you need to do is to take a step back and just ignore the whole WinForms problem. Try to solve the specific problem first:
I want to write a program that will prompt the user to enter the name of a place and to enter 2 digit temperature (F) between ranges 20 and 100. When the user presses the "OK" button on the form I want to have a messagebox displaying the name of the place they entered, and the temperature (F) they entered plus its Celsius conversion and an error message in case any of the fields is left blank or if the temp falls beyond the range.
What could be breaken down into two different problems:
The validation is something that always should be done, so I don't consider it as a separate problem.
The next thing to do is to think about how you want the solution to work. Always start with the solution, since it's often easier than trying to create the implementation directly. Test Driven Development is really great since it does just that.
I would want something like this (pseudo code):
var fahrenheit = dialog.GetInput();
var celcius = fahrenheit.Convert(new FahrenheitToCelciusConverter());
resultDialog.Show(fahrenheit, celsius);
Defining objects
Now since we know what we want to do, lets focus more on the actual implementation. By looking at the pseudo-code we've identified that we need a couple of classes.
First of all, we need to get the input
// the validation should be done in this form when the user
// presses OK. But that's up to you to figure out
public class PlaceAndTemperatureForm : Form
{
public PlaceAndTemperature GetPlaceAndTemperature()
{
return new PlaceAndTemperature(txtName.Text, int.Parse(txtTemperature .Text));
}
}
And since we need to get the data from the form, lets create a class to contain it:
public class PlaceAndTemperature
{
public PlaceAndTemperature(string name, int temperature)
{
Name = name;
Temperature = temperature;
}
public string Name { get; private set; }
public int Temperature { get; private set; }
}
Look at the class above. It has private setters which means that no other class or code can modify it. It's called immutable objects. The good thing is that we know that it's always safe to use and cannot be in an unexpected/invalid state. You should always try to have immutable objects, or at least not let any other objects change the state without having the class itself validate the changes.
Next up is the conversion. We wrote the following code:
var celcius = placeAndTempature.Convert(new FahrenheitToCelciusConverter());
Hence we need to modify the class to take a converter and return a new place.
public class PlaceAndTemperature
{
public PlaceAndTempature(string name, int temperature)
{
Name = name;
Temperature = temperature;
}
public string Name { get; private set; }
public int Temperature { get; private set; }
public PlaceAndTemperature Convert(ITemperatureConverter converter)
{
return new PlaceAndTemperature(Name, converter.Convert(Temperature));
}
}
I've just introduced a new concept called Interfaces. You can look at them as word templates or a blue print. They are there to define how a class should look like, but not to have any logic. It's a specification.
public interface ITemperatureConverter
{
int Convert(int source);
}
The problem now is that we have two PlaceAndTemperature objects, the original one with fahrenheit and one with celcius. We need to be able to identify which kind of unit is used, or we'll probably end up with some nasty bugs later on.
Lets add a unit specification using an enum
.
public enum TempatureUnit
{
Celcius,
Fahrenheit
}
And modify the previous classes and interfaces:
public interface ITemperatureConverter
{
int Convert(int source);
TempatureUnit SourceUnit {get;}
TempatureUnit TargetUnit {get;}
}
public class PlaceAndTemperature
{
public PlaceAndTempature(string name, int temperature, TempatureUnit unit)
{
Name = name;
Temperature = temperature;
TempatureType = unit;
}
public string Name { get; private set; }
public int Temperature { get; private set; }
public TempatureUnit TemperatureType {get; private set; }
public PlaceAndTemperature Convert(ITemperatureConverter converter)
{
return new PlaceAndTemperature(Name, converter.Convert(Temperature), converter.TargetUnit);
}
}
Putting it all together
Great. Not much left now. Let's revisit the original code and update it:
public void Button1_Click(object source, EventArgs e)
{
var form = new PlaceAndTemptureForm();
var result = form.ShowDialog(this);
if (result != DialogResult.Ok)
return; // failed for some reason
var fahrenheit = form.GetPlaceAndTemperature();
var celcius = fahrenheit .Convert(new FahrenheitToCelciusConverter());
var form = new ResultForm();
form.SetTemperatures(fahrenheit, celsius);
resultDialog.ShowDialog(this);
}
Summary
There is still some things that you need to fix yourself. Like creating the FahrenheitToCelciusConverter. Start with something like:
public class FahrenheitToCelciusConverter : ITemperatureConverter
{
public int Convert(int source)
{
// put your code here
}
public TempatureUnit SourceUnit {get { return TemperatureUnit.Fahrenheit; }}
public TempatureUnit TargetUnit {get { return TemperatureUnit.Celcius; }}
}
And you'll also need to create the result form, or simply update the main form.
Upvotes: 8
Reputation: 1064044
at this point in Form1.cs I get " 'celciusTemp' does not exist in the current context"
OK; now we're getting somewhere. celciusTemp
is indeed part of Calculations
, not Form1
, but that shouldn't really impact us, as we already have the temperature:
double temp = Convert.ToDouble(txtTemperature.Text);
(I assume txtTemperature
exists)
The problem seems to be not using temp
in the later call:
MessageBox.Show(string.Format("Temperature: {0}", ctemp.GetTemp(temp)));
(note the above uses temp
, not celsiusTemp
)
As asides, I'm not sure it is necessary to store placeName
and celsiusTemp
as fields on the Calculations
class; they could be static methods, unless there is more detail to add. But that is unrelated to the primary issue here.
Upvotes: 1