I have created a simple calculator using VS 2013 Pro... and here is the segment of the codes:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace CalcTwo
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
string input = string.Empty;
double numb1, numb2, result;
private void button1_Click(object sender, EventArgs e)
{
double.TryParse(textBox1.Text, out numb1);
double.TryParse(textBox2.Text, out numb2);
result = numb1 + numb2;
textBox3.Text = result.ToString();
}
private void button4_Click(object sender, EventArgs e)
{
double.TryParse(textBox1.Text, out numb1);
double.TryParse(textBox2.Text, out numb2);
result = numb1 - numb2;
textBox3.Text = result.ToString();
}
}
}
now the problem I'm facing is, I've got two more buttons for multiplying and dividing, which in turn forces me to copy paste
double.TryParse(textBox1.Text, out numb1);
double.TryParse(textBox2.Text, out numb2);
for each button. I tried to put the codes with the other variables(double numb1, numb2, result) but getting an error...
Here is the screenshots
Pretty new to Visual Studio and C#.
Help is appreciated! :)
The declaration of the variables is fine at the class level. However, in order to reduce the code duplication you can extract that specific functionality into its own method. Something like this perhaps:
private void CaptureValues()
{
double.TryParse(textBox1.Text, out numb1);
double.TryParse(textBox2.Text, out numb2);
}
Then in the handlers:
private void button1_Click(object sender, EventArgs e)
{
CaptureValues();
result = numb1 + numb2;
textBox3.Text = result.ToString();
}
This gives you a convenient place to put additional code. Checking the inputs and displaying a message, for example:
private void CaptureValues()
{
if (!double.TryParse(textBox1.Text, out numb1))
// textBox1 couldn't be parsed, show an error message
if (!double.TryParse(textBox2.Text, out numb2))
// textBox2 couldn't be parsed, show an error message
}
You could even go a step further and put the values into class-level properties. Something like this:
private double Value1
{
get
{
double result;
if (!double.TryParse(textBox1.Text, out result))
throw new Exception("Couldn't parse the first text box!");
return result;
}
}
private double Value2
{
get
{
double result;
if (!double.TryParse(textBox2.Text, out result))
throw new Exception("Couldn't parse the second text box!");
return result;
}
}
With those, you don't need your numb1 or numb2 variables at all, just reference the properties directly:
textBox3.Text = (Value1 + Value2).ToString();
Currently the properties can throw exceptions, so you might want to handle that:
try
{
textBox3.Text = (Value1 + Value2).ToString();
}
catch (Exception ex)
{
// examine what happened with ex and show an error
}
You can throw a more specific Exception type of course, even a custom one. Or you can respond to the error in the properties instead of in the handlers and not use exceptions at all. (There's an argument to be made, and I agree with it, never to use exceptions for normal logic, and this is potentially one of those edge cases. If it's normal logic, don't use exceptions. If it's an exceptional case and the value should never be un-parseable, go ahead and use them. I'd prefer not to in this case, but was just adding it as a possibility.)
There are a lot of options.
Related
I wrote a small WF program which caculates some condensators and the ohmic law. I now want to tidy up a little bit. I ran across a issue where I use 2 doubles which both got assigned the value 0. I can remove the value from the voltage double. But not the current one. And I can't figure out why. Is there anything I am missing? Error Message is CS0165 Use of unassigned local variable 'current' and occurs in the line where the CalcResistance Method gets called
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Kondensator_Ohmsches_Gesetz_Calc
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void calcResistance_Click(object sender, EventArgs e)
{
double voltage;
double current;
bool ok = double.TryParse(textBox1.Text, out voltage) && double.TryParse(textBox2.Text, out current);
if (ok)
{
textBox3.Text = Formulacollection.CalcResistance(voltage, current);
}
else
{
textBox3.Text = "Error Format not found";
}
textBox4.Text = Formulacollection.ConvertMicro(textBox3.Text);
textBox5.Text = Formulacollection.ConvertMilli(textBox3.Text);
textBox6.Text = Formulacollection.ConvertKilo(textBox3.Text);
textBox7.Text = Formulacollection.ConvertMega(textBox3.Text);
}
}
Formulacollection Class works like this:
using System;
using System.Collections.Generic;
using System.Text;
using static System.Math;
using System.Numerics;
using System.Globalization;
namespace Kondensator_Ohmsches_Gesetz_Calc
{
public static class Formulacollection
{
public static string CalcResistance(double voltage, double current)
{
var resistance = voltage / current;
return resistance.ToString();
}
}
The second part won't always be evaluated when you use the && operator. Try to use & instead of it, or set a default value to current when you declare it.
Firstly CS0165 is the error occurs when using the uninitialized variable.
But here the error occurs for the variable current which is initialized correctly. The brief about the error is here
So try the variable initialization globally in the class and then try to compile it.
Then there is a probability of the ok variable holding the value of two TryParse simultaneously, and also replace the && with &.
I am building a program in C# to be used in one of my course at a college to demonstrate how Asynchronous connections work using RS-232 and two computers connected together. My course is not about programming, but data networks, so the connectivity is what I am looking for.
picture 1 - sample layout of GUI using Visual Studio 2015
One of the features I want to implement in my program is to show how a Master-slave, simplex connection works (i.e. the program can choose between been a master to send input from the keyboard; or slave to only receive information and print it on a textbox).
What I have already is the capability of initializing the serial port with specific characteristics (baud rate, data bits, stop bits, etc). This features are selected using combo boxes from the GUI, and assigned to the port when the user clicks a button to "open the port".
What I don't know is how to create the "slave" part of the program. My idea of what I could do is, after you choose the program to be "slave", you open the port waiting for some sort of flag or event to trigger when the input buffer has data stored.
I've been reading several forums and I can't find anything similar to what I need. I have, however, tested multiple alternatives that I believed would bring me closer to what I need with little to no result. I come to ask for an idea of what I could be doing wrong, or suggestions on how to tackle this problem. The problematic lines are bolded (or 2 stars ( * ) ):
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO.Ports;
namespace SerialCommTester
{
public partial class frmSerialComm : Form
{
static SerialPort _PuertoSerial;
public frmSerialComm()
{
InitializeComponent();
getAvailablePorts();
}
//---------------------------------my functions--------------------------------------
void getAvailablePorts()
{
string[] ports = SerialPort.GetPortNames();
cmbPortList.Items.AddRange(ports);
}
void activatePort()
{
//Note that all the combo boxes are named somewhat accordingly to what the information they are meant to display.
if (cmbPortList.Text != "" && cmbBaudRate.Text != "" && cmbParity.Text != "" && cmbStopBits.Text != "")
{
_PuertoSerial.PortName = cmbPortList.Text;
_PuertoSerial.BaudRate = Convert.ToInt32(cmbBaudRate.Text);
_PuertoSerial.RtsEnable = true;
_PuertoSerial.DtrEnable = true;
_PuertoSerial.DataBits = Convert.ToInt32(cmbDataBits.Text);
if (cmbParity.Text == "Even") { _PuertoSerial.Parity = Parity.Even; }
else if (cmbParity.Text == "Odd") { _PuertoSerial.Parity = Parity.Odd; }
else if (cmbParity.Text == "Space") { _PuertoSerial.Parity = Parity.Space; }
else if (cmbParity.Text == "Mark") { _PuertoSerial.Parity = Parity.Mark; }
else { _PuertoSerial.Parity = Parity.None; }
if (cmbStopBits.Text =="2") { _PuertoSerial.StopBits = StopBits.Two; }
else if (cmbStopBits.Text == "1.5") { _PuertoSerial.StopBits = StopBits.OnePointFive; }
else { _PuertoSerial.StopBits = StopBits.One; }
if (cmbHandShake.Text == "Software Flow Control") { _PuertoSerial.Handshake = Handshake.XOnXOff; }
else if (cmbHandShake.Text == "Hardware Flow Control") { _PuertoSerial.Handshake = Handshake.RequestToSend; }
else { _PuertoSerial.Handshake = Handshake.None; }
_PuertoSerial.ReadTimeout = 500;
_PuertoSerial.WriteTimeout = 500;
_PuertoSerial.Open();
//in my understanding, this line of code is needed to handle data being received. Does it trigger a flag or something?
**_PuertoSerial.DataReceived += new SerialDataReceivedEventHandler(DataReceivedHandler);**
}
else
{
txtRecieve.Text = "Input selection missing 1 or more characteristics";
}
}
**
private static void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
{
SerialPort testing = (SerialPort)sender;
txtRecieve.AppendText(testing.ReadExisting()); //txtRecieve cannot be reached within this function. It indicates the following error: "An object reference is required for the non-static field, method, or property 'frmSerialComm.txtRecieve'
}
**
void enableDisableGUI(bool[] input)
{
grpConnection.Enabled = input[0];
grpCharacteristics.Enabled = input[1];
btnOpenPort.Enabled = input[2];
btnClosePort.Enabled = input[3];
txtSend.Enabled = ((cmbControlMasterSlave.Text == "Slave") ? false : true);
}
//----------------------------C# objects / functions--------------------------------------
private void btnOpenPort_Click(object sender, EventArgs e)
{
try
{
_PuertoSerial = new SerialPort();
activatePort();
}
catch(Exception ex)
{
MessageBox.Show(ex.Message, "Message ", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
bool[] format = { false, false, false, true};
enableDisableGUI(format);
}
private void btnClosePort_Click(object sender, EventArgs e)
{
_PuertoSerial.Close();
bool[] format = { true, true, true, false};
enableDisableGUI(format);
}
private void txtSend_KeyPress(object sender, KeyPressEventArgs e)
{
_PuertoSerial.Write(e.KeyChar.ToString()); //this is how I send data through the serial port.
}
private void btnClearTxts_Click(object sender, EventArgs e)
{
txtRecieve.Clear();
txtSend.Clear();
}
} //class closes
} //program closes
I am not an experienced programmer, I just want to create something useful for my students. Any constructive criticism will be highly appreciated.
I don't have any definitive answers for you. You code looks like it should provide what you need once you get past the two possible glitches.
I think you should attach your SerialDataReceivedEventHandler BEFORE
you call _PuertoSerial.Open().
It may have no effect since event handlers can normally be enabled/disabled dynamically, but I base the advice on the following comment taken from the .Net source code for SerialPort on MSDN.
// all the magic happens in the call to the instance's .Open() method.
// Internally, the SerialStream constructor opens the file handle, sets the device control block and associated Win32 structures, and begins the event-watching cycle.
The "object reference" error might be resolved by removing the
static modifier from your DataReceivedHandler. If not, or if that
static modifier is necessary for some reason, then perhaps the
txtRecieve control has a private modifier which needs to be changed
to internal or public. You should be able to use Visual Studio in
debug mode to step into the InitializeComponent() method and see
where txtRecieve is being instantiated.
Well, I believe that I needed to read more. This is how I solved the problem (if this is not the real solution, at least is working for now):
I moved the "SerialDataReceivedEventHandler" line before the _PuertoSerial.open();
I followed the suggestions from this article:
https://msdn.microsoft.com/query/dev14.query?appId=Dev14IDEF1&l=EN-US&k=k(EHInvalidOperation.WinForms.IllegalCrossThreadCall);k(TargetFrameworkMoniker-.NETFramework,Version%3Dv4.5.2);k(DevLang-csharp)&rd=true
So my funtions (one existings + a new one) look like this:
void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
{
printReceivedText(_PuertoSerial.ReadExisting());
}
private void printReceivedText(string text)
{
if (this.txtSend.InvokeRequired)
{
SetTextCallback d = new SetTextCallback(printReceivedText);
this.Invoke(d, new object[] { text });
}
else
{
this.txtRecieve.AppendText(text);
_PuertoSerial.DiscardInBuffer();
}
}
For now seems to be working fine. The final testing will come when I connect another terminal and see the program interacting with each other.
I have a windows Form and i'm using C# for this program. In my form i have a button and a textbox.
I want to click on the button and delete the numbers/letters by incorporating a custom exception (for learning purposes), but i keep on getting an error.
The error in my program is when there is nothing in the textbox, and if i click on the delete button the program crashes. Can someone help me out with this?
public class deleteData : Exception
{
public deleteData()
: base("") { }
}
private void btn_Delete(object sender, EventArgs e)
{
if (textbox1.Text != null)
{
textbox1.Text = textbox1.Text.Remove(textbox1.Text.Length - 1, 1);
}
else
{
throw new deleteData();
}
}
I modified your program a bit. Give it a try and see if this is what you had in mind. The custom exception pops up a messageBox as its exception handling, and the catch block puts the stack trace in the textBox. You could use either, both, or neither method for handling the exception. The main thing is that as long as the exception occurs in the Try-Catch block and is handled in some way there, you will not crash your program. It handles the exception and keeps on running.
You would not usually do this, but I can see the educational benefit in it.
using System;
using System.Windows.Forms;
namespace TryCatch
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void btn_Delete_Click(object sender, EventArgs e)
{
try
{
if (textBox1.Text != "")
{
textBox1.Text = "";
}
else
{
throw new deleteData("Here we are having the custom exception do its own exception handling");
}
}
catch (Exception ex)
{
textBox1.Text = "Here we are catching the custom exception in a catch block\r\n\r\n";
textBox1.Text += "Exception details:" + ex.StackTrace.ToString();
}
}
public class deleteData : Exception
{
public deleteData(string s)
{
MessageBox.Show(s);
}
}
}
}
As many people suggested, this is not a good idea, but if you insist, I'll explain how to do this.
You want to check whether text in a text box is null. If it is, then throw an exception. However, I think you misunderstand what it means by "a string is null" and "a string is empty". An empty string is "" and a null string is just null, nothing. A null string cant do anything, if you call its methods, NullRefereneException! But you can call methods from an empty string.Normally the text in text boxes is empty when you see an empty text box. I guess you want to check for that.
if (textbox1.Text != "") {
textbox1.Text = ""; // This is to remove the text, as you said in the question
} else {
throw new deleteData ();
}
I'm creating an app in winforms c# using vs 2013.
In the app I have a textfile to which I'm saying the time in int format using a custom format from a time select dropdown list.
I then want to display what is in that text file on a selectable listview from where I can remove it from the textfile etc. I'm almost there however at the moment when I try to add the items into the listbox they do seem to add however they do not display correctly.
For example say in my text file there is
22102210
19101610
17182218
10272227
Then that is how it should be displayed in the listview as selectable ready to be deleted.
At the moment it isn't showing correctly, it's showing up as 1.. 2.. 1..
Could someone help me out and point me in the right direction as to why this might be happening? Any help much appreciated. This is my class.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Chronos
{
public partial class Interface : Form
{
private string[] getTimes = System.IO.File.ReadAllLines(#"G:\Dropbox\University\Chronos\Application\Chronos\Chronos\AdminAccount\Times.txt");
public Interface()
{
InitializeComponent();
}
private void Interface_Load(object sender, EventArgs e)
{
PopulateList();
}
private void PopulateList()
{
int size = getTimes.Length;
lstTime.Items.Clear();
GetTimes();
for (int i = 0; i < size; i++)
{
lstTime.Items.Add(getTimes[i]);
}
}
private void GetTimes()
{
string[] getTimes = System.IO.File.ReadAllLines(#"G:\Dropbox\University\Chronos\Application\Chronos\Chronos\AdminAccount\Times.txt");
}
private void btnAdd_Click(object sender, EventArgs e)
{
string time = pickerTimeStart.Value.Hour.ToString() + pickerTimeStart.Value.Minute.ToString() + pickerTimeEnd.Value.Hour.ToString() + pickerTimeEnd.Value.Minute.ToString();
System.IO.File.AppendAllText(#"G:\Dropbox\University\Chronos\Application\Chronos\Chronos\AdminAccount\Times.txt", time + Environment.NewLine);
PopulateList();
MessageBox.Show("Time added", "Ok");
//PopulateList();
}
}
}
As currently written, GetTimes does nothing except read the file:
private void GetTimes()
{
// "string[]" here overrides the outer scope
string[] getTimes = System.IO.File.ReadAllLines(#"G:\Dropbox\University\Chronos\Application\Chronos\Chronos\AdminAccount\Times.txt");
}
If you change it to this, it becomes more useful:
private string[] GetTimes()
{
return File.ReadAllLines(#"G:\Dropbox\University\Chronos\Application\Chronos\Chronos\AdminAccount\Times.txt");
}
... and then PopulateList can simply become:
lstTime.Items.Clear(); //so you aren't getting a bunch of dupes
lstTime.Items.AddRange(GetTimes().Select(t => new ListViewItem(t)).ToArray());
You can also remove this line because you don't need to keep a copy of the data in the class:
private string[] getTimes = ...
Note: If you decide to keep the data source local and not work solely against the file, much of this would change.
I need to create a WinForms textbox that allows decimal text exclusive-or integer text. Also, I don't wish to be required to specify the length of the text in the mask; the user should be able to enter as many characters as he wants, as long as the text fits the decimal or integer mold. However, the MaskedTextBox doesn't allow variable-length masking, as far as I know; I can't find a pre-existing control that does this, either.
Advice? I suppose I could inherit TextBox, override OnKeyPress and do the work there, but I don't know whether a pre-existing control would do things more gracefully.
the NumericUpDown control has some built in decimal/integer parsing behavior - sounds like it might be what you're looking for. Of course, you end up with the updown controls on the text box too.
Try this:
private void TextBox1_Validating(object sender, EventArgs e)
{
string expression = "^\d{1,8}(\.\d{2,2})?$";
if (System.Text.RegularExpressions.Regex.Match(this.txt_monto_total.Text, expression).Success)
this.label_total.Visible = false;
else
this.label_total.Visible = true;
}
It's not a mask but it will let you tell the user if they have entered an incorrect format (i do it by showing the label), you can use any regular expression, in my case i only want numbers with 1 or 8 digits before the "." and 2 after it.
Here's a solution. It's not perfect - it may eat control characters in certain cases, and it doesn't cleanly handle pasting - but it works well enough!
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;
namespace WinFormsTest
{
public partial class MaskedTextBox : TextBox
{
public enum EntryTypeEnum
{
Any,
Integer,
Decimal
}
[DefaultValue(EntryTypeEnum.Any)]
public EntryTypeEnum EntryType { get; set; }
public MaskedTextBox()
{
InitializeComponent();
}
protected override void OnKeyPress(KeyPressEventArgs e)
{
var keyIsValid =
(EntryType == EntryTypeEnum.Any)
|| char.IsControl(e.KeyChar)
|| isValid(Text + e.KeyChar);
e.Handled = !keyIsValid;
base.OnKeyPress(e);
}
protected override void OnValidating(CancelEventArgs e)
{
e.Cancel = !isValid(Text);
base.OnValidating(e);
}
protected bool isValid(string textToValidate)
{
switch (EntryType)
{
case EntryTypeEnum.Any:
break;
case EntryTypeEnum.Decimal:
{
decimal result;
if (!decimal.TryParse(textToValidate, out result))
{
return false;
}
}
break;
case EntryTypeEnum.Integer:
{
int result;
if (!int.TryParse(textToValidate, out result))
{
return false;
}
}
break;
}
return true;
}
}
}
After much searching I was able to discover a control on codeproject that allows for a variable length number.
It is the Nullable Masked Edit, and a Better Masked Edit Also! project.
Note you need to use the 'EditMask' field to set the Mask properties. Trying to set the 'Mask' field won't work.
I was able to set a mask of 999.9 and then entering 1.1 would work without having to add leading spaces.