0

I ran into a problem that I can't seem to figure out on my own. My program is an overlay for another application. It runs multiple windows forms in different threads. They all do everything on their own, but from time to time I need to update data in those forms (labels to be specific). The data for each form is unique, so I can't update all at the same time.

My best leads so far are this question, this and this. However, none of them deal with the problem of keeping track of the multiple instances of a window class. And that's where I need help.

The code looks like this right now:

    > public class main {
    >
    > //This is the class, that organizes all the forms
    > //and creates or updates them if needed. The forms are being created like this: 
    >
    > new Thread(() => new Overlay(neededDataByOverlay).ShowDialog()).Start();
    >
    > }
    >
    > public class Overlay {
    >
    > //This is the overlay which I need to update from time to time. 
    > //Ideally I would like to call a method update(dataThatNeedsToBeUpdated) so it can update itself. 
    > //There will be multiple instances of this class at the same time.
    > 
    > }

My question is, how can I keep track of the different forms in the different threads and then call that method in them? Is it possible to create a list with threads inside or can I somehow put the running forms into a list? I need to identify each window by a name or something to get the right data to the right window. I am really stuck with this one and would appreciate any help.

Edit: Apparently it is not clear what my intention is with this program and why the forms need to be in separate threads. Those forms are overlays for stock trading programs. They display additional information dependent on the used program or the currently opened windows. For instance, one window of the stock trading program shows currency-exchange rates, so the overlay shows additional information related to the currency, that the stock trading program doesn't out of the box. Then another window is showing stock prices in realtime and the overlay displays additional information on top.

The overlays (forms) are constantly resizing and adjusting themselves dependent on the position of the underlying windows (and are actually doing some calculations), that is why they need to be in their own thread. Otherwise the resizing timers and calculation methods of the forms would block the main thread. The main class of my application fetches data from a specific server, whenever there is a new dataset available. So, for example: As soon as a new dataset for currency-exchange-rates is available, it gets processed and the specific overlay needs to be updated.

Now, what is the best way to keep track of all the forms(e.g. form1.purpose = currency, form2.purpose=stocks) and update them in their threads with the new datasets that my main thread is fetching in set intervals?

I am very sorry, if this doesn't answer your questions, I tried my very best to explain this particular problem.

Community
  • 1
  • 1
  • 4
    I'm a bit confused as to what you want to do really. You create threads that only modally show a dialog. Why? And sure you can put form objects in a list but why? The threads already know their form and if they are independent what is the issue? Usually it's also a bad thing to do anything with UI from any other thread than the UI thread so I think there may be a problem with the design. – Sami Kuhmonen Mar 25 '17 at 07:54
  • have you tried passing in your forms to the threads as arguments from the main thread? still dont get where your problem is atm... are you trying to update the ui of forms in other threads from the main thread? – Niklas Mar 25 '17 at 08:06
  • @SamiKuhmonen See my edit for a more thorough explanation. I hope I managed to outline my problem a bit better. And thanks for you help! –  Mar 25 '17 at 10:11
  • @Niklas I didn't try that yet. How would I go about doing it? Yes, that is exactly what I am trying to do! –  Mar 25 '17 at 10:13
  • BackgroundWorker and timers might be a better solution than running several threads manually, especially poking around the UI. – Sami Kuhmonen Mar 25 '17 at 10:24

1 Answers1

0

you could create an object and pass it as an argument to the thread.
when doing that the object is passed by Reference meaning that any change made is reflected on the source object.

right or wrong, to do what you want to do, you can pass a reference of the object to the created thread and ShowDialog your form from the thread there.
here is an example:

Form1 myForm = new Form1();
Thread t = new Thread((formObj) =>
{
    (formObj as Form1).ShowDialog();
});
t.Start(myForm);


//Testing the "making-changes-to-the-form-part"
DataGridView dgv = new DataGridView();
dgv.Dock = DockStyle.Fill;
if (myForm.InvokeRequired)
    myForm.BeginInvoke(new Action(() => { myForm.Controls.Add(dgv); }));
else
    myForm.Controls.Add(dgv);

However, A few things to take into consideration here:
the object of the form is created on your main thread, however the window handle is created in the subthread, that is why the owner of the forms window will be the subthread.

note the use of if(myForm.InvokeRequired), which is true in this case.. which then causes the application to BeginInvoke the control and call its owner thread to make changes to its ui.

the goal of your application is not clear to me, and the nature of the work you're doing seems wrong with little i know.
but the question is how can you access the forms instance once the subthread used it... i think? and thats how you do it.

so in order to have access to multiple instances of a form you need the collection of those forms probably paired with an identifier using collections like Dictionary<TKey,TValue>, and the code above.

However
after seeing your eddited question,i begin to wonder why you don't use System.Windows.Forms.Timer instead of calling the Methods of main form.

here is an example:

private Timer _timer;
private void Form1_Load(object sender, EventArgs e)
{
    if (_timer == null)
    {
        _timer = new Timer
        {
            Interval = (int)TimeSpan.FromSeconds(10).TotalMilliseconds
        };
        _timer.Tick += (s, args) =>
        {
            //Method calls of the form itself here
        };
        _timer.Start();
    }
}

this way your form will initialize a timer when you show it, and that timer will call the method on a timer, which is less trouble for you and you don't have to do cross thread calls this way.

Also... since you talked about thread safe lists I suggest you read this book. It has alot to offer about multi threading and thread safety.

Niklas
  • 955
  • 15
  • 29
  • Thank you for your help so far! I edited my question, so it's easier to understand the purpose of the application. Your answer makes sense. The idea is to create the object in the main thread and then pass it on to the thread with .ShowDialog(), so we can still access its methods later on (Though a bit more complicated with invoking instead of just calling a method), right? I don't really understand the second part though. Why a DataGridView? The part with the multiple instances sounds good as well! I have to dig into that though, as I currently don't exactly understand what you mean. –  Mar 25 '17 at 10:21
  • @z1mdev the datagridview part is simply an example of making a ui change to the form that was showdialoged in a sub thread in order to prove the point of begininvoke, doesnt have to be a datagrid...could be any other kind of control or ui change :) as for it being more complicated than calling a method? Not if your method contains changes to the ui ! Then you will need to check it and begininvoke when needed in order to be able to change the text of a label for example.. you will encounter exceptions if you try to change the ui of a control otherwise! I hope i was clear enough :) – Niklas Mar 25 '17 at 10:26
  • Thank you very much! This was a great idea actually. I just implemented it and it works perfectly fine as far as I can tell. I am going to test it thoroughly now, so I don't have any bad code left. Next step is to implement a thread-safe list where the timers of the different forms can get their information from. Marked your post as the answer! –  Mar 26 '17 at 15:09
  • @z1mdev i added a link to the answer, I suggest you read that to learn about thread safe collections and mechanisms before you decide to make your own! – Niklas Mar 26 '17 at 21:24
  • Looks great! I used a concurrent dictionary for now, but I guess I'll be better off in the future making my own threadsafe stuff. Thank you so much, you really helped me a lot solving this problem and learning about thread-stuff! –  Mar 28 '17 at 12:09