C# update UI from different class/thread [duplicate] - c#

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 5 years ago.
Good morning guys, I'm trying to write some application in C#, where I like to update the UI (A progress bar in this case) from another thread and class.
But I just can't get it to work, I googled and search around but I'm afraid I just don't get it. I have a windows form application, I start a thread when I click a button, and somewhere in this thread I would like to update my UI.
I either get:
An object reference is required for the non-static field, method, or property
or something in the direction of the object being created by a different thread.
(At the location where I try to call Form1.UpdateProgressBar(value); in fileReader).
I have no experience in object orienting programming, I usually stick with C. If anyone could tell me the right way to do this, I would be very happy.
Edit_1: Alright.. Combinations of errors, the answer so far might have helped if I didn't have he static issue. And fixing the static issue by making the entire class static creates another X amount of errors on its own, including:
Static classes cannot have instance constructors
namespace TestCode
{
public partial class Form1 : Form
{
static fileReader SourceReader;
public Thread SearchThread { get; set; }
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
folderBrowserDialog1.ShowDialog();
Console.WriteLine(folderBrowserDialog1.SelectedPath);
this.SearchThread = new Thread(new ThreadStart(this.ThreadProcSafe));
this.SearchThread.Start();
}
public void UpdateProgressBar( int value)
{
progressBar1.Value =value;
}
private void ThreadProcSafe()
{
SourceReader = new fileReader(folderBrowserDialog1.SelectedPath);
}
}
}
Class 2:
namespace TestCode
{
class fileReader
{
public fileReader(String path)
{
int value = 20;
/*Do some stuff*/
Form1.UpdateProgressBar(value);
}
}
}

Check if an invoke is required and inf needed then use the controls Invoke function:
public void UpdateProgressBar( int value)
{
if(progressBar1.InvokeRequired){
progressBar1.Invoke(new MethodInvoker(() => progressBar1.Value=value));
}else{
progressBar1.Value =value;
}
}

You can use a MethodInvoker when trying to modify the UI from another class like this:
ProgressBar progressBar = Form1.progressBar1;
MethodInvoker action = () => progressBar.Value = 80;
progressBar.BeginInvoke(action);
while you can use this when working in a different Thread ( a Task for example ):
progressBar1.Invoke((Action)(() => progressBar1.Value=50))
But consider the comments on your post. It's not needed to be dependent on Forms in fileReader
Side note: I don't know how you didn't find your problem on here:
how to update a windows form GUI from another class?
How to update the GUI from another thread in C#?

Related

BackgroundWorker: Childs of Argument-Object

I am working on a WPF Application that was running smooth until I added threadding. I wanted to ease the saving/autosaving process by putting it into a BackgroundWorker so my UI is not blocked while saving occours.
Think of my App as a custom photobook maker.
Lets assume my UI consists of several Image Objects. The Source for those images lies within a custom PhotobookImageObject because each selected Image also contains additional Metadata.
PhotobookImageObject
public class PhotobookImageObject
{
public BitmapSource source { get; set; }
public String unimportantMetadata{ get; set; }
}
When I want to save, I want to save the complete Photobook. For simplicity:
Photobook
public class Photobook: INotifyPropertyChanged
{
public List<PhotobookImageObject> Photos{ get; set;}
public String otherMetaData { get; set;}
}
My Saving process worked when not using Threads. But ever since Im running it in a BackgroundWorker I can not access the PhotobookImageObjects in the list anymore.
Now I know the Thread for Saving can not Acces Objects from different Threads. This is why I am using a custom Class to Push the object into the thread of the BackgroundWorker. I found this solution here: How do you pass a List<> of Lists<> to a background worker?
Here is the acutal code:
Setting up the Worker:
private static BackgroundWorker saveWorker = new BackgroundWorker();
private static void saveWorkerExec(Photobook book, String Location, bool notAuto)
{
saveWorker.DoWork += doWork;
saveWorker.WorkerSupportsCancellation = true;
saveWorker.RunWorkerCompleted += (s, o) =>
{
Helper.Message("Photobook saved");
if (o.Error != null)
{
MessageBox.Show("There was an error while saving! \n\n" + o.Error.ToString());
}
};
BGObj obj = new BGObj
{
bk = book,
Loc = Location,
not = notAuto
};
saveWorker.RunWorkerAsync(obj);
}
The custom class I use to transfer the Data:
public class BGObj
{
public Photobook bk { get; set; }
public String Loc { get; set; }
public bool not { get; set; }
}
And the actual part where the BackgroundWorker should receive the class into his own Thread:
private static void doWork(object sender, DoWorkEventArgs e)
{
BGObj received = e.Argument as BGObj;
Photobook book= received.bk;
String Location = received.Loc;
bool notAuto = received.not;
//this function can not Access the books.Photos.last().source for example.
SaveProjectToContainer(book, Location, notAuto);
}
I am still receiving a System.InvalidOperationException when I try to access the BitmapSource of the PhotobookImageObject in the Photos List in Photobook.
My assumption: the BGobj I am creating is only referencing the actual Photobook so the data of its members is still resting in the wrong thread. How on earth can I make sure all submembers of my objects are actually passed to the Thread where I want to process them? Or am I wrong here and its something else?
Thank you for your time.
Since nobody could help me with the issue I followed Theodors approach and switched to a more modern approach using Async/Await.
From my understanding this is not making the actions run in the background but still freeing the UI thread and running the await" tasks "inbetween" when the thread has capacity free. This allows me to access the UI-elements and still stop the application from freezin a bit while autosaving.
If someone needs a few hints how to solve this think of it like this:
public static void NotMain()
{
// queue following function. void Main for example would continue running after this.
await do_stuff_in_between(var object);
// Stuff after await will only happen if the function is done but UI is not blocked
Console.WriteLine("saving done");
}
public static async Task do_stuff_in_between(var object)
{
// do stuff with object or whatever you want.
}

Accessing form controls from multiple forms

I have 2 forms and 1 file to upload to youtube. I am accessing them like so from both forms (both of the forms don't interact together)
await new UploadVideo().Run(video);
Now inside my uploadvideo class I am trying to get the percentage uploaded to use in my form
void videosInsertRequest_ResponseReceived(Video video)
{
//core.prog_up.Text = "Video id '{0}' was successfully uploaded." + video.Id;
}
In both of the forms, I have the exact same form controls, so the naming convention is exactly the same. So depending on which form I initiated the uploadvideo class I want the form component to be accessed from the uploadclass.
I have named my forms: Form1 and Form2
I can iniate one by doing :
Form1 frm = new Form1();
But then I can't access Form2 if I initiate it from that form
depedning on which form I initiate tge uploadvideo class I want the form component to be accessed from the uploadclass
No, not really. You only think you do.
Your UploadVideo class should not know anything about the Form classes. It has no need to, and it's exactly your effort to do otherwise that has led you into this trap. Instead, what you want to do is "decouple" your UploadVideo class from the other classes that use it. This avoids these kinds of difficulties and at the same time helps your UploadVideo class remain maximally reusable (you can even use it where there's no Form class involved).
One right way to do this is to implement an event, which each Form class can subscribe to as appropriate:
class UploadVideo
{
public event EventHandler<string> StatusTextChanged;
void videosInsertRequest_ResponseReceived(Video video)
{
StatusTextChanged?.Invoke(this, $"Video id '{video.Id}' was successfully uploaded.");
}
}
NOTE: your original text didn't really make sense. It used a format replacement specifier {0}, but didn't pass that to string.Format(), instead just appending the Id property value to the end of the string. I've changed the text expression to work as one would normally expect it to need to.
If you're not using the latest C# and don't have the "interpolated strings" feature, you can use string.Format("Video id '{0}' was successfully uploaded.", video.Id) instead.
Then a Form class can subscribe:
partial class Form1 : Form
{
async void button1_Click(object sender, EventArgs e)
{
UploadVideo uv = new UploadVideo();
uv.StatusTextChanged += (sender, text) =>
{
Invoke((MethodInvoker)(() => label1.Text = text));
}
await uv.Run(video);
}
}
(You didn't offer enough code to know exactly what the expression core.prog_up is really supposed to be, so in the above I've just assumed an arbitrary label1 object that's used to display the text.)
Another alternative is to use the Progress<T> class:
class UploadVideo
{
private readonly IProgress<string> _progress;
public UploadVideo(IProgress<string> progress)
{
_progress = progress;
}
void videosInsertRequest_ResponseReceived(Video video)
{
_progress.Report($"Video id '{video.Id}' was successfully uploaded.");
}
}
and…
partial class Form1 : Form
{
async void button1_Click(object sender, EventArgs e)
{
Progress<string> progress = new Progress(s => label1.Text = text);
await new UploadVideo(progress).Run(video);
}
}
Note that when using the Progress<T> class, there's no need to add the call to Control.Invoke() to get back on the UI thread, because it handles that automatically for you.
The above shows passing the IProgress<T> instance to the UploadVideo constructor, but you could of course pass it to the Run() method instead. Either way will work. It just depends on where you need to value.
Yet another approach avoids callbacks altogether. Again, your original code example is pretty vague, so it's not clear whether this would apply in your case. But assuming the callback would be handled just before the Run() method returns, and assuming the video object passed to the ResponseReceived event handler is the same one your code passes to the Run() method, then you could just use the completion of the call to the Run() method as the indication to update the UI:
partial class Form1 : Form
{
async void button1_Click(object sender, EventArgs e)
{
await new UploadVideo().Run(video);
label1.Text = $"Video id '{video.Id}' was successfully uploaded.";
}
}
This is a particularly compelling approach, because it removes even the string literal from the UploadVideo class, putting it into the class that actually is directly involved in interacting with the user (i.e. the only place where a string value really matters).
If the above is not enough for you to get back headed in the right direction, you'll need to improve your question by editing it so that it includes a good Minimal, Complete, and Verifiable code example showing exactly how your scenario works.
You can use parameters to pass the reference of form.
private Form _frm;
public Form1(Form form)
{
_frm = form;
InitializeComponent();
}
And then you can simply call the form like this:
Form1 frm = new Form1(this)

unity updating variable from different thread [duplicate]

This question already has answers here:
Use Unity API from another Thread or call a function in the main Thread
(5 answers)
Closed 6 years ago.
I am starting to learn some unity and I have a quick question in regards to multithreading.
I have a class which contains an instance of a datamodel class. The primary function of the class is the fetch a remote resource asynchronously and update the datamodel class. Then in the update function the datamodel class is read out and written to some text in a gameobject.
Anyway I am worrying that it could cause some issues related to multithreading since my async updating of the class could run at the same time as the update function causing a race condition. Do I have to wrap access to the class in a mutex?
class Data {
public int Number { get; set; }
public string Name { get; set; }
}
class Network : MonoBehaviour {
private Data d;
public void Start() {
// setting up handler to async fetch data and call provided callback
Networking.GetData(s => ParsePayload(s));
}
private void ParsePayload(string payload) {
d = JsonConvert.DeserializeObject<Data>(payload);
}
public void Update() {
var label = GameObject.Find("textObject").GetComponent<Text>();
label.Text = d.Name;
}
}
So am I right in this or does unity handle this by itself?
thx for any advice!
So am I right in this or does unity handle this by itself?
You are right in this. It could cause some problems and Unity does not handle this by itself. You are responsible to making sure that only one Thread can access d variable at a time. There are several ways of this but using the lock keyword can accompilsh this.
Since d is updated in the ParsePayload function and accessed in the Update function, you have to use the lock keyword in both functions.
Another unrelated problem is the GameObject.Find("textObject"). This should be done in the Start() function and saved to a variable. Don't do that in the Update function each frame.
class Network : MonoBehaviour
{
private Data d;
Text label;
private System.Object threadLocker = new System.Object();
public void Start()
{
label = GameObject.Find("textObject").GetComponent<Text>();
// setting up handler to async fetch data and call provided callback
Networking.GetData(s => ParsePayload(s));
}
private void ParsePayload(string payload)
{
lock (threadLocker)
{
d = JsonConvert.DeserializeObject<Data>(payload);
}
}
public void Update()
{
lock (threadLocker)
{
label.text = d.Name;
}
}
}

making a cross-thread call to hide a form visual c#

Update: Solution arrived since and is now accepted. Due to the clarity of the pseudo codes on this question the solution took only a few seconds. Trying to figure out the solution from the other seemingly "duplicate" questions took a lot of time already. I had the solution in 20 minutes from the moment I asked this question. So it is not a duplicate, probably the clearest of them all to date.
While several similar questions have been asked on this, I was still not able to put together a working code from them. My main application is not on a form, but in a separate class that is a plugin and executed by a host application.
So while it seems a duplicate question it is not. Please read on.
I have my main class doing stuff. Then I have a form that displays information to the user. I need to hide this form when the user switches away from the application (host application loses focus).
I am using very limited APIs so the only methods I have at my disposal events triggered by the host application.
I created a timer that fires every 100ms and checks whether the user had the application in focus. And if not a command is sent to the form to hide itself.
The reason for this approach is because the host application loosing focus is just one of the many scenarios that I need to hide the form and I need to channel all these through the same exact method.
All works from within the rest of the classes (the Hide() method is called from the rest of the application no problem.
But it does not work when the timer calls the Hide() method, because the timer is on a different thread when it fires. So the call becomes a cross-thread call.
The very specific question is that I need an exact sample code how to make this call from the timer event handler to the form's Hide() method thread-safe with Invoke.
Thanks.
This is the timer:
private void Controllel_Opened(object sender, EventArgs e)
{
myTimer.Elapsed += new System.Timers.ElapsedEventHandler(DisplayTimeEvent);
myTimer.Interval = 50;
myTimer.Start();
}
public static System.Timers.Timer myTimer = new System.Timers.Timer();
// This method checks different scenarios when the tool tip should be hidden and calls the hiding method
public static void DisplayTimeEvent(object source, System.Timers.ElapsedEventArgs e)
{
FormHandler.Hide();
}
Then the "FormHandler" class:
public static class FormHandler
{
private static Form1 frm1 = new Form1();
public delegate void Form1HideEventHandler();
public static event Form1HideEventHandler Form1Hide;
public static void Hide()
{
if (Form1Hide != null)
{
Form1Hide();
}
}
}
Then the form's code:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
FormHandler.Form1Hide += FormHandler_Form1Hide;
}
private void FormHandler_Form1Hide()
{
Hide();
}
}
I would like to get a solution with exact code if possible. Thanks.
private void FormHandler_Form1Hide()
{
if (InvokeRequired)
{
this.Invoke(new Action(() => { FormHandler_Form1Hide(); }));
}
else
{
Hide();
}
}
You need to use System.Windows.Forms.Timer instead. That will invoke back onto the dispatcher thread.

Best way to communicate between forms?

I almost never used (advanced, or at all) graphical interfaces, or one simple form with simple controls... but this time I've got something a little more complex, and I don't have much experience with GUI.
I have one main form (and possibly more in the future) from which other sub-forms open (and they might have sub-forms of themselves) and I wonder what is, in your opinion, the best way to communicate between them?
I thought of passing the main form as a parameter to the constructors of the sub-forms, but it doesn't seem like a good way, especially if I'm going to need to communicate between other, distinct, sub-forms, not to mention I have to double check the input, or make a few methods, but it seems more like functional programming than object oriented programming...
Perhaps I can:
Create a static class (or Properties.Settings) for global settings. Cons: every change of data is needed to be copied to the class, I'm looking for something a bit more comfortable and elegant.
Use the ugly way of accessing the controls from Application.OpenForms - fixes the problem of passing the main form as parameter. Cons: not very stable.
Do something else I haven't thought of. Suggestions? Cons: don't know what it is yet.
Your constructor idea is probably the most sound method of communication back to the main form. Your sub form would do something like the following:
public class SubForm : Form
{
public SubForm(MainForm parentForm)
{
_parentForm = parentForm;
}
private MainForm _parentForm;
private void btn_UpdateClientName_Click(object sender, EventArgs e)
{
_parentForm.UpdateClientName(txt_ClientName.Text);
}
}
And then you expose public methods on your MainForm:
public class MainForm : Form
{
public void UpdateClientName(string clientName)
{
txt_MainClientName.Text = clientName;
}
}
Alternatively, you can go the other way around and subscribe to events from your SubForms:
public class MainForm : Form
{
private SubForm1 _subForm1;
private SubForm2 _subForm2;
public MainForm()
{
_subForm1 = new SubForm1();
_subForm2 = new SubForm2();
_subForm1.ClientUpdated += new EventHandler(_subForm1_ClientUpdated);
_subForm2.ClientUpdated += new EventHandler(_subForm2_ProductUpdated);
}
private void _subForm1_ClientUpdated(object sender, EventArgs e)
{
txt_ClientName.Text = _subForm1.ClientName; // Expose a public property
}
private void _subForm2_ProductUpdated(object sender, EventArgs e)
{
txt_ProductName.Text = _subForm2.ProductName; // Expose a public property
}
}
A good way is to declare delegates in the form that want to start the communication. You need a delegate and a callback function:
public delegate void SetValueDelegate(string value);
public SetValueDelegate SetValueCallback;
Another form can then attach to this delegate. At that moment both forms have to know each other, but not after that moment:
firstForm.SetValueCallback += new SetValueDelegate(secondForm.SetValueFunction);
The second form has to declare a function that matches the delegate definition:
public void SetValueFunction(string value)
{
// do something
}
Now the first form can use the delegate to use the function of the second form (and all other forms or classes that were attached to the delegate:
SetValueCallback(txtParam.Text);
Edit: made an complete example
using System;
namespace DelegateTest
{
public delegate void SetValueDelegate(string value);
public class Class1
{
public SetValueDelegate SetValueCallBack;
public void Test()
{
if(SetValueCallBack != null)
{
SetValueCallBack("Hello World!");
}
}
}
public class Class2
{
public void SetValueFunction(string value)
{
Console.WriteLine(value);
}
}
public class Launcher
{
public static void Main(string[] args)
{
Class1 c1 = new Class1();
Class2 c2 = new Class2();
c1.SetValueCallBack += new SetValueDelegate(c2.SetValueFunction);
c1.Test();
}
}
}
The most flexible, scalable (and IMHO the most professional) way to do it is to use CAB (Composite Application Block). In simple terms CAB is a set of 2-3 assemblies that implement a lot of plumbing required to make complex UI applications the right way and it exposes this plumbing to the user of the library in a nice way. Among others it has a very nice event and command (as in command pattern) system.
The downside: requires some time to learn and not very trivial to grasp.
Here is a comprehensive (but easy to understand) tutorial that will help you make the learning easier.
You can use the built in Tag property of the form which is an "object" class.
public Form1()
{
(ComplicatedDataStructure)Tag = new ComplicatedDataStracture();
}
.
.
form1 = new Form1();
.
.
form2 = new Form2();
.
.
form2.Tag = form1.Tag;
so form2.Tag is equals to "ComplicatedDataStracture" object;

Categories