I am using Telerik's radcontrols for winforms.
Here is a program that can reproduce my problem:
public partial class RadForm1 : Telerik.WinControls.UI.RadForm
{
public RadForm1()
{
InitializeComponent();
}
private void radButton1_Click(object sender, EventArgs e)
{
RadMessageBox.SetThemeName("Office2010Black");
RadMessageBox.Show("Hello World");
//MessageBox.Show("hello world");
run();
}
public void run()
{
var thread = new Thread(() => run2());
thread.IsBackground = true;
thread.Start();
}
public void run2()
{
//MessageBox.Show("hello");
RadMessageBox.Show("Hello");
}
}
Whenever try using Telerik's messagebox I am getting a cross thread exception. However if I use the standard winform messagebox instead then it will work absolutely fine.
Maybe i am missing something here.
UPDATE:
for anyone else having the same problem this is the link to offical reply Click here
The winform MessageBox class is specifically designed to be able to be called from a non-UI thread.
The RadMessageBox simply wasn't. It was designed under the assumption that it would be called from the UI thread.
Related
This question already has answers here:
Cross-thread operation not valid: Control accessed from a thread other than the thread it was created on
(22 answers)
Closed 3 years ago.
Apologies as I know cross-thread operations have been addressed elsewhere, but all I see are fragments and can't quite figure out where to apply the solutions correctly. So I have distilled this problem to it's most basic essence in the hope that me and anybody else who comes across this can see a complete solution without a lot of support code to wade through or fragments with limited context.
I have looked at various posts such as here, here and here but can't quite place the solutions in context.
I have created a Windows Forms project with a single button and textbox. In the form.cs file here is the complete code to demonstrate the problem:
using System;
using System.Windows.Forms;
using System.Threading;
namespace SampleEventTest
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Button1_Click(object sender, EventArgs e)
{
new Thread(() =>
{
Thread.CurrentThread.IsBackground = true;
TestClass();
}).Start();
}
private void TestClass()
{
TestEvent tv = new TestEvent();
tv.OnClsConnect += new TestEvent.clsConnect(OnConnected);
tv.DoSomethingThread();
}
public void OnConnected(string str)
{
textBox1.Text = str;
}
}
public class TestEvent
{
public delegate void clsConnect(string str);
public event clsConnect OnClsConnect;
public void DoSomethingThread()
{
if (OnClsConnect != null)
{
OnClsConnect("Thread run");
}
}
}
}
Click the button and you will get the "Cross thread operation not valid" error. How does one properly fix this code? TIA
Basically you can use the BackgroundWorker Control. here is a quick link. also here is an anther link which helps you.
also please read this:
How to: Make thread-safe calls to Windows Forms controls
H/T to S.A. Parkhid for this link.
Here is the solution: modify the method OnConnected to the following:
public void OnConnected(string str)
{
if (textBox1.InvokeRequired)
{
var d = new TestEvent.clsConnect(OnConnected);
textBox1.Invoke(d, new object[] { str });
}
else
{
textBox1.Text = str;
}
}
I have been searching for an answer to my particular problem for a while with no success.
I have a task in my program that takes a few seconds and I want to show a new form while that task is being done. The new form has a loadingbar and some text.
I need to show the new form parallel to the task otherwise the task will not start untill I close the new form.
This is the solution I have now:
private void loadingBar()
{
frmLoading frm = new frmLoading("Please wait while the database is being backed up", "This might take several days.");
frm.ShowDialog();
}
public void Backup()
{
Thread load = new Thread(new ThreadStart(loadingBar));
load.Start();
///Execute a task.
load.Abort();
}
So, this works OK but my question is: Wouldn't it be better to close the the form "frm" in the load-thread to make it stop?
You could do this a few ways...
1 - You could do as BendEg suggested and invoke you frmClose once you are ready
Something like;
Invoke(new Action(Close));
or
Invoke(new Action(() => frmMain.Close()));
2 - Or you could simply use a background worker;
The simplest way to demonstrate this would be to add a BackgroundWorker to your form, and use the events provided;
public Form1()
{
InitializeComponent();
backgroundWorker1.RunWorkerAsync();
MessageBox.Show(#"Please wait while the database is being backed up", #"This might take several days.");
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
Debug.WriteLine("Running"); //Execute a task
}
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
Debug.WriteLine("Ended"); //Dispose of any objects you'd like (close yor form etc.)
}
I hope this helps.
You can declare the form on Class-Level and later close it with an invoke.
MSDN-Windows Forms Invoke
Like this:
public class Class1
{
private Form myForm;
public Class1()
{
myForm = new Form();
}
public void DoSomeWork()
{
// ===================================================
// Do Some Work...
// ===================================================
myForm.Invoke(new MethodInvoker(this.Hide));
}
public void Hide()
{
myForm.Hide();
}
public void Backup()
{
myForm.ShowDialog();
Thread load = new Thread(new ThreadStart(DoSomeWork));
load.Start();
}
}
I think this can work for you.
void YourMethod()
{
WaitForm wf = new WaitForm();
Invoke(new PleaseWaitDelegate(Launch),wf);
bool val = BoolMethodDoWork();
Invoke(new PleaseWaitDelegate(Close), wf);
if(val)
{
MessageBox.Show("Success!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
return;
}
MessageBox.Show("Damn!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
}
delegate void PleaseWaitDelegate(Form form);
void Launch(Form form)
{
new System.Threading.Thread(()=> form. ShowDialog()).Start();
}
void Close(Form form)
{
form.Close();
}
I think this will help you (if i understood you right):
Parallel.Invoke(() => somemethod(), () =>
{
someothertaskmethod();
});
I placed methods as example to demonstrate 2 tasks running.
You nee to use the proper using statement using System.Threading.Tasks;
OK guys, I have this Class that shows a "Loading..." Splash Screen. It works great when I call it on Initialize() but not on Form_Load. Instead of showing at the beginning of Form_Load, it shows after all tables are filled and then just hangs there (no lock).
class innerLoad
{
//Delegate for cross thread call to close
private delegate void CloseDelegate();
//The type of form to be displayed as the splash screen.
private static frmLoading splashForm;
static public void ShowSplashScreen()
{
// Make sure it is only launched once.
if (splashForm != null)
return;
Thread thread = new Thread(new ThreadStart(innerLoad.ShowForm));
thread.IsBackground = true;
//Thread.Sleep(100);
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
}
//volatile static public bool isOpen = false;
static private void ShowForm()
{
splashForm = new frmLoading();
splashForm.ShowDialog();
splashForm.Dispose();
}
static public void CloseForm()
{
try
{
if (splashForm == null)
return;
splashForm.Invoke(new CloseDelegate(innerLoad.CloseFormInternal));
}
catch
{
}
}
static private void CloseFormInternal()
{
splashForm.Close();
splashForm = null;
}
}
And here is the Form_Load Code:
private void frmPayGen_Load(object sender, EventArgs e)
{
//th1 = new Thread(LoadingForm);
//th1.Start();
//Thread.Sleep(500);
innerLoad.ShowSplashScreen();
fill();
innerLoad.CloseForm();
//Thread.Sleep(500);
}
I appreciate your help and I love this site... helps me a lot :D
If you set a breakpoint at the start of your Form Load event, and use F11 to step through, you eventually see this exception:
Exceptions in a Form Load event are basically ignored. If an exception is thrown, nothing after the line where the exception was thrown runs, but the Windows Form doesn't crash either. Taking away this line of code should make things work as you wish.
I have a WPF UI called GUI.xaml and i need to change labels and images from other class. More over i need to perform a long task, so i'm using a background worker. So i've read a solution in this site:
In GUI.xaml.cs:
public static ChangeGUI someClass;
private void worker_DoWork(object sender, DoWorkEventArgs e)
{
someClass = new ChangeGUI(this); //
TaskClass.ConnectionThread(SuperHero.getUserID());
}
in ChangeGUI.cs:
public class ChangeGUI
{
GUI _GUIRef;
public ChangeGUI(GUI gui)
{
_GUIRef = gui;
}
public void ChangeLabel()
{
//here we can play with labels
}
public void ChangeMap(ImageSource tmp)
{
if (_GUIRef.image1.Dispatcher.CheckAccess())
_GUIRef.image1.Source = tmp;//ERROR!!!!!!!!!!!!!!
else
_GUIRef.image1.Dispatcher.Invoke(new Changer(ChangeMap), tmp);
}
}
Here i receive an error: The calling thread cannot access this object because a different thread owns it.
Help is welcome,
Thank You!
If you created the ImageSource on the background thread, make sure you freeze it so that it's accessible from any thread:
var imageSource = ...;
imageSource.Freeze();
I want to make server application. In the beginning it should make thread for organizing every connection and write logs in Listbox. I have problem because i don't know where can i make new thread which would have access to Form1.Listbox1. This is what i tried:
public class ServerLoop
{
Form1 form1;
public ServerLoop(Form1 f)
{
form1 = f;
}
public void loop()
{
form1.addConsoleMessage("test");
}
}
And Form1 class:
public partial class Form1 : Form
{
public Thread tServerLoop;
public ServerLoop serverLoop;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
console.Items.Clear();
players.Items.Clear();
players.Items.Add("Witaj w serwerze");
addConsoleMessage("test");
serverLoop = new ServerLoop(this);
tServerLoop = new Thread(serverLoop.loop);
tServerLoop.Start();
}
private void connectButton_Click(object sender, EventArgs e)
{
}
public void addConsoleMessage(String msg)
{
console.Items.Add(msg);
}
}
Anyone knows what can i do to acheive this?
Well, you could use Invoke to marshal a delegate back onto the UI thread where that ListBox can be safely accessed.
public void loop()
{
form1.Invoke(new Action(
() =>
{
form1.addConsoleMessage("test");
}));
}
But alas, this option is inferior. Actually, these marshaling techniques are generally terrible. Do not get me wrong. There is a time and place for Invoke (and the like), but this, like many situations, is not one of them.
The code is ugly because you have to sprinkle Invoke calls all over the place.
It forces you into a design where the UI thread and worker thread are tightly coupled.
The worker thread is dictating the update frequency of the UI.
It is inefficient.
It can flood the UI message queue (at least it could with BeginInvoke).
The worker thread has to wait for a response from the UI thread before it can proceed (it will with Invoke anyway).
So how would I solve this problem? Well, with the boring old System.Windows.Forms.Timer and the fancy new ConcurrentQueue<T> of course.
public partial class Form1 : Form
{
private ConcurrentQueue<string> queue = new ConcurrentQueue<string>();
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
console.Items.Clear();
console.Items.Add("test");
players.Items.Clear();
players.Items.Add("Witaj w serwerze");
Task.Factory.StartNew(
() =>
{
while (GetSomeCondition())
{
string value = GetSomeValue();
queue.Enqueue(value);
}
});
}
private void YourTimer_Tick(object sender, EventArgs e)
{
string value;
while (queue.TryDequeue(out value)
{
console.Items.Add(value);
}
}
}
So what do we have now.
It looks elegant.
Our background task knows only about a queue. The tight coupling has been broken.
The UI thread is now dictating the update frequency...the way it should be.
It is a lot more efficient.
There is no chance that the UI message queue will get flooded.
And finally, the worker can speed along merrily completely unware of what the UI thread is doing.
This solution is not completely devoid of disadvantages though. Now that we have our worker thread speeding along it is possible that it produces more items for the queue then what the UI thread can consume. It would not typically be a problem, but there are techniques for dealing with that.