how to receive string from COM port displayed on 2 textbox - c#

I have 2 data strings (eg: string "1data2DATA") from a COM port. I want string "1data" to show up in textbox_1 and string "2DATA" to show up in textextbox_2. How should I do?
image:
private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e) // nhan dulieu tu cong COM
{
string data = serialPort1.ReadExisting();
SetText(data);
}
private void SetText(string text)
{
//if (text[0] == 'A') // test thử
// {
if (this.tBoxCV1.InvokeRequired)
{
SetTextCallback d = new SetTextCallback(SetText); // khởi tạo 1 delegate mới gọi đến SetText
this.Invoke(d, new object[] { text });
}
else
{
this.tBoxCV1.Text += text;
if (text == "1")
{
this.tBoxCV1.Clear();
}
}
//}
}

As long as the format will always be
"1somecharacterswithnonumbers2othercharacterswithoutnumbers"
then you can split on the character 2
private void SetText(string text)
{
if (this.tBoxCV1.InvokeRequired)
{
this.Invoke(new Action<string>(SetText), new object[] { text });
}
else
{
var results = text.Split('2');
results[1] = '2' + results[1];
this.tBoxCV1.Text += results[0];
if (results[0] == "1")
this.tBoxCV1.Clear();
this.tBoxCV2.Text += results[1];
if (results[1] == "2")
this.tBoxCV2.Clear();
}
}
But if you may receive a 2 in either data, then I don't see how this is possible, and 1 and 2 would make terrible delimiters.

Related

How to check whether a string was already entered?

there is a textbox and by entering the name in it, it checks if there is such a name in the dictionary
if there is, it displays a message and asks to rewrite the name
but I have a keypress that skips all Russian letters and after the output of the name correspondence message the game continues
Here is the code with keypress and button with a check if there is such a name or not:
The question is how to get around keypress with a duplicate name?
private void Button5_Click(object sender, EventArgs e)
{
var dict = new Dictionary<string, int>(); // where will the data be imported from the file
using (var stream = new StreamReader(#"C:\Users\HP\Desktop\photo\results.txt")) // open file
{
// auxiliary elements
var line = "";
string[] param;
// go through all the lines
while ((line = stream.ReadLine()) != null)
{
param = line.Split(' '); // Break line
dict.Add(param[0], Convert.ToInt32(param[1])); // add to dictionary
}
}
if (dict.ContainsKey(textBox1.Text) == false)
{
}
else
{
MessageBox.Show("This name already exists!");
}
}
private void TextBox1_KeyPress(object sender, KeyPressEventArgs e)
{
string Symbol = e.KeyChar.ToString();
if (!Regex.Match(Symbol, #"[а-яА-Я]").Success && (Symbol != "\b"))
{
e.Handled = true;
}
}
First, I suggest extracting methods, i.e.
using System.IO;
using System.Linq;
...
private static Dictionary<string, int> AllNames() {
return File
.ReadLines(#"C:\Users\HP\Desktop\картинки\results.txt")
.Where(line => !string.IsNullOrWhiteSpace(line))
.Select(item => item.Split(' '))
.ToDictionary(items => items[0],
items => int.Parse(items[1]));
}
private static bool NameExists(string name) {
return AllNames().ContainsKey(name);
}
private static bool IsValidNameCharacter(char value) {
// Russian letters are valid ones
if (value >= 'А' && value <= 'Я' ||
value >= 'а' && value <= 'я' ||
value == 'ё' ||
value == 'Ё')
return true;
// ...All the others are not
return false;
}
Then in order to prevent adding Russian Letters into names, let's test textBox1.Text at TextChanged:
private void Button5_Click(object sender, EventArgs e) {
if (NameExists(textBox1.Text)) {
// Let us be nice: put keyboard focus on the problem field
if (textBox1.CanFocus) {
textBox1.Focus();
// textBox1.SelectAll(); // if you want to select all the text
}
MessageBox.Show("This name already exists!");
return;
}
//given name passed validation control (name is all russian letters and unique)
//TODO: put relevant code here (start the game?)
}
private void textBox1_TextChanged(object sender, EventArgs e) {
textBox1.Text = string.Concat(textBox1.Text.Where(c => IsValidNameCharacter(c)));
}

how to read only the weight instead of the whole text from the serial port

I have a Barcode Weighing machine Sartorious BSA 4235 and it is connected to a serial port(COM). I am trying to display it in a text box in my winforms asp.net application. The data received is coming in the format N + 5.249 g . I need to get only the weight value. But when I am trying to extract only the weight, as the fluctuation of the weight is happening, and as I am replacing the string with decimal the value, the textbox is overwriting instead of only the last digit fluctuation similar to weighing scale. So the user is unable to finalize the weight. The fluctuation is happening at a faster rate. Here are the settings for the serial port:
Baud Rate:1200
Parity:None
Data Bits:7
Stop Bits:1
and Here is the code:
_serialPort = new SerialPort(PortName, BaudRate, (Parity)Enum.ToObject(typeof(Parity), paritybits), databits, (StopBits)Enum.ToObject(typeof(StopBits), stopbits));
private void SerialPortOnDataReceived(object sender, SerialDataReceivedEventArgs serialDataReceivedEventArgs)
{
if (IsFire)
{
if (InvokeRequired) //<-- Makes sure the function is invoked to work properly in the UI-Thread
BeginInvoke(new Closure(() => { SerialPortOnDataReceived(sender, serialDataReceivedEventArgs); })); //<-- Function invokes itself
else
{
int dataLength = _serialPort.BytesToRead;
byte[] data = new byte[dataLength];
int nbrDataRead = _serialPort.Read(data, 0, dataLength);
if (nbrDataRead == 0)
return;
string str = System.Text.Encoding.UTF8.GetString(data);
double number;
if (Double.TryParse(str, out number))
{
txtBCGGrassWeight.Text = string.Format("{0:0.000}", str);
}
else
{
var doubleArray = Regex.Split(str, #"[^0-9\.]+")
.Where(c => c != "." && c.Trim() != "");
string[] str1 = ((System.Collections.IEnumerable)doubleArray)
.Cast<object>()
.Select(x => x.ToString())
.ToArray();
if (str1 != null && str1.Length > 0)
{
txtBCGGrassWeight.Text = string.Format("{0:0.000}", str1[0]);
}
}
}
}
}
This is untested and may need some syntactical correction, but try it:
private void SerialPortOnDataReceived(object sender, SerialDataReceivedEventArgs serialDataReceivedEventArgs)
{
if (IsFire)
{
int dataLength = _serialPort.BytesToRead;
byte[] data = new byte[dataLength];
int nbrDataRead = _serialPort.Read(data, 0, dataLength);
if (nbrDataRead == 0) return;
string str = System.Text.Encoding.UTF8.GetString(data);
double number;
bool success = false;
if (Double.TryParse(str, out number))
{
success = true;
}
else
{
var match = Regex.Match( str, #"\d+\.\d+");
if( match.Success )
{
success = Double.TryParse(match.Value, out number);
}
}
if( success )
{
SetText(number.ToString());
}
}
}
delegate void SetTextCallback(string text);
private void SetText(string text)
{
// InvokeRequired required compares the thread ID of the
// calling thread to the thread ID of the creating thread.
// If these threads are different, it returns true.
if (this.txtBCGGrassWeight.InvokeRequired)
{
SetTextCallback d = new SetTextCallback(SetText);
this.Invoke(d, new object[] { text });
}
else
{
this.txtBCGGrassWeight.Text = string.Format("{0:0.000}",text);
}
}

Trying to set variable in the UI-Thread

I use this code to read from a weighting scale, I successfully read weight value from it but when trying to set the variable hex = "" for the next weight value I can't get it in the textbox, it appears very quickly and then disappears again, if I trace the program with the hex = "" enabled the results are as expected, but if run the program without trace it, then the blinking with the values and the textbox gets empty :( any ideas
string hex = "";
private delegate void Closure();
private void SerialPortOnDataReceived(object sender, SerialDataReceivedEventArgs serialDataReceivedEventArgs)
{
if (InvokeRequired)
{
BeginInvoke(new Closure(() => { SerialPortOnDataReceived(sender, serialDataReceivedEventArgs); }));
}
else
{
if (_serialPort.BytesToRead > 0)
{
//hex = ""; <- Without this different weight values appears one after another. If applied then happens what explained above.
while (_serialPort.BytesToRead > 0) //<-- repeats until the In-Buffer is empty
{
hex += string.Format("{0:X2} ", _serialPort.ReadByte());
}
byte[] data = FromHex(hex.Trim());
textBox1.Text = Encoding.ASCII.GetString(data).Trim();
}
}
}
public byte[] FromHex(string aHex)
{
aHex = aHex.Replace(" ", "");
byte[] raw = new byte[aHex.Length / 2];
for (int i = 0; i < raw.Length; i++)
{
raw[i] = Convert.ToByte(aHex.Substring(i * 2, 2), 16);
}
return raw;
}
This is the code to start listening:
private void button1_Click(object sender, EventArgs e)
{
//<-- This block ensures that no exceptions happen
if (_serialPort != null && _serialPort.IsOpen)
_serialPort.Close();
if (_serialPort != null)
_serialPort.Dispose();
//<-- End of Block
/*--- OHAUS Ranger Count Config ---*/
//http://us.ohaus.com/us/en/home/support/faq.aspx
_serialPort = new SerialPort(comboBox1.Text);
_serialPort.BaudRate = 2400;
_serialPort.Parity = Parity.None;
_serialPort.DataBits = 7;
_serialPort.StopBits = StopBits.Two;
_serialPort.Handshake = Handshake.None;
/*--- End OHAUS Ranger Count Config ---*/
label1.Text = "Listening on " + _serialPort.PortName + "...";
_serialPort.DataReceived += SerialPortOnDataReceived; //<- Here I add the event
_serialPort.Open(); //<-- make the comport listen
}
Inside the method that is called when you press the print key, you can add the serial port event handler:
_serialPort.OnDataReceived+=SerialPortOnDataReceived;
Then, at the end of your SerialPortOnDataReceived method (after the successful read), remove the event handler from the serial port object. This will make it stop listening for new data on the serial port until you press print again.
private void SerialPortOnDataReceived(object sender, SerialDataReceivedEventArgs serialDataReceivedEventArgs)
{
if (InvokeRequired)
{
BeginInvoke(new Closure(() => { SerialPortOnDataReceived(sender, serialDataReceivedEventArgs); }));
}
else
{
if (_serialPort.BytesToRead > 0)
{
//hex = ""; <- Without this different weight values appears one after another. If applied then happens what explained above.
while (_serialPort.BytesToRead > 0) //<-- repeats until the In-Buffer is empty
{
hex += string.Format("{0:X2} ", _serialPort.ReadByte());
}
byte[] data = FromHex(hex.Trim());
textBox1.Text = Encoding.ASCII.GetString(data).Trim();
_serialPort.OnDataReceived-=SerialPortOnDataReceived; // <---add this
}
}
}
This is how I update the UI thread.
delegate void SerialPortOnDataReceivedDelegate(object sender, SerialDataReceivedEventArgs serialDataReceivedEventArgs);
private void SerialPortOnDataReceived(object sender, SerialDataReceivedEventArgs serialDataReceivedEventArgs)
{
if (InvokeRequired)
BeginInvoke(new SerialPortOnDataReceivedDelegate(SerialPortOnDataReceived), new object[] { sender, serialDataReceivedEventArgs });
else
{
if (_serialPort.BytesToRead > 0)
{
//hex = ""; <- Without this different weight values appears one after another. If applied then happens what explained above.
while (_serialPort.BytesToRead > 0) //<-- repeats until the In-Buffer is empty
{
hex += string.Format("{0:X2} ", _serialPort.ReadByte());
}
byte[] data = FromHex(hex.Trim());
textBox1.Text = Encoding.ASCII.GetString(data).Trim();
}
}
}
public byte[] FromHex(string aHex)
{
aHex = aHex.Replace(" ", "");
byte[] raw = new byte[aHex.Length / 2];
for (int i = 0; i < raw.Length; i++)
{
raw[i] = Convert.ToByte(aHex.Substring(i * 2, 2), 16);
}
return raw;
}
This is what worked for me, I added some delay before hex = "", however I believe this is not a good practice though:
string hex = "";
private delegate void Closure();
private void SerialPortOnDataReceived(object sender, SerialDataReceivedEventArgs serialDataReceivedEventArgs)
{
if (InvokeRequired)
{
BeginInvoke(new Closure(() => { SerialPortOnDataReceived(sender, serialDataReceivedEventArgs); }));
}
else
{
if (_serialPort.BytesToRead > 0)
{
Thread.Sleep(200); //<-- Add some delay
hex = "";
while (_serialPort.BytesToRead > 0) //<-- repeats until the In-Buffer is empty
{
hex += string.Format("{0:X2} ", _serialPort.ReadByte());
}
byte[] data = FromHex(hex.Trim());
textBox1.Text = Encoding.ASCII.GetString(data).Trim();
}
}
}

Accessing text box from other thread

I am writing text to text box from another thread using code as below
delegate void SetTextCallback(string text);
private void SetText1(string text)
{
if (this.textBox7.InvokeRequired)
{
SetTextCallback d = new SetTextCallback(SetText1);
this.Invoke(d, new object[] { text});
}
else
{
this.textBox7.Text = text;
}
}
Now I have to write text to multiple text boxes (eg textBox8, 9, 10). I wanted this same function SetText1 to work. SO is there a way that I can make textBox7 variable in this function and use the textbox I intend to write from the other thread.
Otherwise if I follow my current approach, then if I want to write to ten textboxes I will need ten SetText functions
you can do it just with one function - you don't even need the delegate
private void SetText(TextBox txt, string text)
{
if (txt.InvokeRequired)
{
Invoke((MethodInvoker)(() => txt.Text = text));
}
else
{
txt.Text = text;
}
}
delegate void SetTextCallback(TextBox textBox, string text);
private void SetText(TextBox textBox, string text)
{
if (textBox.InvokeRequired)
{
SetTextCallback d = new SetTextCallback(SetText);
this.Invoke(d, new object[] {textBox, text});
}
else
{
textBox.Text = text;
}
}

_textChanged event is giving me error "Object reference not set to an instance of an object"

I'm new to C# so still finding my way around.
I have a button I want to enable only when a user enter text to textbox.
I get this error - "Object reference not set to an instance of an object".
Here is the related code (without the using and variables):
public MainWindow()
{
MessageBox.Show("Make sure to edit Settings tab.");
InitializeComponent();
if (startTextBox.Text == "0") // Checks to see if a textbox has some text other than zero. if no than the user cannot press button1 yet.
{
button1.IsEnabled = false;
}
else
{
button1.IsEnabled = true;
}
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
if (radioButton1.IsChecked == false)
{
label17.Content = "No Hourly wage was set.";
}
}
private void add(object sender, RoutedEventArgs e) /// here is a very long method so I've removed its content.
}
public void printTime()
{
int Sum = (this.EndInt - this.StartInt);
int Money = (Sum * this.L1001);
label16.Content = Sum;
label17.Content = Money;
if ((textBox1.Text == "0") && ((textBox2.Text == "0") || (textBox3.Text == "0")))
{
label17.Content = "No Hourly wage was set.";
}
}
public void printTime2()
{
int Sum = (this.EndInt - this.StartInt);
MessageBox.Show("Is it possible that you've worked - " + Sum + " Hours?");
}
public void printTime3()
{
int Sum = (this.EndInt - this.StartInt);
int Money = (Sum * this.L1001);
label16.Content = Sum;
label17.Content = Money;
if (textBox1.Text == "0")
{
label17.Content = "No Hourly wage was set.";
}
}
public int Convert(String S)
{
int i = int.Parse(S);
return i;
}
// Input Validation For Excepting Integers Only!
private void input(object sender, TextCompositionEventArgs e)
{ CheckIsNumeric(e); }
private void CheckIsNumeric(TextCompositionEventArgs e)
{
int result; if (!(int.TryParse(e.Text, out result) || e.Text == "."))
{ e.Handled = true; MessageBox.Show("Numbers Only"); }
}
private void startTextBox_TextChanged(object sender, TextChangedEventArgs e)
{
button1.IsEnabled = true;
}
}
}
It's the scope problem. You didn't show where button1 is defined. But inside your event handler startTextBox_TextChanged, button1 definition is nowhere to be found (actually it needs to be instantiated as well). Since you try to invoke a method on an object (button1) which has not been instantiated yet, that exception was thrown.
If you post more than just those snippets, either I or someone else might be able to further help you.

Categories

Resources