I am trying to update a text box. I thought my threading code would fix the problem, but it does not. Can anyone help with this?
new Thread((ThreadStart)delegate { txtCapacitance.Text = Math.Round(capacitance, 3).ToString(); }).Start();
Gives the following error:
Cross-thread operation not valid:
Control 'txtCapacitance' accessed from
a thread other than the thread it was
created on.
Note that all this is being started by a dataReceived function which is called whenever USB data is received.
UI objects can only be called from the UI thread. This can be accomplished via the Control's Invoke method:
txtCapacitance.Invoke((Action)(() => { txtCapacitance.Text = Math.Round(capacitance, 3).ToString(); }));
You should rather have a look at using BackgroundWorker Class
Have a look at
C# BackgroundWorker Tutorial.
Updates to any UI element must be done on the UI-thread. You can certainly calculate your value on another thread, but you must use the .Invoke(...) method of the control to perform the update.
try this one
//delegate
delegate void updateTextboxDelegate(string value);
private void updateDisplay(string value)
{
txtCapacitance.Text = value;
}
//the thread
string msg = string.empty;
var th =new Thread(()=>{BeginInvoke(new updateTextboxDelegate(updateDisplay), msg); });
th.Start();
Hope that will work for you.
You need to make sure that you update textBox from same thread as you have created it.
For this purpose create yourself class helper like this and use this extensions instead of using normal way (here are couple of extensions i made for myself, but the one interesting you is changeText):
public static class ControlExtensions {
public static void changeStatus(this Control varControl, bool varState) {
if (varControl.InvokeRequired) {
varControl.BeginInvoke(new MethodInvoker(() => changeStatus(varControl, varState)));
} else {
varControl.Enabled = varState;
}
}
public static void changeText(this Control varControl, string varText) {
if (varControl.InvokeRequired) {
varControl.BeginInvoke(new MethodInvoker(() => changeText(varControl, varText)));
} else {
varControl.Text = varText;
}
}
public static DateTime readDateValue(this DateTimePicker varControl) {
if (varControl.InvokeRequired) {
return (DateTime) varControl.Invoke(new Func<DateTime>(() => readDateValue(varControl)));
} else {
return varControl.Value;
}
}
public static bool ReadStatus(this CheckBox varControl) {
if (varControl.InvokeRequired) {
return (bool) varControl.Invoke(new Func<bool>(() => ReadStatus(varControl)));
}
return varControl.Checked;
}
public static bool ReadStatus(this RadioButton varControl) {
if (varControl.InvokeRequired) {
return (bool) varControl.Invoke(new Func<bool>(() => ReadStatus(varControl)));
}
return varControl.Checked;
}
public static string readText(this Control varControl) {
if (varControl.InvokeRequired) {
return (string) varControl.Invoke(new Func<string>(() => readText(varControl)));
} else {
return varControl.Text;
}
}
public static bool readEnabled(this Control varControl) {
if (varControl.InvokeRequired) {
return (bool) varControl.Invoke(new Func<bool>(() => readEnabled(varControl)));
} else {
return varControl.Enabled;
}
}
}
Then you use it like this: txtCapacitance.changeText("new text");
Related
I want to send a progress bar that is available on my form to a function to display the progress of the operation of that function and finally return true if everything is fine and return false if else
The operation inside the SaveBadCustomerMustStayMasdoodExcelFile function is executed asynchronously so as not to interfere with the execution of other operations.
When the program runs and the compiler calls the line _ProgressBar.Invoke((MethodInvoker)(() => {_ProgressBar.Value = Convert.ToInt32(i);})); Inside the badCustomers.SendToDB(progressBar_BadCustomers) function, there is no feedback and the program seems to be stuck in an infinite loop.
But if the output of the SaveBadCustomerMustStayMasdoodExcelFile function is defined as void, everything works fine.
My code when the system hangs:
In Button:
private void btn_ChoiceBadCustomersFile_Click(object sender, EventArgs e)
{
try
{
DialogResult dialogResult = MessageBox.Show("message", "title",
MessageBoxButtons.YesNo);
if ((dialogResult == DialogResult.Yes))
{
bool result = false;
try
{
result = GetDataFromExcelFile.SaveBadCustomerMustStayMasdoodExcelFile(
progressBar_BadCustomers).Result;
}
catch
{
result = false;
}
if (result)
{
//code...
}
}
}
catch
{
//code...
}
}
Code In GetDataFromExcelFile.SaveBadCustomerMustStayMasdoodExcelFile(...)
public static class GetDataFromExcelFile
{
public async static Task<bool> SaveBadCustomerMustStayMasdoodExcelFile(
DevComponents.DotNetBar.Controls.ProgressBarX progressBar_BadCustomers)
{
try
{
PoomaDbAppEntities DB10 = new PoomaDbAppEntities();
IQueryable<tbl_BadCustomers> dt = null;
MyExcelWorkSpace _excelApp = new MyExcelWorkSpace();
MyExcelWorkSpace.badCustomers badCustomers = new MyExcelWorkSpace
.badCustomers();
string path = badCustomers.select();
if (path != String.Empty)
{
if (badCustomers.Open(path))
{
try
{
await Task.Run(() => { dt = badCustomers
.SendToDB(progressBar_BadCustomers); });
return true;
}
catch
{
return false;
}
}
else
{
return false;
}
}
else
{
return false;
}
}
catch
{
return false;
}
}
}
And In badCustomers.SendToDB(...) :
public class badCustomers : ExcelFile, IStartWorkWithExcelFile<tbl_BadCustomers>
{
//code
public IQueryable<tbl_BadCustomers> SendToDB(DevComponents.DotNetBar
.Controls.ProgressBarX _ProgressBar)
{
try
{
//code
_ProgressBar.Invoke((MethodInvoker)(() => {
_ProgressBar.Value = Convert.ToInt32(i); }));
}
catch
{
//code
}
}
IQueryable<tbl_BadCustomers> dt = DB10.tbl_BadCustomers.Select(i => i);
return dt;
}
}
If the SaveBadCustomerMustStayMasdoodExcelFile function is defined as below, the program works, but I need to know if an error has occurred or not.
public async static void SaveBadCustomerMustStayMasdoodExcelFile(
DevComponents.DotNetBar.Controls.ProgressBarX progressBar_BadCustomers)
{
//code
}
If the SaveBadCustomerMustStayMasdoodExcelFile function is defined as below, the program works, but I need to know if an error has occurred or not.
public async static void SaveBadCustomerMustStayMasdoodExcelFile(
DevComponents.DotNetBar.Controls.ProgressBarX progressBar_BadCustomers)
{
//code
}
there is no feedback and the program seems to be stuck in an infinite loop.
This is because the code is using Result; full details on my blog.
To solve this, you want to avoid async void (i.e., for SaveBadCustomerMustStayMasdoodExcelFile); async void is intended for event handlers, so you can make btn_ChoiceBadCustomersFile_Click an async void method. Everything else should use await and async Task.
As far as the Progress goes, I echo the recommendations in the comments: IProgress<T> with Progress<T> makes your code cleaner (e.g., no Invoke necessary).
Don't now if title is clear. Here is a piece of code from a class in charge of managing a long operation :
public class LongProcess
{
public delegate void RunningChangedEventHandler(bool running);
public event RunningChangedEventHandler RunningChanged;
private object runningLock = new object();
public bool Running
{
get { lock (runningLock) { return mRunning; } }
set
{
lock (runningLock)
{
RunningChanged.Invoke(value);
value = mRunning;
}
}
}
public void start()
{
mWorker = new BackgroundWorker();
mWorker.DoWork += Bg_DoWork;
mWorker.RunWorkerAsync();
}
private void Bg_DoWork(object sender, DoWorkEventArgs e)
{
Running = true;
// Some things to do here ... but I need Running to be equals to true and it is not
}
}
In main programm, I use LongProcess to start some tasks, it is completed by report progression etc ...
The only problem I'm facing, is that it seems that I'm unable to set "Running" to true. Even right after the call to the setter, it still keeps its old value.
Any help and explanations on how this works will be greatly appreciated !
You have your value and field the wrong way around in the setter. You need this:
public bool Running
{
get { lock (runningLock) { return mRunning; } }
set
{
lock (runningLock)
{
RunningChanged.Invoke(value);
mRunning = value; // <=== LOOK HERE
}
}
}
I want all the methods of my class to be allowed to be called only from the same thread that the object was created on. The same way as Windows Forms controls do not allow their method/properties to be accessed on any other thread except the UI thread and they throw an exception if you try to do that. What are the winforms' controls doing in order to enforce such behavior? Is there anything that I can use to annotate the methods (like some special attribute) or I have to handle those situations "by hand"?
EDIT 1:
Here is the code of the Handle property getter of the WinForms' Control class
public IntPtr Handle {
get {
if (checkForIllegalCrossThreadCalls &&
!inCrossThreadSafeCall &&
InvokeRequired) {
throw new InvalidOperationException(SR.GetString(SR.IllegalCrossThreadCall,
Name));
}
if (!IsHandleCreated)
{
CreateHandle();
}
return HandleInternal;
}
}
This is the code of InvokeRequired of the WinForms' Control class
public bool InvokeRequired {
get {
using (new MultithreadSafeCallScope())
{
HandleRef hwnd;
if (IsHandleCreated) {
hwnd = new HandleRef(this, Handle);
}
else {
Control marshalingControl = FindMarshalingControl();
if (!marshalingControl.IsHandleCreated) {
return false;
}
hwnd = new HandleRef(marshalingControl, marshalingControl.Handle);
}
int pid;
int hwndThread = SafeNativeMethods.GetWindowThreadProcessId(hwnd, out pid);
int currentThread = SafeNativeMethods.GetCurrentThreadId();
return(hwndThread != currentThread);
}
}
}
Looking at this code I can see one solution to the problem will be in the constructor of the object we store the current thread id in private field and then on every subsequent call we check if the current thread id differs from the id we have stored, throwing InvalidOperationException if that's the case. Do you find any problems with the aforementioned solution or do you know a better approach?
static class Program
{
static void Main()
{
MySafeClass c = new MySafeClass();
Task.Factory.StartNew(() => c.Operation1(), TaskCreationOptions.LongRunning); // This should throw an exception
}
}
class MySafeClass
{
private readonly int creationThreadId;
public MySafeClass()
{
creationThreadId = Thread.CurrentThread.ManagedThreadId;
}
private void CheckCrossThreadOperation()
{
if (this.creationThreadId != Thread.CurrentThread.ManagedThreadId)
{
throw new InvalidOperationException("Cross thread operatoin is not allowed");
}
}
public void Operation1()
{
CheckCrossThreadOperation();
// ...
}
public void Operation2()
{
CheckCrossThreadOperation();
// ...
}
}
I have a Silverlight app that uses actions to get data from the model (which again gets the data from WCF services).
I need to somehow sync two ActionCallbacks, or wait for them, and then execute some code.
Example:
_model.GetMyTypeList(list =>
{
MyTypeList.AddRange(list);
});
_model.GetStigTypeList(list =>
{
StigTypeList.AddRange(list);
});
doSomethingWhenBothHaveReturned();
I know I can use a counter to keep track of how many has returned, but is there not a better way to do this?
EDIT: user24601 has a good answer, but CountdownEvent does not exist in silverlight, any other great ideas? :)
Yes, a counter is what you need. The 'more elegant' solution would be to use a countdown event:
using (CountDownEvent countDownEvent = new CountDownEvent(2))
{
_model.GetMyTypeList(list =>
{
MyTypeList.AddRange(list);
countDownEvent.Signal();
});
_model.GetStigTypeList(list =>
{
StigTypeList.AddRange(list);
countDownEvent.Signal();
});
countdownEvent.Wait();
doSomethingNowThatWereComplete();
}
Solved the problem my self, using a counter:
public class ActionWaitHandler
{
private int _count;
private readonly Action _callback;
public ActionWaitHandler(int count, Action callback)
{
_count = count;
_callback = callback;
}
public void Signal()
{
_count--;
if (_count == 0)
{
_callback();
}
}
}
usage:
public void method() {
var handler = new ActionWaitHandler(2, OnActionsComplete);
_model.GetMyTypeList(list =>
{
MyTypeList.AddRange(list);
handler .Signal();
});
_model.GetStigTypeList(list =>
{
StigTypeList.AddRange(list);
handler .Signal();
});
}
public void OnActionsComplete()
{
dosomething;
}
C# 2008 SP1
The function below will be called from another thread. So the control themselves will have to be invoked so that the correct thread that created them can change the properties.
However, as I have many controls that need to be updated. I don't really want to write all those delegates for each one. I have done one below. However, I am thinking that is a lot of code. Is there anyway to shorten this?
Many thanks,
public void SetIdleState(string callStatusMsg)
{
this.btnCallAnswer.Text = CATWinSIP_MsgStrings.Call;
this.btnEndCallReject.Text = CATWinSIP_MsgStrings.EndCall;
this.btnHoldUnhold.Text = CATWinSIP_MsgStrings.Hold;
this.btnCallAnswer.Enabled = true;
this.btnRedial.Enabled = true;
this.btnEndCallReject.Enabled = false;
this.btnHoldUnhold.Enabled = false;
if (this.statusDisplay1.InvokeRequired)
{
statusDisplay1.Invoke(new UpdateCallStatusDelegate(this.UpdateCallStatus), callStatusMsg);
}
else
{
this.statusDisplay1.CallStatus = callStatusMsg;
}
}
// Delegate for marshalling the call on the correct thread.
private delegate void UpdateCallStatusDelegate(string callStatusMsg);
private void UpdateCallStatus(string callStatusMsg)
{
this.statusDisplay1.CallStatus = callStatusMsg;
}
How about something like:
Dispatcher.BeginInvoke(new DispatcherOperationCallback((param) =>
{
this.statusDisplay1.CallStatus = callStatusMsg;
return null;
}), DispatcherPriority.Background, new object[] { null });
}
I asked a similar question . The answer that was provided by Jon Skeet is the best approach I have come across. The relevant code is below.
Create a static helper method:
public static void InvokeIfNecessary(UIElement element, MethodInvoker action)
{
if (element.Dispatcher.Thread != Thread.CurrentThread)
{
element.Dispatcher.Invoke(DispatcherPriority.Normal, action);
}
else
{
action();
}
}
In your example you could use it as:
InvokeIfNecessary(statusDisplay1, delegate {statusDisplay1.CallStatus = callStatusMsg;});
Here is what I've done in a previous project:
I wrote a helper static class.
public static class WorkbenchService
{
private static SynchronizationContext uiContext;
static WorkbenchService()
{
uiContext = WindowsFormsSynchronizationContext.Current;
}
/// <summary>
/// Makes a call GUI threadSafe. WARNING: This method waits for the result of the operation, which can result in a dead-lock when the main thread waits for this thread to exit!
/// </summary>
public static void SafeThreadCall(SendOrPostCallback d, object state)
{
uiContext.Send(d, state);
}
/// <summary>
/// Makes a call GUI thread safe without waiting for the returned value.
/// </summary>
public static void SafeThreadAsyncCall(SendOrPostCallback d, object state)
{
uiContext.Post(d, state);
}
}
And then I use it like:
WorkbenchService.SafeThreadAsyncCall(delegate {
this.statusDisplay1.CallStatus = "Blah";
this.btnCallAnswer.Text = "hello there";
}, null);
I found the best way to do this. And converted my code to this.
Hope this helps someone else.
// Delegate for marshalling the call on the correct thread.
private delegate void SetIdleStateDelegate(string callStatusMsg);
// Set object back to idle state.
public void SetIdleState(string callStatusMsg)
{
if (this.InvokeRequired)
{
this.Invoke(new SetIdleStateDelegate(SetIdleState), callStatusMsg);
}
else
{
this.btnCallAnswer.Text = CATWinSIP_MsgStrings.Call;
this.btnEndCallReject.Text = CATWinSIP_MsgStrings.EndCall;
this.btnHoldUnhold.Text = CATWinSIP_MsgStrings.Hold;
this.btnCallAnswer.Enabled = true;
this.btnRedial.Enabled = true;
this.btnEndCallReject.Enabled = false;
this.btnHoldUnhold.Enabled = false;
}
}