How to make a C# method cancellable? - c#

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

Related

How can I use one function, which belongs to two objects, for only one objects?

I am writing a c# monogame.
On the map there are two goldmines. The player can collect the gold with the following method:
public static void CollectGold(ObjectFactory.ObjectType type)
{
if (Hud.mCurrentTime >= Hud.mCountDuration)
{
Counter++;
Hud.mCurrentTime -= Hud.mCountDuration
if (sMaxGold < 10)
{
sMaxGold += 2;
}
if (sMaxGold >= 10)
{
sMaxGold -= 2; // or sMaxGold = 10 in earlier version-> same output
}
}
else if (sMaxGold > 0)
{
Hud.mGold += 2;
sMaxGold -= 2;
}
}
But for sure, when the player collects gold from goldmine, it is like, he is collecting gold from the other mine as well.
How can I seperate this, that CollectGold only works for the one selected mine.
I can't create CollectGold2 with the same code for the second mine, because one time I want to build a lot of mines in my code. I think there is a better way, than copy and paste the method.
My first idea was, that i can check the mine position, so that the method knows the one mine.
But I don't know how to do it?
Any ideas?
You should use a custom class for a mine and make a non-static method there instead of a static one. Then you should just find the mine needed and collect it's gold. Example:
private class Player
{
public int GoldBalance = 0;
}
private class Mine
{
public int GoldAvailable = 10;
public void Collect(Player player)
{
if (GoldAvailable <= 0)
return;
player.GoldBalance += GoldAvailable;
GoldAvailable = 0;
}
}
This question isn't really answerable in this form; we need more information. For example, how are you representing your mines in code?
However, here are a couple of possible approaches:
Move your method to the Mine class (if it exists), so that you call the method something like this:
var mine = new Mine();
mine.CollectGold();
Pass a Mine object, or the id of a mine, to the method, so that the signature would look like this:
public static void CollectGold(Mine mine)
or
public static void CollectGold(int mineId)
I have removed the type parameter which was unused.
Method 1 is probably preferable but it depends what you're trying to achieve and how complex your application will be.

Automatic function linked to an external timer

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.

Continuously adding and removing to flow-layout panel win forms

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.

Model as dependency property used within different threads

I do have the following szenario. I created a WPF C# project that follows the MVVM pattern. Furthermore I developed a user control that is some kind of a image drawer. Now I create a Model within the viewmodel and share it with the usercontrol as dependency property. This is done like this:
User control:
public DXModel Model
{
get { return (DXModel)GetValue(ModelProperty); }
set { SetValue(ModelProperty, value); }
}
public static readonly DependencyProperty ModelProperty =
DependencyProperty.Register("Model", typeof(DXModel), typeof(DXControl),
new PropertyMetadata(null, OnChanged));
static void OnChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
(sender as DXControl).OnChanged();
}
void OnChanged()
{
if (Model != null)
Model.PropertyChanged += new PropertyChangedEventHandler(Model_Changed); // comes from the ui thread...comes only when init model...ok
textTitle.Text = Model.Title;
internalModel = (DXModel)Model;
}
void Model_Changed(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
if (!receiveTimer.Enabled)
{
receiveTimer.Interval = receiveDelay;
receiveTimer.Start();
refreshTimer.Start();
}
}
So I also get the event when the Model was changed in the viewmodel and I then perform the drawing. Basically I have a list of points which I completely overwrite within the viewmodel several times per second:
ViewModel:
dxModel1.Series[0].Points = list1;
In the User control the points are redrawn also several times per second. To do so, I have to iterate through the points first:
User control:
int length = internalModel.Series[i].Points.Count-1;
float lastX = internalModel.Series[i].Points[0].X;
for (int j = 0; j <= length; j++)
{
float x = ((float)targetImage.Width - 0) / (internalModel.Axes[0].Max - internalModel.Axes[0].Min) * (internalModel.Series[i].Points[j].X- lastX - internalModel.Axes[0].Min);
float y = (0 - (float)targetImage.Height) / (internalModel.Axes[1].Max - internalModel.Axes[1].Min) * (internalModel.Series[i].Points[j].Y - internalModel.Axes[1].Min) + (float)targetImage.Height;
tmpPoints.Add(new SharpDX.Vector2(x, y));
}
What is important, the Model is changed in a worker thread within the viewmodel. The user control is living in the ui thread. The problem I have is that this iteration through the points gives me an exception from time to time. I guess, this is because The points are overwritten in the worker thread at the same time it iterates through the points.
I tried to lock the internalModel in the usercontrol and the dxModel1 within the viewmodel but that did not help me.
Am I right with my approach why it fails and if so, how could I overcome this issue?
if you are working with .net4.5, I think by using async-await in your method should take care of this issue. some link I came across with: http://www.i-programmer.info/programming/c/1514-async-await-and-the-ui-problem.html
I'm not sure that I fully understand your problem as you didn't tell us the Exception details, but if you just want to ensure that your code runs on the UI thread, you can do something like this:
RunOnUiThread((Action)delegate()
{
int length = internalModel.Series[i].Points.Count-1;
float lastX = internalModel.Series[i].Points[0].X;
for (int j = 0; j <= length; j++)
{
float x = ((float)targetImage.Width - 0) / (internalModel.Axes[0].Max - internalModel.Axes[0].Min) * (internalModel.Series[i].Points[j].X- lastX - internalModel.Axes[0].Min);
float y = (0 - (float)targetImage.Height) / (internalModel.Axes[1].Max - internalModel.Axes[1].Min) * (internalModel.Series[i].Points[j].Y - internalModel.Axes[1].Min) + (float)targetImage.Height;
tmpPoints.Add(new SharpDX.Vector2(x, y));
}
});
...
public object RunOnUiThread(Delegate method)
{
return Dispatcher.Invoke(DispatcherPriority.Normal, method);
}

How do I check the state of a thread

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();

Categories

Resources