How to access Form textboxes inside EventHandler by string in C#? - c#

I am using Visual Studio 2017. There is a form with textboxes. These textboxes need a refresh every 10 seconds. For achieving this I use a Timer event.
public partial class status_window : Form
{
public status_window()
{
InitializeComponent();
shutdown_button.Click += new EventHandler(shutdown_click);
Timer timer = new Timer();
timer.Interval = (1 * 10000); // 10 secs
timer.Tick += new EventHandler(timer_Tick);
timer.Start();
}
}
The timer_tick function is member of the status_window class. Inside that eventhandler I can access the textboxes by their name as expected. But how to do that if the textbox "adress" is i variable. Look:
private void timer_Tick(object sender, EventArgs e)
{
Int32 unixtime = (Int32)(DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1))).TotalSeconds;
// for all boxes per exname
for (int i = 0; i < something.Count() ; i++)
{
// try to find textbox 1 -> embty result
Console.WriteLine( this.Controls.Find("nam1_last_event", true) );
Console.WriteLine( this.Controls.Find("nam2_last_event", true) ); // also empty result
// this works and fills the formbox as ecxpected
nam1_last_event.Text = "somevalue";
nam1_event_count.Text = "anothervale";
nam2_last_event.Text = "somemorevalue";
nam2_event_count.Text = "andsoon";
// thats what i want later to use my for loop for those:
// something[i] exuals to nam1,nam2 and so on
this.Controls.Find( String.Format("{0}_last_event", something[i].ToLower()) , true)[0].Text = "somevalue"; // this fails cause array returned by find is empty
this.Controls.Find(String.Format("{0}_last_event", ex_name.ToLower()), true)[0].Text = "anothervale"; // same
}
}
So I stuck here somehow limited by my own knowledge. Most results on Google suggest to use the controls Find Method.

This works for me:
var inPanel = this.Controls.Find("inPanel", true).OfType<TextBox>().FirstOrDefault();
inPanel?.Text = "Found it";

In your code you use equally name nam1_last_event as member of class status_window and name of control. Please check in designer if your control relay has name nam1_last_event.
Function Controls.Find use key which is value of property Name of control.

Create a list or Dictionary variable to save those textboxs, and get it in the timer_Tick.

Related

How to get list index of Timer object list in Timer Event Handler

My application requires 22 separate timers. So I created a timer list like so.
List<Timer> myTimers = new List<Timer>();
for(int i = 0; i < 22; i++)
{
myTimers.Add(new Timer());
}
Then I set settings for the timers
foreach(var timer in myTimers)
{
timer.Elapsed += new ElapsedEventHandler(ElapsedTimerEventHandler);
timer.Interval = 10000;
timer.Enabled = false;
}
I then created a method to start the timer.
public void SetTimerMethod(int timerId)
{
var timer = myTimers.ElementAt(timerId);
timer.Enabled = true;
}
My question is in my Event Handler how do I find out which timer called the event handler. I tried using indexOf(myTimers); on the source object passed to the event handler but that does not work. The reason I need the index position is because I need to update a field in a list of class objects based upon which timer expired. Any help would be appreciated.
I am new to this so I am open to doing this in a different way if this is a bad way of doing what I want to.
If you really want the index and not just the timer, you could use IndexOf
private ElapsedEventHandler(object sender, ElapsedEventArgs e)
{
var index = myTimers.IndexOf((Timer)sender);
}
If every timer has the same interval and is started the same time what is the point of having many of them versus one? Anyway, the sender property of the Elapsed event is the source timer (see also the docs:
private void ElapsedTimerEventHandler(Object source, System.Timers.ElapsedEventArgs e)
{
var timerCausingThisEvent = (Timer)source; // source is the timer
var timerInList = myTimers.First(t => t == timerCausingThisEvent);
var index = myTimers.IndexOf(timerCausingThisEvent);
}

update datagridview very frequently

I'm having trouble refreshing my DataGridView in a reasonable time in C# (which I am new to btw, I'm used to java...).
I'm getting data over a network with 20 packages sent per second. I'd like to parse the data and put it in a DataGridView. I would also like to adjust the interval in which the DataGridView is updated, from 0.1 seconds to 1 minute.
So I created an extra thread, which reads the packages and parses them to an Array. I also have a Timer, which I use to change the Interval. On every timer tick, I reassign the DataSource to the DataGridView.
Interestingly, when I do, even if I set the timer to 0.1 seconds, it is only triggered about once a second. If I do not refresh the DataGridView, it gets triggered 10 times a second, as it is supposed to.
So I am assuming that my method of updating the DataGridView is too time consuming. But what do I have to do to make it more efficient, so I can update it 10 times a second without any problems?
Here is the code I use:
public MyForm()
{
InitializeComponent();
timer = new System.Windows.Forms.Timer();
timer.Interval = (1 * 1000); // 1 secs
timer.Tick += new EventHandler(timer_Tick);
timer.Start();
readNetworkValues = true;
networkReader = new Thread(() =>
{
Thread.CurrentThread.IsBackground = true;
byte[] data = new byte[1024];
IPEndPoint ipep = new IPEndPoint(IPAddress.Any, 49003);
UdpClient newsock = new UdpClient(ipep);
IPEndPoint sender = new IPEndPoint(IPAddress.Any, 0);
while (readNetworkValues)
{
data = newsock.Receive(ref sender);
dataSet = parseData(data); //Decrypts the data
}
newsock.Close();
});
networkReader.Start();
}
private void timer_Tick(object sender, EventArgs e)
{
if (dataSet != null)
{
lock (dataSet)
{
int currentRow = dataGrid.FirstDisplayedScrollingRowIndex;
dataGrid.DataSource = dataSet;
dataGrid.FirstDisplayedScrollingRowIndex = currentRow;
}
}
}
The number of cells you want to update and also the update rate you want are high enough to cause flicker and lagging.
To avoid it you can turn on DoubleBuffering for the DataGridView.
This property is not exposed by default. So have a have a choice of either
creating a subclass or
accessing it via reflection
Here is a post that demonstrates the former. It was written for a case of scrolling flicker but will help avoid update lags as well. The class can maybe look like this:
public class DBDataGridView : DataGridView
{
public new bool DoubleBuffered
{
get { return base.DoubleBuffered; }
set { base.DoubleBuffered = value; }
}
public DBDataGridView()
{
DoubleBuffered = true;
}
}
You can add this class to the project or simply to the form class (before the very last curly.) Compile and it will show up in the ToolBox.
The other option uses reflection; here is a general-purpose function that should work for for any type of control:
using System.Reflection;
static void SetDoubleBuffer(Control ctl, bool DoubleBuffered)
{
typeof(Control).InvokeMember("DoubleBuffered",
BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.SetProperty,
null, ctl, new object[] { DoubleBuffered });
}
Both ways let you turn DoubleBuffering on and off at will; the former via the now exposed property, the latter by the bool param of the method.

Storing loop values from click button?

I am currently using a loop to create a new User Control on my windows form. I want it to add a single instance of this User Control in a new position where Y is incremented by 125 each time.
I'm pretty new with C# and Visual Studio, so with the below code, the first instance is being replicated each time I press the 'add' event. I was just wondering if someone can give some assistance on the best way to store the value of 'y' from this first instance to be passed into the loop the second time? Or if there is any better way to do this.
Thanks in advance!
private void btnAddRow_Click(object sender, EventArgs e)
{
int y = 175;
for (int i = 0; i <= 0; i++)
{
NewSkillRow nSkill = new NewSkillRow();
nSkill.Location = new Point(75, y += 125);
Controls.Add(nSkill);
btnAddRow.Click += new EventHandler(btnAddRow_Click);
}
}
Make your y variable local to the class (you can also initialize it with its default):
private int y = 175;
The event handler is called every time you click the button. So remove the initialization of y from there.
private void btnAddRow_Click(object sender, EventArgs e)
{
var nSkill = new NewSkillRow();
nSkill.Location = new Point(75, y += 125);
Controls.Add(nSkill);
}
Note that the event handler attachment was removed. Reattaching an event handler from within the handler would lead to an increasing number of invokations every time the button is clicked.
The loop is fine, but not necessary: For just one iteration, you can as well just omit it.
The use of the y += 125 is also ok, it relies on the specification that the return value of an assignment operator is the value that has been assigned.

auto scroll in an ultragridview for infragistics

I am using an Infragistics UltraGridView in my program. Is it possible to set it to automatically scroll the UltraGridView starting at top to the bottom and then resetting it back to the top? Also the UltraGridView is to be set as AutoRefresh. Any ideas?
You can simply build a tight loop as this
foreach (UltraGridRow row in grid.Rows)
{
row.Activate();
}
But it is unclear what is your purpose for this code. Your user probably will not be able to understand anything of the data while it scrolls on the grid.
Instead if your point is to set a particular row as the first one in the grid area then you should work along the line of this
grid.ActiveRowScrollRegion.FirstRow = grid.Rows[500];
(Assuming that you have more than 500 rows of course)
If you want to slow down the scrolling then you could add a Timer and in the Tick event run the Activate call. In this context you could write a class like this
public class SlowScroller
{
private UltraGridRow current = null;
private UltraGrid grd = null;
private System.Windows.Forms.Timer t = null;
public SlowScroller(UltraGrid grid)
{
grd = grid;
t = new System.Windows.Forms.Timer();
}
public void Start(int interval)
{
t.Interval = interval;
t.Tick += onTick;
t.Start();
}
public void Stop()
{
if (t.Enabled)
t.Stop();
}
private void onTick(object sender, EventArgs e)
{
if(current == null)
current = grd.Rows[0];
else
current = current.GetSibling(SiblingRow.Next);
current.Activate();
}
}
And call it with
SlowScroller ss = new SlowScroller(grid);
ss.Start(500); // Scroll every 500 milliseconds
Note the presence of the Stop method. This is necessary because you don't want this class to continue fire the Tick event even when you discard your form. Thus you need to call the Stop in the Form_Closing event handler

Updating a WinForm label value from code without buttons

I have a simple question but I could not find a direct answer anywhere
I have a C# program which executes a counter after the user pushes a "start" button. So 1, 2, 3, etc but the increments are performed with casual different time durations, i.e.
1 -> [4 seconds after] 2 -> [7 seconds after] 3 -> etc
and checked in the program every millisecond
I wanted to put an indication on the GUI to let the user know about the number reached
I was thinking to obtain it using a label for the word "Counter:"
// CounterLabel
//
this.CounterLabel.Anchor = ((System.Windows.Forms.AnchorStyles)
((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
this.CounterLabel.AutoSize = true;
this.CounterLabel.Location = new System.Drawing.Point(1090, 35);
this.CounterLabel.Name = "CounterLabel";
this.CounterLabel.Size = new System.Drawing.Size(58, 17);
this.CounterLabel.TabIndex = 52;
this.CounterLabel.Text = "Counter:";
but then I have two questions:
1) do I need a read-only text box to host the changing number
//
// CounterValue
//
this.CounterValue.Anchor = ((System.Windows.Forms.AnchorStyles)
((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
this.CounterValue.BackColor = System.Drawing.SystemColors.Control;
this.CounterValue.Location = new System.Drawing.Point(1149, 32);
this.CounterValue.Name = "CounterValue";
this.CounterValue.Size = new System.Drawing.Size(84, 22);
this.CounterValue.TabIndex = 53;
this.CounterValue.ReadOnly = true;
//this.CounterValue.Text += this.GetCounterValue();
or there is a way to have it using only the label?
2) how to perform the control to see if we have to update the UI? I mean, the value to display is checked every msec and I want the interface to be updated every msec as well [without using an "update" button to ask to show the value reached]
Thanks in advance to those who will try to help
1) Yes, you would need read-only text box next to the label.
2) add a method to the form as follows:
void UpdateCounter()
{
if (InvokeRequired)
{
BeginInvoke(new MethodInvoker(UpdateCounter));
return;
}
CounterValue.Text = Counter.ToString();
}
3) call this method everytime the counter is changed.
Or you could use a timer to call the UpdateCounter function.
another option is to use timer control it will automatically changelable value
timer1.star();
private void timer1_Tick(object sender, EventArgs e)
{
//Your code
}

Categories