0

How can I use class System.Windows.Threading.Dispatcher from within a .Net 5.0 app?

According to the online documentation, it should be available.
https://learn.microsoft.com/en-us/dotnet/api/system.windows.threading.dispatcher?view=net-5.0.

Normally, in a .Net Framework app, I would just add a reference to assembly WindowsBase.dll. But since I'm using a .Net 5.0 project I can only reference Nuget Packages.
Cannot add assemblies to .Net Core application in Visual Studio 2019.

However, there does not seem to be a WindowsBase Nuget package.
https://www.nuget.org/packages?q=WindowsBase.

There is a package called Microsoft.Windows.Compatibility which according to its descriptions sounds like it should include the class; but it does not.
https://www.nuget.org/packages/Microsoft.Windows.Compatibility/6.0.0-preview.5.21301.5

Any suggestions?

Restrictions:

  • The project uses WinForms extensively. It's not viable to convert it to WPF.
  • The reason I use Dispatcher, it so that objects on different threads can call modifications to the UI. The UI does not exist when these objects are created, so passing controls to them is not an option (also, not very elegant IMO for business objects to know about buttons and stuff).
Cesar Coll
  • 105
  • 10
  • You can use [Progress](https://learn.microsoft.com/en-us/dotnet/api/system.progress-1) delegates. Or [SynchronizationContext.Post()](https://learn.microsoft.com/en-us/dotnet/api/system.threading.synchronizationcontext). Or use the async/await pattern, when available (or when you *make it* available). There are other synchronization methods. You don't need the WPF Dispatcher in WinForms. – Jimi Jun 17 '21 at 09:28
  • Sounds like a good idea. Thanks, Jimi. – Cesar Coll Jun 17 '21 at 09:56

1 Answers1

0

After looking carefully, I realized that as of today (17/Jun/2021) The Nuget Package Microsoft.Windows.Compatibility is still in pre-release. This means that by the time other people read this thread the class might be already included.

If not, I found a workaround:

  1. Create a WPF class library
  2. Add a DispatcherWrapper class
  3. Add a private Dispatcher attribute.
  4. Add all the (needed) Dispatcher methods to the DispatcherWrapper class
  5. Add a project reference from the WinForms app to the WPF library.
  6. Use the DispatcherWrapper class instead of Dispatcher.

However, after reading the comment from Jimi, I think that, when working on a Winforms application, it is more elegant to use SynchronizationContext instead of Dispatcher.

Cesar Coll
  • 105
  • 10
  • Prefer `Progress` Action delegates. The class already captures the UI Thread SynchronizationContext for you, it's really simple to use and works very well in most scenarios. – Jimi Jun 17 '21 at 10:24
  • Anyway, see different implementations here: [How to avoid cross-thread operation not valid exception in Winform service bus message receiver](https://stackoverflow.com/a/62449011/7444103). It includes a note about the WPF Dispatcher that you should read. – Jimi Jun 17 '21 at 10:31
  • I'll take a look at them as well. I just wanted to add an answer to the actual question "How to access Dispatcher from a .Net 5 Winforms app" in case someone else really needs to do just that. – Cesar Coll Jun 18 '21 at 05:46
  • It's like trying to use WinForm's `BeginInvoke()` in WPF. Does it make sense? Is WPF lacking some features that require methods from another platform framework (or the other way around)? Not really. – Jimi Jun 18 '21 at 14:24
  • Yes, I understand. But, AFAIK Dispatcher existed on WinForms too, (even before WPF was released?) . It wasn't exclusive to WPF. Now I'm porting a huge system to Net 5, and my first priority is that everything works, introducing as few changes as possible. Dispatcher is used extensively in my classes, so for now, I rather use a wrapper. And I can imagine that there are other people in my same situation. That said, I'm very grateful that you have showed me the correct way, and it should be on my backlog soon. – Cesar Coll Jun 18 '21 at 18:38