已答覆 PostMessage vs. Dispatcher

  • Thursday, April 25, 2013 12:44 PM
     
     

    Hello all,

    in the Win32 API world I sometimes had to decouple a task by using PostMessage in the same thread.

    In WPF I now faced the problem that I have bound a ComboBox's selected item to a property of my view model. In the setter of the property I want to react to the change of the selected item by filling a list.

    The problem is that the ComboBox is not correctly rendered until the list is filled (only about 1-2 seconds but still looks bad). In Win32 I would have used PostMessage to decouple the task, then the ComboBox would be updated first and then the list would be filled.

    I accomplished a similar behavior with DispatcherTimer but my question is more general: is there an equivalent to PostMessage for decoupling in the same thread?

    Many thanks,
    Nicolas

All Replies

  • Monday, April 29, 2013 7:03 AM
     
     Answered
    • Marked As Answer by nicolasr75 Tuesday, April 30, 2013 12:24 AM
    •  
  • Monday, April 29, 2013 11:26 AM
     
     Answered

    I'm not clear exactly what you're doing.

    You might be able to do this using binding without any decoupling if all you're doing is selecting which stuff to show in the list.

    Async and await, and tasks offer functionality which might be relevent.

    I'm guessing you want to start a separate non blocking process off in the setter of your viewmodel or whatever you have bound to the combo.

    In which case a task can be run on a separate thread and somehow select/fill what the listbox is bound to. 

    Tasks can be run in the same thread if you prefer.  Although I'm particularly unclear why that would be a good idea.

    • Marked As Answer by nicolasr75 Tuesday, April 30, 2013 12:24 AM
    •  
  • Monday, April 29, 2013 3:56 PM
     
     Answered

    Yes Andy,

    I believe that is what he wants:

    1. Start a Aysnc Task that gets the stuff, determine how to notify, either indivually for each item or entire collection
    2. The view or viewmodel that contains the combobox must listen for incoming events and then marshall the data onto the GUI thread using the dispatcher object.

    Doing it this way there is NEVER a wait as it's all asynch with event based notification.

    If you really want to get tricky try out Reactive Extensions!


    JP Cowboy Coders Unite!

    • Marked As Answer by nicolasr75 Tuesday, April 30, 2013 12:25 AM
    •  
  • Monday, April 29, 2013 5:14 PM
     
     

    Thanks to all for your replies!

    While your suggestions are all interesting to read, my problem here seems to be rather special and I should have explained more clearly what I'm doing in the first place:

    My program has a built-in table editor for direct editing of tables (if the user prefers to do so).

    I have a ComboBox that shows a list of table names and SelectedItem is bound to the property SelectedTable in my view model. Below the ComboBox I have a DataGrid which is bound to a CollectionViewSource that represents the selected table.

    When the user selects a table in the ComboBox the property setter fills a DataTable and gets the default view from it which is then displayed in the DataGrid.

    Loading of the largest table takes about 2-3 seconds. Not sure whether you consider this long enough to justify a worker thread? And if so, would it actually help? I guess most of the time is needed to populate the DataGrid and this would have to be done in the GUI thread via Invoke or similar anyway. Please correct me if I'm wrong here!

    All would be fine if, when the user selects a table from the ComboBox, the drop down list would close, the selection would correctly be displayed/repainted and then I could show a wait cursor and load the data for 2-3 seconds. But at the moment the ComboBox hangs until the data are loaded.

    Seems like a tiny detail but it looks ugly to the user. Anyway, I think I can learn a lot from your input!

    Any ideas?

    Thanks again,
    Nicolas

  • Monday, April 29, 2013 7:13 PM
     
     

    Everything hangs because you're doing everything on the main thread and it's blocking.

    So your problems would go away if you cranked up a separate thread to go get the data.

    To be replaced by a different problem as there's no visible indication to the user that something is happening.

    I would have a small throbber somewhere. Perhaps in the centre and on top of your list.

    As you start your thread/task/worker process off you can show your throbber  then hide it when you have the data. And async await could make this fairly painless if you're using the latest version of wpf.

    • Edited by Andy ONeill Monday, April 29, 2013 7:17 PM
    •  
  • Tuesday, April 30, 2013 12:25 AM
     
     Answered

    Thanks Andy for your help again.

    I am now using a Task and it works as desired. It looks like fetching the DataTable in the Task takes about 2.5 sec and dispatching the DataTable to the GUI DataGrid takes only about 0.5 sec. So I assume using a Task is the best idea.
    One problem is that I have to pass the GUI thread Dispatcher instance to the view models but that is another problem and I found many other posts dealing with this...

    Although my original intent was a different one I will mark all replies as Answer as they all solve the original problem.

    thanks again,
    Nick

  • Tuesday, April 30, 2013 5:34 PM
     
     

    Ok Congratulations Nick you are on your way to true asynchronous programming! Just remember 1 thing, if you see an error when binding data to gui thread you have to dispatch it using the dispatch.Invoke pattern.  This can be done anywhere in the application using the Application.Current.Dispatcher if you have to...


    JP Cowboy Coders Unite!

  • Wednesday, May 01, 2013 8:24 PM
     
     

    Thanks for the pointer, using Application.Current.Dispatcher is really easier than passing the Dispatcher to all view model constructors (probably nested).

    Nick