Model as dependency property used within different threads - c#

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

Related

How to make a C# method cancellable?

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

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.

How to refresh canvas

I am trying to create a visual representation of any sorting algorithm where the data is represented in an int[] array. An example of bubble sort on wikipedia:
My sorting algorithms all raise an event ItemsSwapped when two items in the int[] array are swapped. I am trying to display the data after every event on canvas, this is my code:
// Handler for ItemsSwapped event.
private void Render(object sender, ItemsSwapEventArgs e)
{
canvas.Children.Clear();
int numberOfElements = e.Data.Length;
for (int x = 0; x < numberOfElements; x++)
{
RenderValue(x, e.Data[x]);
}
// Here I should somehow refresh canvas.
}
private void RenderValue(int x, int y)
{
var value = new Ellipse
{
Width = 5,
Height = 5,
Stroke = Brushes.Black,
StrokeThickness = 2,
};
Canvas.SetTop(value, x);
Canvas.SetLeft(value, y);
canvas.Children.Add(value);
}
The problem is, that the canvas doesn't refresh itself, it just displays the final solution after some time. How can I refresh it after every raised event?
Edit - I tried with UpdateLayout, InvalidateMeasure and Dispatcher object, but neither worked.
Maybe you start your sort algorithm on the UI thread, so it won't update until finished. Try sorting in another thread and update the Canvas children using the Dispatcher, by calling Invoke or BeginInvoke.
If your ItemsSwapped handler is called from a separate thread, it may look like this:
private void Render(object sender, ItemsSwapEventArgs e)
{
Dispatcher.Invoke((Action)(() =>
{
canvas.Children.Clear();
int numberOfElements = e.Data.Length;
for (int x = 0; x < numberOfElements; x++)
{
RenderValue(x, e.Data[x]);
}
}));
}
Are you using threads? You must do your work in a separate thread from the main UI. Here is a link to get you started: How to update the GUI from another thread in C#?

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

Adding multiple expanders event programmatically wont work

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

Categories

Resources