Hi guys I receive an exception if (checkBox1.IsChecked == true || checkBox2.IsChecked == true):
The calling thread cannot access this object because a different
thread owns it.
in my wpf app:
private void button1_Click(object sender, RoutedEventArgs e)
{
int i = 0;
int j = Int32.Parse(textBox1.Text);
thr = new Thread[j];
for (; i < j; i++)
{
thr[i] = new Thread(new ThreadStart(go));
thr[i].IsBackground = true;
thr[i].Start();
}
}
public void go()
{
while (true)
{
string acc = "";
string proxy = "";
if (checkBox1.IsChecked == true || checkBox2.IsChecked == true)
{
if (checkBox1.IsChecked == true)
Proxy.type = "http";
else if (checkBox2.IsChecked == true)
Proxy.type = "socks5";
else
Proxy.type = "none";
proxy = rand_proxy();
}
}
}
Why?
You cannot access UI elements from a thread other than one which was those created. Your check boxes are created on UI thread and you can access these only on UI thread.
try this.
public void go()
{
Dispatcher.BeginInvoke(new Action(()=>{
while (true)
{
string acc = "";
string proxy = "";
if (checkBox1.IsChecked == true || checkBox2.IsChecked == true)
{
if (checkBox1.IsChecked == true)
Proxy.type = "http";
else if (checkBox2.IsChecked == true)
Proxy.type = "socks5";
else
Proxy.type = "none";
proxy = rand_proxy();
}
}), null);
}
You cannot access UI elements on a different thread than the UI. To work around this, you can check
checkBox1.Dispatcher.CheckAccess()
and if true, use
checkBox1.Dispatcher.Invoke
or
checkBox1.Dispatcher.BeginInvoke
Use CheckAccess to see if you need call Dispatcher.BeginInvoke or Invoke
See also this post
Basically you're not allowed to access controls from threads other than the thread they were created on. There's a good explanation of the WPF threading model here, and this walks through the issue you are describing.
Good luck.
Related
I have been trying to work out why my background worker is 'finishing' its work when there is still a lot for it to do. I am actually in the process of refactoring the code for this app, so it did work in the past, but now I am unable to figure out what has gone wrong.
Specifically, the app should open Outlook and then perform a few checks. However, the background worker exits straight after Outlook is opened for no apparent reason (as you will se below there is still plenty of processing to be done).
This appears to be happening early on in the Start() method, directly after calling Process.Start() on Outlook.exe.
The code runs in this order:
calling the background worker - this was the user's choice from a radio set
....
else if (radioButton5.Checked == true)
{
textBox1.Text = "Please wait while your session restarts";
pageControl1.SelectedIndex = 10;
backgroundReset.RunWorkerAsync();
}
The do-work method
public void backgroundReset_DoWork(object sender, DoWorkEventArgs e)
{
backgroundReset.WorkerSupportsCancellation = true;
Session.Reset();
}
the reset session method starts by killing the current session ...
public static void Reset()
{
KillSession();
System.Threading.Thread.Sleep(5000);
Start();
// THE BACKGROUNDWORKER EXITS BEFORE HERE!
if (IsLoggedIn() == false)
{
return;
}
else
{
// Make sure Lync is open before finishing the process ...
var j = 0;
GetSession(Init.servers);
j = 0;
var checker = false;
checker = ProcessHandler.CheckRunning("lync.exe");
while (checker == false)
{
if (j == 100)
{
break;
}
Thread.Sleep(500);
checker = ProcessHandler.CheckRunning("lync.exe");
j++;
}
}
}
As you can see from the comment, the backgroundworder is calling RunWorkerCompleted way before the Reset() method has finished executing.
Below are the other methods called (kill, logoff, start):
KillSession logs the session of and then makes sure it is logged off
private static void KillSession()
{
if (sessionId != null)
{
LogOff();
for (int i = 0; i < 150; i++)
{
if (IsLoggedIn() == true)
{
Thread.Sleep(500);
}
else
{
break;
}
}
}
}
LogOff sends a Cmd command to log off the current session
public static void LogOff()
{
string strCmdIn = "/C LOGOFF " + sessionId + " /SERVER:" + serverName;
Cmd.Exec(strCmdIn);
}
Start() Simply opens Outlook, causing a Citrix session to also start. The app is definitely launching Outlook, but after that it doesn't reach either of the for statements - the BackgroundWorker just exits.
public static void Start()
{
Process.Start(appDataCitrix + "Outlook.exe");
for (int i = 0; i < 15; i++)
{
if (IsLoggedIn2() == false)
{
Thread.Sleep(1000);
}
else
{
break;
}
}
if (IsLoggedIn2() == false)
{
Process.Start(appDataCitrix + "Outlook.exe");
for (int i = 0; i < 10; i++)
{
if (IsLoggedIn2() == false)
{
Thread.Sleep(1000);
}
else
{
break;
}
}
}
}
Does anyone have any idea what is going on here? It is driving me crazy!
Many thanks
Update
The RunWorkerCompleted Method:
As far as my understanding goes, this has no baring on when the process will finish.
public void backgroundReset_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (Session.IsLoggedIn())
{
btnFailFinish.Visible = true;
label10.Text = Session.serverName;
pageControl1.SelectedIndex = 3;
}
else
{
pageControl1.SelectedIndex = 10;
pictureBox2.Visible = false;
textBox1.Text = "Double-click Outlook on your desktop to launch a new session.";
textBox15.Text = "Once you have done this please click Finish.";
pictureBox9.Visible = true;
}
}
This is probably because of an exception being thrown from within the start method.
You may either add a try / catch block all around this method and handle the error from within the catch, or check in the RunWorkerCompleted method if an exception occurred :
private void RunWorkerCompleted (object sender, RunWorkerCompletedEventArgs e)
{
if (e.Error != null)
{
// handle your exception here
}
}
I have a datatemplate in which i have a text block and speech synthesizer. Whwn i bind it with data the template spawns atleast 3 children. A speech synthesizer is activated on click of one checkbox. It works fine in normal conditions. But if i test it vigorously and try to play more than one synthesizer before initialization, it plays unexpected audio. And it continue even after exiting from that page.
I am sharing code for check box click event. Please suggest a solution.
private async void checkboxPlay_Click(object sender, RoutedEventArgs e)
{
// when _mediaCounter == 0, synthesizer is stopped or not played
// when _mediaCounter == 1, it is playing
// when _mediaVounter == 2, it is paused
Grid gd = (Grid)((sender as CheckBox).Parent as Grid).Parent;
var child = VisualTreeHelper.GetParent(gd);
try
{
if (sender is CheckBox)
{
if (_listElement.Count > 0)
{
if (sender != _listElement[_checkCounter].CheckBox && _listElement[_checkCounter].CheckBox != null)
{
_listElement[_checkCounter].MediaElement.Stop();
_mediaCounter = 0;
_timer.Stop();
_listElement[_checkCounter].Slider.Value = 0;
_description = string.Empty;
_listElement[_checkCounter].CheckBox.IsChecked = false;
}
}
CheckBox cb = sender as CheckBox;
Grid x = (Grid)VisualTreeHelper.GetParent(cb);
_mediaIndex = Convert.ToInt32(
x.DataContext.ToString().Substring(x.DataContext.ToString().Length - 1, 1)
) - 1;
_checkCounter = _mediaIndex;
if (_description != cb.DataContext.ToString())
{
cb.IsChecked = true;
_description = cb.DataContext.ToString();
_mediaCounter = 0;
_InitializeCheckbox(cb);
_InitializeMedia();
}
}
if (_mediaCounter == 0)
{
_mediaCounter = 1;
string desc = string.Empty;
SpeechSynthesizer synth = new SpeechSynthesizer();
SpeechSynthesisStream stream = await synth.SynthesizeTextToStreamAsync(_description.ToString());
_listElement[_checkCounter].MediaElement.SetSource(stream, stream.ContentType);
_listElement[_checkCounter].MediaElement.Play();
}
else if (_mediaCounter == 1)
{
_listElement[_checkCounter].MediaElement.Pause();
_timer.Stop();
_mediaCounter = 2;
}
else
{
_listElement[_checkCounter].MediaElement.Play();
_timer.Start();
_mediaCounter = 1;
}
}
catch
{
}
}
Have you tried using the MediaElement.CurrentState property?
MediaElement.CurrentState
here's a link
http://msdn.microsoft.com/En-US/Library/Windows/Apps/windows.ui.xaml.controls.mediaelement.currentstate
I have this button5 function below. What I want is when the use wants to click button1 after clicking button5 the while loop in button5 should break, because the choice is now 1. Choice is a global variable set to zero at the start. While the button5 function is running the button1 function will not be called on click. How to solve this problem?
This is the Answer Thanks Everyone For the Help!!
private Thread demoThread = null;
delegate void SetTextCallback(string text);
private void button1_Click(object sender, EventArgs e)
{
choice = 1;
System.Console.WriteLine(choice);
}
private void button5_Click(object sender, EventArgs e)
{
//button1.Enabled = false;
button5.Visible = false;
panel2.Visible = true;
panel1.Visible = true;
panel3.Visible = true;
label2.Visible = true;
button1.Visible = true;
button2.Visible = true;
button3.Visible = true;
button4.Visible = true;
this.demoThread = new Thread(new ThreadStart(this.StartForLoop));
this.demoThread.Start();
}
private void StartForLoop()
{
while (choice != 1 || choice != 2 || choice != 3)
{
if (choice == 1 )
{
choice = 1;
break;
}
if (choice == 2)
{
choice = 2;
break;
}
if (choice == 3)
{
choice = 3;
break;
}
Application.DoEvents();
}
System.Console.WriteLine("AAA");
if (choice == 3)//why
{
}
if (choice == 1)//true
{
System.Console.WriteLine("label");
this.SetText("Does the animal lay eggs?");
}
if (choice == 2)//false
{
}
}
This is a wrong concept. Never use Application.DoEvents();, it's a hack. It does not solve any of your problems.
You do not need a while loop in Button5_Click. Everything in that loop could be handled by code in your other click handler.
Your problem can probably be solved by a state machine. This looks complicated, but it#s not. Try to implement it as simple as possible and ask another question when you encounter problems.
You have a problem with Thread's, the problem is that you program Thread is busy in the loop of your button5 and until it finishes handling button5 code, your thread will not pay attention to more anything.
To solve this, you must run your while loop inside of new thread like this:
Thread t = new Thread (new ThreadStart(delegate(){
//while goes here along with the if's...
}));
t.Start();
In your button1, when you change the value of your global variables
the code inside of a thread launched in the button5 will now be aware of
your changes and behave accordingly.
Also be very careful with the following, since choice is a global variable
it can be access by two threads now at the same time, the program thread
and your new thread, because of this ensure you access the choice variable
with mutexs, in c# you can access a thread shared variable like this:
//declare this next to your choice variable.
Object mux_choice = new Object();
lock(mux_choice){
//changing choice here is thread safe.
}
Since choice seems to be a value type, you must create a object representing the access to your value type variable (http://msdn.microsoft.com/en-us/library/c5kehkcz.aspx).
You have more info about threads in C# here:
http://www.albahari.com/threading/
Note: Make sure you protect the choice variable everywhere it is used.
Also, from your comments I assume that you want to modify the Form controls
properties, like label2.Text="..." becarefull with that, you will face Cross Thread Exceptions if you do that. To modify a Controls property you must call the Invoke method, that invokes the change in the UI thread, like this:
label2.Invoke((MethodInvoker)(() => label2.Text = "some text"));
Depending on the .NET framework version, here is a code compatible with .NET 2.0:
label2.Invoke(new MethodInvoker(delegate(){ label2.Text = "some text"; }));
Regards.
The best way is to run a for each loop into another thread so it will not disturb the UI of form.
and user can easily click on button 1.
like just for basic idea :
private void button5_Click(object sender, EventArgs e)
{
button5.Visible = false;
panel2.Visible = true;
panel1.Visible = true;
panel3.Visible = true;
label2.Visible = true;
button1.Visible = true;
button2.Visible = true;
button3.Visible = true;
button4.Visible = true;
Thread thread = new Thread(new ThreadStart(StartForLoop));
thread.Start();
}
public void StartForLoop()
{
while (choice != 1 || choice != 2 || choice != 3)
{
if (choice == 1 || choice == 2 || choice == 3)
{
choice = 1000;
break;
}
Application.DoEvents();
}
if(choice==3)//why
{
}
if(choice==1)//true
{
label2.Text = "asdasd";
}
if(choice==2)//false
{
}
}
PS : better to implement lock on choice as well
Hi guys I have such construction:
Start threads:
Thread[] thr;
int good_auth, bad_auth, good_like, bad_like;
static object accslocker = new object();
static object limitlocker = new object();
string acc_path, proxy_path, posts_path;
int position_of_limit, position = 0;
private void button1_Click(object sender, EventArgs e)
{
button1.Enabled = false;
button2.Enabled = true;
decimal value = numericUpDown1.Value;
int i = 0;
int j = (int)(value);
thr = new Thread[j];
for (; i < j; i++)
{
thr[i] = new Thread(new ThreadStart(go));
thr[i].IsBackground = true;
thr[i].Start();
}
}
And than function go:
public void go()
{
while (true)
{
string acc = "";
string proxy = "";
lock (limitlocker)
{
if (position_of_limit >= int.Parse(textBox2.Text) - 1)
{
position_of_limit = 0;
if (position < posts.Count - 1)
position++;
else
{
break;
}
}
}
lock (accslocker)
{
if (accs.Count == 0)
{
break;
}
else
acc = accs.Dequeue();
}
OD od = new OD(acc);
string login = od.Auth();
if (login == "Login")
{
lock (accslocker)
{
good_auth++;
log_good_auth(good_auth);
}
string like = od.like(posts[position], textBox1.Text);
if (like == "Good")
{
lock (accslocker)
{
position_of_limit++;
good_like++;
log_good_like(good_like);
}
}
else if (like == "Failed")
{
lock (accslocker)
{
bad_like++;
log_bad_like(bad_like);
}
}
else
{
lock (accslocker)
{
bad_like++;
log_bad_like(bad_like);
}
}
}
else if (login == "Spamblock")
{
lock (accslocker)
{
bad_auth++;
log_bad_auth(bad_auth);
}
}
else if (login == "Locked")
{
lock (accslocker)
{
bad_auth++;
log_bad_auth(bad_auth);
}
}
else if (login == "Invalid")
{
lock (accslocker)
{
bad_auth++;
log_bad_auth(bad_auth);
}
}
else if (login == "Bad_proxy")
{
lock (accslocker)
{
accs.Enqueue(acc);
Proxy.proxies.Remove(proxy);
}
}
else
{
lock (accslocker)
{
accs.Enqueue(acc);
Proxy.proxies.Remove(proxy);
}
}
}
}
I start for example 20 threads, when position_of_limit becomes bigger than int.Parse(textBox2.Text) - 1 all threads need to take next posts[position] in next loop. But I receive an exception on line string like = od.like(posts[position], textBox1.Text);
"Index was out of range. Must be non-negative and less than the size of the collection.
Parameter name: index"
How to solve this problem? Thanks
Locking the GUI thread is evil, since it's an STA thread.
That means it must manage a message loop and is not allowed to block. So blocking is likely to cause deadlocks.
Rather use callbacks like BackgroundWorker.RunWorkerCompleted.
Some other informative links about locking:
Guidelines of when to use locking
Obtaining lock on a UI thread
I'm having a problem with outputting to textblock. Basicly what I do is this:
private void ReadData()
{
double dHeading = 0;
int iHeading = 0;
String sString = "";
while (!stop)
{
//Get Heading
result = fsuipc.FSUIPC_Read(0x0580, 4, ref token, ref dwResult);
result = fsuipc.FSUIPC_Process(ref dwResult);
result = fsuipc.FSUIPC_Get(ref token, ref dwResult);
dHeading = dwResult;
if (dHeading != 0)
{
dHeading = dHeading * 360 / (65536.0 * 65536.0);
iHeading = Convert.ToInt32(dHeading);
}
if (iHeading < 0)
{
iHeading = 360 + Convert.ToInt32(dHeading);
}
if (iHeading == 0)
{
iHeading = 360;
}
if (result == true && iHeading < 10)
{
sString = "00" + Convert.ToString(iHeading);
}
if (result == true && iHeading >= 10 && iHeading < 100)
{
sString = "0" + Convert.ToString(iHeading);
}
if (result == true && iHeading >= 100)
{
sString = Convert.ToString(iHeading);
}
txbHeading.Text = sString;
// But if I change this line to MessageBox.Show(sString);
// it works fine.
}
}
The program freezes and I can't do anything with it. I have to stop it in VS .
If I change the txbHeading.Text = sString to MessageBox.Show(sString), it works fine.
Please note that I just started with C#.
Thanks in advance!
The while loop in your code causes the UI thread to block, so the program should stop responding when the method is called. A background worker allows your code to be executed in a seperate thread without blocking the GUI.
try
this.Invoke(new Action(() => txbHeading.Text = sString))
instead. i assume you running outside the UI thread.
More on this: The Practical Guide to Multithreading - Part 1