This question already has answers here:
How do I update the GUI from another thread?
(47 answers)
Closed 8 years ago.
catch (Exception ex)\\error
{
clsLogs.LogError("Error: " + ex.Message + this.Name + " || ImportData");
result = false;
}
;Cross-thread operation not valid: Control 'cmbDeviceName' accessed from a thread other than the thread it was created on
You can do it like this using Invoke:
this.Invoke((MethodInvoker)delegate()
{
//// your code
});
class YourForm : Form
{
private SynchronizationContext synchronizationContext ;
public YourForm()
{
this.synchronizationContext = SynchronizationContext.Current;
//the rest of your code
}
}
and then, when you need to do some thread-unsafe form actualizations you should use something like this:
synchronizationContext.Send(new SendOrPostCallback(
delegate(object state)
{
textBoxOut.Text = "New text";
}
), null);
source codeproject
Related
Good day,
After being unsuccessful in my Google & Stackoverflow queries (not sure what I should search for), I'm posting here a public question.
I have a main form (frmMainMenu). Whenever this form is loaded and a button on this form is pressed, I'm trying to update a chart. However, as this could be CPU-demanding, I was considering calling the operation to retrieve the chart from another thread.
I'm constantly getting an error : Cross-thread operation not valid: Control 'labelX2' accessed from a thread other than the thread it was created on. System.Windows.Forms at System.Windows.Forms.Control.get_Handle()
The idea behind is also to display this symbol (referenced as the circularProgress1 control whenever data is being retrieved and to hide it whenever the operation is complete.
Here below is the code of my method in the userform :
[...]
private void feedDashboard()
{
Thread l_Thread;
ClsStartPgm l_Start = null;
try
{
this.Invoke(new MethodInvoker(delegate()
{
l_Thread = new Thread(() =>
{
try
{
l_Start = new ClsStartPgm();
l_Start.getDashboardInformations(
this.labelX2,
this.circularProgress1,
this.tmr_Progress,
this.chart1,
this.expandablePanel_1);
}
finally
{
// onCompleted();
}
});
l_Thread.Start();
}));
}
catch (Exception exc)
{
ClsFinappErrorManager.manageException(exc);
}
finally
{
}
}
[...]
and if it can be helpful, here is my mentioned getDashboardInformations method of my Class ClsStartPgm
public sealed class ClsStartPgm
{
[...]
// (Constructors, accessors and other methods not mentioned here
// to simplify the reading of my question)
[...]
public void getDashboardInformations(
LabelX pInformationText,
Controls.CircularProgress pCircularProgress,
System.Windows.Forms.Timer pTimer,
Chart pChart1,
ExpandablePanel pExpandablePanel1)
{
List<double> l_DoubleList = null;
List<string> l_StringList = null;
try
{
pTimer.Start();
this.m_Busy_Dashboard_Generation = true;
this.m_Busy_Dashboard_Generation = false;
double[] yValues = l_DoubleList.ToArray();
string[] xValues = l_StringList.ToArray();
pChart1.Series["MySerie"].Points.Clear();
// Populate series data
pChart1.Series["MySerie"].Points.DataBindXY(xValues, yValues);
// Set Doughnut chart type
pChart1.Series["MySerie"].ChartType = SeriesChartType.Pie;
// Set title of the expendable panel
pExpandablePanel1.TitleText = "Situation: " + DateTime.Now.ToShortDateString();
[...]
}
catch (Exception exc)
{
ClsFinappErrorManager.manageException(exc);
}
finally
{
l_Tuple = null;
l_Accounts = null;
}
}
}
Please, could anyone guide me on what's wrong in my code? I'm definitely not asking to get the code written for me. However, I would be keen on understanding what I'm doing incorrectly here in my approach.
Many thanks for your appreciated help and best wishes,
This question already has answers here:
How to call function from another form
(5 answers)
Closed 5 years ago.
in form1 , there are two functions , one for a button 's click event
private void bQuery_Click(object sender, EventArgs e)
{
string sPrefix = tbPrefix.Text.Trim();
QueryAll(sPrefix);
}
another one is a task
async Task QueryAll(string sPrefix)
{
}
now I need invoke form1 's task in form2 certain function , such as
string prefix = "abc";
frm = new form1();
frm.ShowDialog();
frm.Dispose();
frm.QueryAll(sPrefix);
I know this statement
frm.QueryAll(sPrefix);
can not compile , just to show what I want to do , anyone knows how to call this task "QueryAll" ? thanks for your help
it will be task
public Task QueryAll(string sPrefix)
{
return Task.Run(() =>
{
//code here
var foo = sPrefix;
});
}
then
frm = new form1();
frm.QueryAll(sPrefix).GetAwaiter().GetResult();
This question already has answers here:
Accessing UI (Main) Thread safely in WPF
(3 answers)
Closed 8 years ago.
why this code wont work without Dispatcher.RunAsync and what does it do? without Dispatcher its throwing error at copying value to textv.Text " thats its on different thread"
async void Current_GeofenceStateChanged(GeofenceMonitor sender, object args)
{
var reports = sender.ReadReports();
await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
foreach (var report in reports)
{
GeofenceState st = report.NewState;
Geofence gf2 = report.Geofence;
if (st == GeofenceState.Entered)
{
textv2.Text = "Hello"; //XAML TEXT
}
else if(st==GeofenceState.Exited)
{
textv2.Text = "Bye";
}
}
});
}
The Event Current_GeofenceStateChanged is being fired outside of the GUI thread and only the GUI thread can change GUI elements. Dispatcher.RunAsync says the code inside should run on the GUI thread so it works.
if you put the result on a string variable it will work if you only put:
Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => textv2.Text = StringVariable;);
EDIT: I only noticed that you have XAML code later you can just put the string on a property and bind the property to the text value of the text box letting you free from the Dispatcher.
<TextBox Text="{Binding StringVariable}"/>
and on the code just have
public string StringVariable { get; set; }
than on the method just set the value to the property
StringVariable = "bla bla";
This question already has answers here:
How do I update the GUI from another thread?
(47 answers)
Closed 9 years ago.
I have a problem. I'm trying to make seekbar for BASS in C#.NET (WPF) but when I'm starting a new Thread it can't get access to modify value of my Slider or Label (with current song position value). Here is a Code:
//class:
Thread seekbar;
public Window1()
{
InitializeComponent();
Bass.BASS_Init(-1, 44100, BASSInit.BASS_DEVICE_DEFAULT, IntPtr.Zero);
seekbar = new Thread(new ThreadStart(this.ThreadTask));
seekbar.IsBackground = true;
seekbar.Start();
}
private void ThreadTask()
{
int value = (int)Bass.BASS_ChannelGetPosition(music);
while (true)
{
MusicSeekBar.Value = value; //MusicSeekBar is mine Slider
CurrentValue.Content = value; //CurrentValue is a Label
}
}
I always get an error that thread can't get access to this two objects. Thanks for help in advice.
You need to call the MusicSeekBar & CurrentValue in a Dispatcher beceause the new thread doesn't have access to them.
Dispatcher.BeginInvoke(new Action(() =>
{
MusicSeekBar.Value = value; //MusicSeekBar is mine Slider
CurrentValue.Content = value; //CurrentValue is a Label
}));
Note: Part of a series: C#: Accessing form members from another class and How to access form objects from another cs file in C#.
Hello,
The Idea is to notify the user using the memo when a packet is received/sent in a TCP Client.
After couple of fixes,the most suitable solution seemed to be this one
public string TextValue
{
set
{
this.Memo.Text += value + "\n";
}
}
That's how it's being called
var form = Form.ActiveForm as Form1;
if(form != null)
form.TextValue = "Test asdasd";
However,calling the code throws an exception ,because of Unsafe thread call.I found a solution at msdn,but I can't seem to acquire the method they've used there.
This is my remake,which doesn't work.
private void SetTextMemo(string txt)
{
if(this.Memo.InvokeRequired)
{
this.Invoke(SetTextMemo,txt); //error here
}
else
{
this.Memo.Text += txt + "\n";
}
}
errors:
Argument '1': cannot convert from 'method group' to 'System.Delegate'
Argument '2': cannot convert from 'string' to 'object[]'
Basically,I'm trying to access the Memo(or more likely said,add text to the memo) from another thread using Invoke.I never used it before,maybe that's why I misunderstand my mistake.
The easy way is:
this.Invoke((MethodInvoker)delegate {
this.Memo.Text += txt + "\n";
});
Which uses an anonymous method to do the job inline. Since you expect to be on another thread, you may as well just call Invoke - it is safe even from the UI thread.
If you're using C# 3.0 and the 3.5 framework try the following
if ( this.Memo.InvokeRequired ) {
this.Invoke((Action)(() => SetTextMemo(txt)));
}
Your implementation assumes that the method will not infinitely recurse because the behavior of the InvokeRequired property will prevent it. This assumption may proove to be true, but there's no problem coding the function to avoid this possibility entirely. Here's what I suggest:
private void SetMemo(string txt)
{
Memo.Text = txt;
}
private delegate void MemoSetter(string txt);
public void ThreadSafeSet(string txt)
{
Invoke(new MemoSetter(SetMemo), txt);
}
I used to handle all this cross-thread business, but recently I went with AOP, where you simply decorate a method to execute on the UI thread. Here's an example (from PostSharp):
public class FormsThreadAttribute : OnMethodInvocationAspect
{
public override void OnInvocation(MethodInvocationEventArgs eventArgs)
{
Form f = (Form)eventArgs.Delegate.Target;
if (f.InvokeRequired)
f.Invoke(eventArgs.Delegate, eventArgs.GetArgumentArray());
else
eventArgs.Proceed();
}
}