I have an automatic function, the idea is to execute in an specific time some actions.
It receives a ListView with the actions and specific times.
It runs almost pefect. I say almost because sometimes it doesn't executes one action (lets say action #10, and it has 30 actions to do) and when this happen the rest of the actions neither get executed.
I have some validations where I check if the previous actions is executed then the current one is excuted, but it doesn't make any difference, it continues stopping at some point.
Here the code for this automatic function:
Constructor
public RunAutomatic()
{
InitializeComponent();
stopwatch = new System.Windows.Forms.Timer();
stopwatch.Interval = 5;
stopwatch.Tick += new EventHandler(stopwatch_Tick);
repSeconds = 0;
for (int x = 0; x < repeatActions.Capacity; x++)
{
repeatActions.Add(x);
finished.Add(x);
}
}
Run Function
private void RunFaster()
{
if (contPos > 1)
{
ArrayList tmp = (ArrayList)repeatActions[contPos - 1];
if ((bool)tmp[tmp.Count - 1] == true) //This is where it is supposed to validate that the previous action is already executed
Execute(2);
else
{
contPos = contPos - 1;
Execute(2);
}
}
else
Execute(2);
}
I have tried to solve this but can't get over it.
Thanks to all replies.
Related
I'm on a project coding a 4 axes robot arm.
I'm working on Virtual Studio and coding in C#. I'm NEW to C# so please be tolerant.
The robot came with a large .cs library and a Programming Manual with sample methods.
The sample interface :
sample_interface
I used cetains of these samples to build an operation method which makes the arm accomplishes repetitive movements for a chosen number of times. (I erased some movements here to avoid too much useless code) Here it comes :
private async void button_operation_Click(object sender, EventArgs e)
{
int op_number;
for (op_number = 0; op_number < Convert.ToInt32(textBox_operation.Text); op_number++) {
int i;
for (i = 0; i < 4; i++)
{
axis_list[i] = i;
}
v_dist[0] = 60;
v_dist[1] = 10000;
v_dist[2] = -1000;
v_dist[3] = -8000;
if ((int)g_handle != 0)
{
zmcaux.ZAux_Direct_Base(g_handle, 4, axis_list);
zmcaux.ZAux_Direct_SetSpeed(g_handle, axis_list[0], 10000);
zmcaux.ZAux_Direct_MoveAbs(g_handle, 4, v_dist);
zmcaux.ZAux_Direct_GetIfIdle(g_handle, 3, ref idle_state[3]);
make_pause(g_handle, 3);
v_dist[0] = 50;
v_dist[2] = -1700;
v_dist[3] = -10550;
zmcaux.ZAux_Direct_MoveAbs(g_handle, 4, v_dist);
zmcaux.ZAux_Direct_GetIfIdle(g_handle, 3, ref idle_state[3]);
make_pause(g_handle, 3);
v_dist[0] = 60;
v_dist[2] = -1000;
v_dist[3] = -8000;
zmcaux.ZAux_Direct_MoveAbs(g_handle, 4, v_dist);
zmcaux.ZAux_Direct_GetIfIdle(g_handle, 3, ref idle_state[3]);
make_pause(g_handle, 3);
}
}
}
The make_pause() method is to make the robot wait the end of a movement before beggining the next :
{
while (idle_state[iaxis] == 0)
{
zmcaux.ZAux_Direct_GetIfIdle(g_handle, iaxis, ref idle_state[iaxis]);
}
}
By side, I also used another sample to add a "STOP" button but for this one, I just had to copy the whole method as it comes. Its role is to obviously cancel every movement. However, it's not working.
The sample method I used for the Stop Button :
{
if ((int)g_handle != 0)
{
zmcaux.ZAux_Direct_Rapidstop(g_handle,2);
}
}
My first though is that my operation method construction does not allow another method call to cancel.
Thus, I made a TEST button to create a single movement just like on my sample project.
Problem is that the STOP button is still not working.
What am I missing ? Is there something wrong with the way I am building the methods or project ?
Thanks
I have a c# win forms application which has a flowLayoutPanel in it.
I need to update all the children in this panel every second.
here is my current code which gets called in a system timer every 1 seconds:
public void RefreshReceiversPage()
{
if (checkBox_enableReceivers.Checked)
{
var receivers = OutgoingReceiverManager.GetCopyOfActiveRecieverHolders();
for (int i = 0; i < flowLayoutPanel_receivers.Controls.Count; i++)
{
var tmp = flowLayoutPanel_receivers.Controls[i];
flowLayoutPanel_receivers.Controls[i].Dispose();
tmp.Dispose();
}
flowLayoutPanel_receivers.Controls.Clear();
foreach (var item in receivers.ToList())
{
var tmpUc = new ucReceiverItem(item);
if (flowLayoutPanel_receivers != null)
{
try
{
flowLayoutPanel_receivers.Controls.Add(tmpUc);
}
catch
{
}
}
}
receivers = null;
}
}
now this code works perfectly for about 2 minutes and then all of a sudden I start getting error creating window handle Hence the reason for my try catch in the code above.
But after this happens the pane view goes funny and I cant recover it without starting up the program again.
I have searched high and low and I cant seem to find anything on the exception being thrown?
All that I can think is that im maybe not disposing of object properly and that its running out of memory some where?
Does any one have any suggestions or solutions?
EDIT:
here is UCRecieverItem:
public partial class ucReceiverItem : UserControl
{
public ucReceiverItem(ReceiverHolder item)
{
InitializeComponent();
ConstructItem(item);
item = null;
}
private void ConstructItem(ReceiverHolder item)
{
label_name.Text = item.ReceiverDb.Name;
label_numberOfConnections.Text = item.ReceiverOutgoingConnectionManager.GetNumberOfConnections().ToString();
label_mrFilters.Text = item.ReceiverDb.MrFilters;
label_multipleConnections.Text = item.ReceiverDb.MultipleConnections.ToString();
//
int count = item.GetActiveBufferCount();
int size = item.GetActiveBufferSize();
//
label_bufferCount.Text = count + #" / " + size;
progressBar_buffer.Maximum = size;
progressBar_buffer.Minimum = 0;
progressBar_buffer.Value = count;
}
}
This code is a problem:
for (int i = 0; i < flowLayoutPanel_receivers.Controls.Count; i++)
{
var tmp = flowLayoutPanel_receivers.Controls[i];
flowLayoutPanel_receivers.Controls[i].Dispose();
tmp.Dispose();
}
flowLayoutPanel_receivers.Controls.Clear();
It is only disposing half of the controls in the container. The other half get removed by the Controls.Clear(); call, but those controls do not get disposed — so they still exist and are using up memory.
Doing this every second compounds the problem: that's potentially a lot of controls.
The immediate work-around would be to properly dispose of the controls:
while (flowLayoutPanel_receivers.Controls.Count > 0) {
flowLayoutPanel_receivers.Controls[0].Dispose();
}
After that, I would question the need to do this every second — seems like a harsh environment for a user to work in.
I have winform application where i am trying to play multiple videos and i am creating threading for that. My code is :
public String[,] vpath = new String[3, 7];
public Video[,] video = new Video[3, 7];
public static Thread[,] th = new Thread[3, 7];
public void playclick(object sender, EventArgs e)
{
int i, j;
for (j = 0; j <= 7 - 1; j++)
{
for (i = 0; i <= 3 - 1; i++)
{
if (btnp[i, j].Capture)
{
//play();
th[i, j] = new Thread(new ThreadStart(play));
th[i, j].IsBackground = true;
th[i, j].Start();
}
}
}
}
public void play()
{
int i, j;
for (j = 0; j <= 7 - 1; j++)
{
for (i = 0; i <= 3 - 1; i++)
{
if (th[i, j].ThreadState == ThreadState.Running) // Having problem here
{
if (video[i, j].State != StateFlags.Running)
{
video[i, j].Play();
}
}
}
}
}
So with out that if statement it will run all the videos on single button press. But i want to run the particular video which the thread is in ..
pls help me guys
ThreadState is a bitmask-type property (enum has the [Flags] property, that's always the hint), so you don't check it directly using ==, you only need to check the relevant bit:
if ((t.ThreadState & ThreadState.Running) == ThreadState.Running) { ...
Read here about the meanings of the ThreadState values. From reading that and possibly the whole article, or whole book (highly recommended!) you'll also most likely notice that yours is probably not the ideal approach.
Not knowing your exact endgame though, it;s hard to suggest an exact one.
As to why you are getting an exception, HaemEternal nailed that in his comment. You are only initializing one thread at a time, yet you are checking all of them. A null thread object does not have a ThreadState value.
May I suggest though, that you change your design altogether;
There is no need to constantly check which thread was activated. You can change the signature of the Play() method to accept an Object, and you can pass the correct video to the method using that Object.
public void playclick(object sender, EventArgs e)
{
int i, j;
for (j = 0; j <= 7 - 1; j++)
{
for (i = 0; i <= 3 - 1; i++)
{
if (btnp[i, j].Capture)
{
//play();
th[i, j] = new Thread(new ParameterizedThreadStart(play));
th[i, j].IsBackground = true;
th[i, j].Start(video[i,j]);
}
}
}
}
public void play(object video)
{
Video vid = video as Video;
if (vid.State != StateFlags.Running)
{
vid.Play();
}
}
An even better approach is to encapsulate these three elements in a single object that contains a Video object, a Thread object, and a path string.
If you own the Video class, you might even want to make the Thread and the string values fields of that class.
You might even want to create a field on your buttons of type of this new object, so each button will be associated with a button.
This is much more typical of object oriented design. There is no reason you should maintain four separate identically sized arrays, each of different type.
The answer by #tar gives some hints but the code is wrong (as commented by #Sampath).
This come from the fact that ThreadState is implemented in a questionable strange way:
Normally a bitmask state is implemented using for example bit 1 for state on and the
same bit for the opposite off. This is not the case, in fact, for example, the Running
state has a 0 value, whereas the 1 value is taken by StopRequested.
So it is not wise to do a bit check.
A first approach would be to check for state with an or statement:
while (t.ThreadState == ThreadState.Running ||
t.ThreadState == ThreadState.Background)
Application.DoEvents();
t.Join();
Keep in mind that if you start a process in background you will have the
ThreadState.Background enum value returned and not ThreadState.Running,
this is why I have put both.
The better and simpler approach is:
while (t.IsAlive)
Application.DoEvents();
t.Join();
if (th.ThreadState.Equals(ThreadState.Unstarted))
th.Start();
I've got a problem with adding Expanded event to my Expanders. I have expanders on my Window and I want to get the effect when I expand my expander all other will go down. I write functions that let me do this and it work correct. The problem is that I have 96 expanders I don't want add 96 events for Expand and 96 events for Collapse so I thought that I can add this programmatically.
look at the code:
private void InitExpanders()
{
var expanders = GetExpanders(); // List<Expander> - list of expanders
for (int i = 0; i < expanders.Count; i++)
{
if (i % 6 == 1)
{
expanders[i - 1].Expanded += new RoutedEventHandler(delegate(object sender, RoutedEventArgs args)
{
DisableBigExpanders(1); // problem is here!
});
}
}
}
this code works fine but for each expander function parameter will be 1.
Ive tried to add integer and increment it but it wont works.
private void InitExpanders()
{
var expanders = GetExpanders();
int x = 0;
for (int i = 0; i < expanders.Count; i++)
{
if (i % 6 == 1)
{
expanders[i - 1].Expanded += new RoutedEventHandler(delegate(object sender, RoutedEventArgs args)
{
DisableBigExpanders(x);
});
x++;
}
}
}
Thanks for all replies.
I suspect you are finding x in the delegate is always the highest value it reached during the loop. This is due to the way the compiler instantiates the instance of the anonymous method you've defined. It looks at what captured outer variables there are around the delegate and decides whether it requires separate instances or if it can use a single instance. In this case, you have no captured outer variables; therefore, the compiler is permitted to use the same instance of the delegate and therefore the same value of x.
To get around this issue, all you need to do is add a more granular variable just before the delegate and assign it the value of x. This will work:
private void InitExpanders()
{
var expanders = GetExpanders();
int x = 0;
for (int i = 0; i < expanders.Count; i++)
{
if (i % 6 == 1)
{
int y = x++;
expanders[i - 1].Expanded += delegate
{
DisableBigExpanders(y);
};
}
}
}
See here for more info on the theory: http://en.csharp-online.net/ECMA-334%3A_14.5.15.4_Anonymous_method_evaluation
I have code that does a web-service request.
While doing this request I need a progress-bar to be moving independently.
My problem is that I just need to say run a progress update every 1 or 2 seconds and check to see if progress of the request has been completed.
NetBasisServicesSoapClient client = new NetBasisServicesSoapClient();
TransactionDetails[] transactions = new TransactionDetails[dataGridView1.Rows.Count - 1];
for (int i = 0; i < dataGridView1.Rows.Count - 1; i++)
{
transactions[i] = new TransactionDetails();
transactions[i].TransactionDate = (string)dataGridView1.Rows[i].Cells[2].Value;
transactions[i].TransactionType = (string)dataGridView1.Rows[i].Cells[3].Value;
transactions[i].Shares = (string)dataGridView1.Rows[i].Cells[4].Value;
transactions[i].Pershare = (string)dataGridView1.Rows[i].Cells[5].Value;
transactions[i].TotalAmount = (string)dataGridView1.Rows[i].Cells[6].Value;
}
CostbasisResult result = client.Costbasis(dataGridView1.Rows[0].Cells[0].Value.ToString(), dataGridView1.Rows[0].Cells[1].Value.ToString(), transactions, false, "", "", "FIFO", true);
string result1 = ConvertStringArrayToString(result.Details);
I use Background Workers all the time, they are great for processing long time actions.
from your code
#region Background Work of My Request
private void ProcessMyRequest()
{
if (!bkgWorkerMyRequest.IsBusy)
{
lblMessageToUser.Text = "Processing Request...";
btnProcessRequest.Enabled = false;
bkgWorkerMyRequest.RunWorkerAsync();
}
}
private void bkgWorkerMyRequest_DoWork(object sender, DoWorkEventArgs e)
{
// let's process what we need in a diferrent thread than the UI thread
string r = GetStuffDone();
e.Result = r;
}
private void bkgWorkerMyRequest_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
string myResult = (String)e.Result;
lblMessageToUser.Text = myResult;
btnProcessRequest.Enabled = true;
}
#endregion
private function string GetStuffDone()
{
NetBasisServicesSoapClient client = new NetBasisServicesSoapClient();
TransactionDetails[] transactions = new TransactionDetails[dataGridView1.Rows.Count - 1];
for (int i = 0; i < dataGridView1.Rows.Count - 1; i++)
{
transactions[i] = new TransactionDetails();
transactions[i].TransactionDate = (string)dataGridView1.Rows[i].Cells[2].Value;
transactions[i].TransactionType = (string)dataGridView1.Rows[i].Cells[3].Value;
transactions[i].Shares = (string)dataGridView1.Rows[i].Cells[4].Value;
transactions[i].Pershare = (string)dataGridView1.Rows[i].Cells[5].Value;
transactions[i].TotalAmount = (string)dataGridView1.Rows[i].Cells[6].Value;
}
CostbasisResult result = client.Costbasis(dataGridView1.Rows[0].Cells[0].Value.ToString(), dataGridView1.Rows[0].Cells[1].Value.ToString(), transactions, false, "", "", "FIFO", true);
return ConvertStringArrayToString(result.Details);
}
all you need to do is call the method:
ProcessMyRequest();
and it will do the job. If you need to let the main Thread to be aware of progress, you can use the ProgressChanged event
private void bkgWorkerMyRequest_ProgressChanged(
object sender, ProgressChangedEventArgs e)
{
progressBar1.Value = e.ProgressPercentage;
}
in the bkgWorkerMyRequest_DoWork method you need to change the code to have
//reports a percentage between 0 and 100
bkgWorkerMyRequest.ReportProgress(i * 10);
Remember:
alt text http://www.balexandre.com/temp/2010-04-07_1200.png
You will, however get stuck when trying to Debug the method GetStuffDone as it's that kinda hard debugging multi threaded applications
So, what I do is, debug everything without workers and then apply the workers.
Works fine for me, let me know if you need any more help on this.
added
I didn't aware that you were getting the Grid in the worker, sorry, for this, just send the grid as a argument and use it, please change:
bkgWorkerMyRequest.RunWorkerAsync(dataGridView1);
string r = GetStuffDone((GridView)e.Argument);
private function string GetStuffDone(GridView dataGridView1)
Create a BackgroundWorker (call the instance "bgw") and type "bgw.DoWork += " followed by TAB TAB. Visual Studio then generates the DoWork event handler method. Copy the code above into the handler and voila.
I don't think it makes sense for you to report progress, since your progress is determined by the duration of the web service request over which you have no influence (and you cannot break it into smaller tasks). As such, just display the "doing work" dialog and initiate the background task to call the web service. When it's done close the "doing work" dialog.