Storing KeyPress input as a string [duplicate] - c#

This question already has an answer here:
get barcode reader value form background monitoring
(1 answer)
Closed 4 years ago.
I am scanning in a value from a barcode to a form, but it is not being entered into a textbox. I would like to "build" a string from the values returned by KeyPress so that I can parse the barcode later. I'm not sure how to set up a loop to capture all the characters from the barcode.
private string input;
private void MESMenu_KeyPress(object sender, KeyPressEventArgs e)
{
input += e.KeyChar;
MessageBox.Show(input);
}

Key Press looks like a event. One the one hand there is a loop - the Event Queue. On the other hand, there is no loop you can use directly (as you get no counting variable).
There are workarounds but they all have the same problem: You need to figure out when one barcode is "done" and can be processed. And thus the next one can begin. Or when the input of a barcode failed (propably due to some number not being readable) and thus should be repeated.
Aside from that, you are on the right track: You need a Variable outside of the Event that you append to. This can be a string, a List, List (a lot of single Character strings) or a Stringbuilder.
String is often good enough for short cases. If you do a lot of assignments, there is a bit of overhead in string connaction. It comes from the Inmubtability of the string and the fact that there is features like string interning to save memory. Just to get around those optimisations/issues, StringBuilder was added.
One thing you should avoid is using any GUI Element as teh outside variable. Writing the GUI causes considerable overhead. Not a issue if you do it once per user triggered event. But from any kind of loop the effects can be massive:
using System;
using System.Windows.Forms;
namespace UIWriteOverhead
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
int[] getNumbers(int upperLimit)
{
int[] ReturnValue = new int[upperLimit];
for (int i = 0; i < ReturnValue.Length; i++)
ReturnValue[i] = i;
return ReturnValue;
}
void printWithBuffer(int[] Values)
{
textBox1.Text = "";
string buffer = "";
foreach (int Number in Values)
buffer += Number.ToString() + Environment.NewLine;
textBox1.Text = buffer;
}
void printDirectly(int[] Values){
textBox1.Text = "";
foreach (int Number in Values)
textBox1.Text += Number.ToString() + Environment.NewLine;
}
private void btnPrintBuffer_Click(object sender, EventArgs e)
{
MessageBox.Show("Generating Numbers");
int[] temp = getNumbers(10000);
MessageBox.Show("Printing with buffer");
printWithBuffer(temp);
MessageBox.Show("Printing done");
}
private void btnPrintDirect_Click(object sender, EventArgs e)
{
MessageBox.Show("Generating Numbers");
int[] temp = getNumbers(1000);
MessageBox.Show("Printing directly");
printDirectly(temp);
MessageBox.Show("Printing done");
}
}
}

Related

Method to draw a line

My Professor gave us this question
Write a method called Drawline that accepts as input an integer n and generates a line of output in lstOutput with n hyphens. That is, if n = 5 we have a line of ‘-----‘ displayed in the list box.
Basically he wants me to type a number in a text box and when i click the button it should display that many hyphens in a list box. Using visual Studio C# WindowsFormApp.
Here's my code:
private void btn3_Click(object sender, EventArgs e)
{
double n;
Drawline(out n);
}
private void Drawline(out double n)
{
n = double.Parse(textBox1.Text);
string strline = "";
for (n = 1; n <= 5; n++);
strline += '-';
lstOutput.Items.Add(String.Format(strline, n));
}
It works but no matter what number i put in the text box only one hyphen shows up. Can anyone help me?
The problem is with your for loop in DrawLine method.
You need to remove the semi-colon at the end of the for statement, so the strLine += '-'; will belong to the loop, not just be executed once.
private void Drawline(out double n)
{
n = double.Parse(textBox1.Text);
string strline = "";
for (i = 1; i <= 5; i++)
strline += '-';
lstOutput.Items.Add(String.Format(strline, n));
}
It appears you may be making this more complicated than it has to be.
It is unclear “why” the DrawLine method returns a double value using the out property? Is this a requirement? If it is not a requirement, then it is unnecessary.
Also, as per the requirement… ”Write a method called Drawline that accepts as input an integer n” … if this is the requirement, I have to ask why is the method accepting a double value? This would not fit with the requirement.
Below is a simplified version and should fit your requirements. First in the button click event, we want to get the integer value from the text box. We need to assume the user typed in a value that is NOT a valid integer. If the value is NOT a valid integer greater than zero (0), then we will display a message box indicating such.
private void button1_Click(object sender, EventArgs e) {
if ((int.TryParse(textBox1.Text, out int value)) && value > 0) {
Drawline(value);
}
else {
MessageBox.Show("String is not a number or is less than 1 : " + textBox1.Text);
}
}
Next the DrawLine method that simply adds a string of “-“ character(s) to the list box. Note the passed-in/accepted value of n has already been verified as a valid integer number greater than 0.
private void Drawline(int n) {
lstOutput.Items.Add(new string('-', n));
}
If you MUST use a for loop to generate the string, it may look something like…
private void Drawline(int n) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < n; i++) {
sb.Append("-");
}
lstOutput.Items.Add(sb.ToString());
}

Why Lock statement doesn't work as expected

static List<int> sharedCollection = new List<int>();
static readonly Object obj = new Object();
static void Main(string[] args)`enter code here`
{
var writeThread = new Thread(() =>
{
for (int i = 0; i < 10; i++)
{
lock (obj)
{
Write();
}
}
});
var readThread = new Thread(() =>
{
for (int i = 0; i < 10; i++)
{
lock (obj)
{
Read();
}
}
});
writeThread.Start();
readThread.Start();
Console.ReadLine();
}
static void Read()
{
Console.Write("Current collection state: ");
sharedCollection.ForEach((e) => Console.Write($"{e} "));
Console.WriteLine();
}
static void Write()
{
Random generator = new Random();
var addedValue = generator.Next(1, 20);
sharedCollection.Add(addedValue);
Console.WriteLine($"Added value is: {addedValue}");
}
I spend a lot of time trying to understand why I receive this:
console result
Could someone explain to me what is wrong with this code?
Mutex works fine but I need to illustrate lock statement too...
I expect that after every adding in 1st thread I obtain a collection state from the 2nd thread. Like this:
Added value: 1
Collection state: 1
Added value: 15
Collection state: 1 15
Added value: 4
Collection state: 1 15 4
I understand you expeected those threasd to run somewhat in paralell, but instead they executed sequentially. You expectation is correct.
I do not think it has anything to do with lock, however. lock will only prevent a read and a write from happening at the same time, not produce this behavior. Try it without the lock to verify. (However due to things like the JiT Compiler, CPU cache invalidations and Optimisations, results may still differet if there is a lock, even if it has no direct effect).
My best bet is that the read thread is simply so slow, it does not finish once before the write is through all it's itteartions. Writing the UI is expensive, even on something as trivial as the console. Or even especially there. I do a lot of backups of userprofiles using robocopy. And if it hits a lot of very small files, just writing the Console becomes the actuall programm bottleneck, ever over disk access. And something out-bottlenecking disk acess is not something that happens often.
If you write the UI only once per user triggerd event, you will not notice the cost. But do it from any form of loop - especially one running in another thread - and you will start to notice it. I was particualry informed that a foreach is apparently half as slow at ittearting as a for loop.
I even made a example for this, albeit in a Windows Forms Environment:
using System;
using System.Windows.Forms;
namespace UIWriteOverhead
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
int[] getNumbers(int upperLimit)
{
int[] ReturnValue = new int[upperLimit];
for (int i = 0; i < ReturnValue.Length; i++)
ReturnValue[i] = i;
return ReturnValue;
}
void printWithBuffer(int[] Values)
{
textBox1.Text = "";
string buffer = "";
foreach (int Number in Values)
buffer += Number.ToString() + Environment.NewLine;
textBox1.Text = buffer;
}
void printDirectly(int[] Values){
textBox1.Text = "";
foreach (int Number in Values)
textBox1.Text += Number.ToString() + Environment.NewLine;
}
private void btnPrintBuffer_Click(object sender, EventArgs e)
{
MessageBox.Show("Generating Numbers");
int[] temp = getNumbers(10000);
MessageBox.Show("Printing with buffer");
printWithBuffer(temp);
MessageBox.Show("Printing done");
}
private void btnPrintDirect_Click(object sender, EventArgs e)
{
MessageBox.Show("Generating Numbers");
int[] temp = getNumbers(1000);
MessageBox.Show("Printing directly");
printDirectly(temp);
MessageBox.Show("Printing done");
}
}
}
But even this overhead is pretty unlikey to have a presistent result. At some time the read thread should get the lock first, blocking write. But still, there are too many variables to say for sure. You should propably try a simpler example, with more consistent (and a whole lot less) writework. What about writing "A" and "B" to the console, instead of complex stuff like this?

Wpf async await ui is frozen

I writing a WPF desktop application and I used async await to keep my UI update.
its works OK for 5 or 6 sec but after that UI freezing but background code is running normally.
await Task.Run(() =>
{
result = index.lucene_index(filepath, filename, fileContent);
if (result) {
updateResultTextBox(filename);
Task.Delay(1000);
}
});
and updateResultTextBox is
private void updateResultTextBox(string _filename)
{
sync.Post(new SendOrPostCallback(o =>
{
result_tbx.Text += "Indexed \t" + (string)o + "\n";
result_tbx.ScrollToEnd();
}), _filename);
}
Your question is less then clear. So I have to guess. My only guess at this time: GUI write overhead.
Writing the GUI is not cheap. If you only do it once per user triggered event, you do not notice it. But once you do it in a loop - even one that runs in a seperate task or thread - you will notice it. I wrote this simple Windows Forms example to showcase the difference:
using System;
using System.Windows.Forms;
namespace UIWriteOverhead
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
int[] getNumbers(int upperLimit)
{
int[] ReturnValue = new int[upperLimit];
for (int i = 0; i < ReturnValue.Length; i++)
ReturnValue[i] = i;
return ReturnValue;
}
void printWithBuffer(int[] Values)
{
textBox1.Text = "";
string buffer = "";
foreach (int Number in Values)
buffer += Number.ToString() + Environment.NewLine;
textBox1.Text = buffer;
}
void printDirectly(int[] Values){
textBox1.Text = "";
foreach (int Number in Values)
textBox1.Text += Number.ToString() + Environment.NewLine;
}
private void btnPrintBuffer_Click(object sender, EventArgs e)
{
MessageBox.Show("Generating Numbers");
int[] temp = getNumbers(10000);
MessageBox.Show("Printing with buffer");
printWithBuffer(temp);
MessageBox.Show("Printing done");
}
private void btnPrintDirect_Click(object sender, EventArgs e)
{
MessageBox.Show("Generating Numbers");
int[] temp = getNumbers(1000);
MessageBox.Show("Printing directly");
printDirectly(temp);
MessageBox.Show("Printing done");
}
}
}
If you start a lot of those tasks and they suddenly all return 5-6 seconds in the process, you might just plain overload the GUI thread with the sheer amount of write operations.
I actually had that issue with my very first attempt at Multithreading. I did proper Multthreading, but I still overloaded the GUI thread wich made it appear I had failed.
there is something very strange on this code. Anyway, here are my two cents:
var text = await Task.Run(() =>
{
result = index.lucene_index(filepath, filename, fileContent);
if (result) {
return filename;
}
return string.Empty;
});
if (!string.IsNullOrEmpty(text)) {
result_tbx.Text += $"Indexed \t {text} {Environment.NewLine}";
result_tbx.ScrollToEnd();
}
Still a code smell...

C# Windows Form - How can I call array initialized in click method to other parts of the form

How can I call this array that initializes on a button click event:
private void button1_Click(object sender, EventArgs e)
{
int[] n = textBox1.Text.Split(' ').Select(int.Parse).ToArray();
richTextBox1.Text += "Entered values: ";
foreach (int num in n)
{
richTextBox1.Text += num + " ";
}
richTextBox1.Text += "\n";
}
to other parts of an array, say another click event.
I have tried declaring the array in the form class but that requires the array to have a pre-defined size which is problematic for other parts of the code.
EDIT: Solved! Thanks to the guys at stackoverflow. Solutions and comments were very helpful :D
You can declare the array in the Form's class without specifying its dimensions simply like this:
int[] n = null; //choose better name, and comment the use of the variable.
The rest of the methods (such as click event handlers) can use it like this:
private void someOtherButton_Click(object sender, EventArgs e)
{
if(n != null && n.Length > 0)
{
//do something with the array
}
}
You have to make the array to a field (You can initialize the array with the size 0, if that's a problem for your program you have to overthink the rest of your code). It would look like this then:
private int[] n = new int[0];
private void button1_Click(object sender, EventArgs e)
{
n = textBox1.Text.Split(' ').Select(int.Parse).ToArray();
By the way, I'd strongly suggest not to call the array 'n' but a meaningful name (e.g. _splittedTb1Content).
Use Generics collection type instead :
private void button1_Click(object sender, EventArgs e)
{
List<int> n= textBox1.Text.Split(' ').Select(int.Parse).ToList();
richTextBox1.Text += "Entered values: ";
foreach (int num in n)
{
richTextBox1.Text += num + " ";
}
richTextBox1.Text += "\n";
}
You can declare list n in your form class:
List<int> n;
I also recommend use stringBuilder inside your "foreach" to improve performance for longer list. Use following code if you are processing a longer list.
private void button1_Click(object sender, EventArgs e)
{
List<int> n= textBox1.Text.Split(' ').Select(int.Parse).ToList();
var sBuilder = new StringBuilder();
sBuilder.Append("Entered values: ");
foreach (int num in n)
{
sBuilder.Append(num + " ");
}
sBuilder.AppendLine();
richTextBox1.Text += sBuilder.ToString();
}

How do I add a number that I type in a textbox to an array, and how can I orde ir from the largest to the smallest?

I would like to know how can I add or type a number in a textbox, then this number gets saved, then add other numbers, and save them so at the end I can order them from larger to smaller and viceversa.
I got one textbox (where I type the numbers), one button (add button, that adds the typed number to the textbox2), another textbox2(where the numbers are being added simultaneously, so you can check them). There is a textbox3 (where the numbers must appear ordered from larger to smaller) and a textbox4 (where the numbers must appear ordered from smaller to larger).
Can someone help me?
Not perfect but it works. Try it.:)
//index count
int index=0;
//array declaration
string [] numbers=new string[10];
//method displaying array's content
string arrayDisplay() {
string str="";
for (int i = 0; i < numbers.Length; i++)
{
if (!(numbers[i]== "") )
{
str += numbers[i];
}
}
return str;
}
private void button1_Click(object sender, EventArgs e)
{
textBox2.Text += textBox1.Text;
index++;
if (numbers.Length >=index )
{
numbers[index] = textBox1.Text;
textBox1.Text = "";
}
//Regular sort and display
Array.Sort(numbers);
textBox3.Text = arrayDisplay();
//Reverse sort and display
Array.Reverse(numbers);
textBox4.Text = arrayDisplay();
}

Categories