0

I'm working on a WinForm app (using .NET 4.0) which has several tabs filled with data regarding Shipments. Currently, when a user clicks on a tab a specific method is called, in which each control of the selected tab is populated with the relevant data.

We are working with an outside consultant who mentioned that our application could benefit from the TPL, so I started to research the TPL. I'm still very much in the process of researching as well as trying out small samples and tutorials I find online, but I believe I'm ready to implement the TPL in our existing code.

So what I would like to do in my first attempt is to go ahead and call each of the selected tab load methods on the initial load of a Shipment, rather than waiting for the user to click on the tab.

In the calling method, I have the following code (I didn't include every TaskFactory call as it would be a waste of space in this example.)

  Tasks.Task.Factory.StartNew(Function() LoadSummaryTab())
  Tasks.Task.Factory.StartNew(Function() LoadRouteTab())

I tried running the code, but ran into cross-thread issues. After researching that issue, I found that it is due to ui controls being updated in each of the two methods I've called.

So I found some samples online that suggest I use SyncronizationContext, but I'm beginning to wonder if what I'm trying to do is even worth it.

Using what I researched online, I created a simple WinForm application to test out the code I found. Is this anywhere near the correct solution for what I'm trying to do? This succesfully resolves my cross-thread issue, but obviously this is not like my real-world situation.

  private void Form1_Load(object sender, EventArgs e)
    {
        var ui = TaskScheduler.FromCurrentSynchronizationContext();
        var tf = Task.Factory;

        var task = tf.StartNew(() =>
       {
           for (int i = 0; i < 100; i++)
           {
               Thread.Sleep(10);

           };
       });
        task.ContinueWith(x =>
        {
            label1.Text = "I am label 1.";
            label2.Text = "I am label 2.";
            label3.Text = "I am label 3.";
            label4.Text = "I am label 4.";
        }, ui);
    }

I found an answer here - Use Begin Invoke, but it seems that I will have a bit of repetitive code since I have so many controls to update. Is BeginInvoke the best idea for what I'm trying to do?

I'm just looking to get feedback from other experienced developers who have been down this road and can advise me. I do need to stay on the path which the consultant has advised us to go on, so TPL needs to be the primary focus.

So I'll end with this question. Considering the limited information I've provided, does it makes sense for me to try and execute all the loadselectedtab methods using TPL, especially considering that several UI controls are updated in each method? If so, would anyone be able to advise me in pursuing this path?

Community
  • 1
  • 1
  • `especially considering that several UI controls are updated in each method?` - That's the problem with winforms, that it forces you to crappy practices like this, where you mash alltogether UI, data and business logic. That's why WPF was created to replace it. Unfortunately you're stuck with that. Try to `Get` the data in a background thread (as opposed to "putting" it into the UI) and then "put" the data into the UI in the UI thread. – Federico Berasategui Oct 08 '13 at 18:12
  • **Professional**-level Windows application development is based on [DataBinding](http://msdn.microsoft.com/en-us/library/ms752347.aspx), as opposed to `label1.Text = "Text1"; Label2.Text="Text2";`. Again, winforms' databinding capabilities are a joke, that's why professional level software must be created using professional level frameworks such as WPF, while leaving winforms to elementary school kids who are learning how to drag and drop in a designer – Federico Berasategui Oct 08 '13 at 18:16
  • @HighCore Whoa, WinForms doesn't force you to mix UI/Data logic. I do use WPF (and WinForms), WPF is setup to promote separation of data and ui. To the asker, you are aware that the UI (in both WinForms and WPF) can only be updated by the UI thread? What you need to do is load/get your data on multiple threads, and when that process is done, then you can update the user interface with either Invoke or BeginInvoke. The only difference is BeginInvoke doesn't block, while Invoke does. – Alan Oct 08 '13 at 18:16
  • @Alan that's precisely what I said. However winforms doesn't have `true` databinding therefore you are always forced to use crappy code behind stuff. – Federico Berasategui Oct 08 '13 at 18:17
  • Yeah, I didn't explain the background behind this project. Way before I was hired on (just 2 months ago), my company purchased some custom software from a 3rd party. It was full of bugs and had so many issues. Back in December 2012/January 2013, my company was able to obtain the source code and we are now fully in charge of bringing this application into the more modern age. I am by no means a great programmer, but I'm trying to research and teach myself and learn from others (which is why I'm finally posting here after so much lurking.) – Jeremy Hardin Oct 08 '13 at 19:14
  • So, the original code used datasets for everything. Eventually Entity Framework was added in so we could do true object relational mapping. Very recently we've actually switched overt Subsonic and we have seen a significant speed increase (yeah!) So that's some background to the application. I was thinking if anything, using BeginInvoke as I found in that other answer. – Jeremy Hardin Oct 08 '13 at 19:18
  • @Alan - yes, I am now aware that the UI can only be updated by the UI thread. I didn't know that before I started trying out this code. You mention getting my data on multiple threads and using BeginInvoke. I like that idea, but I don't think that will work since I'm using Subsonic and I'm loading my Shipment object and all its related objects in one go. If we were still using datasets, I would do that. – Jeremy Hardin Oct 08 '13 at 19:22
  • HighCore - we have discussed switching to WPF in the future and are seriously considering it. But for now, we're just thinking of ways in which we can enhance the user experience using what we've got. There were no patterns put into place in the design or coding of the app, so in a sense, myself and my supervisor will be the ones driving which direction this application goes. I will be looking into WPF more now though. I appreciate your answers as well as yours @Alan. – Jeremy Hardin Oct 08 '13 at 19:26
  • @jeremyHardin regardless of where your data comes from, and how it is structured, you can still "get it" in a background thread (by calling a service or data access layer using a Task) and then use the return value (such as an Entity model) to populate your UI in the UI thread. – Federico Berasategui Oct 08 '13 at 19:27
  • @HighCore I hadn't thought of that. Thank you. Honestly, the more I think of this "issue", I wonder if parallel programming will benefit us enough to warrant pursuing that course of action. Regardless, I'm still interested in TPL and this discussion. – Jeremy Hardin Oct 08 '13 at 19:58
  • @HighCore I have a few more questions regarding your last comment. What benefit would there be for me to "get" my Shipment object on a background thread? As I read your comment, I thought that perhaps I could get the object on the background thread, and populate the UI on the main thread, is that what you meant? If so, by using a Task wouldn't the get and the populate both be running in parallel? – Jeremy Hardin Oct 09 '13 at 11:51
  • @HighCore ...If that is correct, isn't there a chance that the main thread might try to alter the text property of a textbox before that particular property of the Shipment object is loaded on the background thread? I wonder if I'm misunderstanding how the Task works. I'd appreciate your feedback (as well as anyone else's.) Thanks in advance. – Jeremy Hardin Oct 09 '13 at 11:52

0 Answers0