{"id":102373,"date":"2019-03-29T07:00:00","date_gmt":"2019-03-29T14:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=102373"},"modified":"2019-06-06T17:39:09","modified_gmt":"2019-06-07T00:39:09","slug":"20190329-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20190329-00\/?p=102373","title":{"rendered":"C++\/WinRT envy: Bringing thread switching tasks to C# (WPF and WinForms edition)"},"content":{"rendered":"<p><!-- backref: C++\/WinRT envy: Bringing thread switching tasks to C# (UWP edition) -->Last time<\/a>, we brought <code>Thread&shy;Switcher.<\/code><code>Resume&shy;Foreground&shy;Async<\/code> and <code>Thread&shy;Switcher.<\/code><code>Resume&shy;Background&shy;Async<\/code> to C# for UWP. Today, we&#8217;ll do the same for WPF and Windows Forms. <\/p>\n<p>It&#8217;ll be easier the second and third times through because we already learned how to structure the implementation. It&#8217;s just the minor details that need to be tweaked. <\/p>\n<pre>\nusing System;\nusing System.Runtime.CompilerServices;\nusing System.Threading;          \/\/ For ThreadPool\nusing System.Windows.Forms;      \/\/ For Windows Forms\nusing System.Windows.Threading;  \/\/ For WPF\n\n\/\/ For WPF\nstruct DispatcherThreadSwitcher : INotifyCompletion\n{\n    internal DispatcherThreadSwitcher(Dispatcher dispatcher) =&gt;\n        this.dispatcher = dispatcher;\n    public DispatcherThreadSwitcher GetAwaiter() =&gt; this;\n    public bool IsCompleted =&gt; dispatcher.CheckAccess();\n    public void GetResult() { }\n    public void OnCompleted(Action continuation) =&gt;\n        dispatcher.BeginInvoke(continuation);\n    Dispatcher dispatcher;\n}\n\n\/\/ For Windows Forms\nstruct ControlThreadSwitcher : INotifyCompletion\n{\n    internal ControlThreadSwitcher(Control control) =&gt;\n        this.control = control;\n    public ControlThreadSwitcher GetAwaiter() =&gt; this;\n    public bool IsCompleted =&gt; !control.InvokeRequired;\n    public void GetResult() { }\n    public void OnCompleted(Action continuation) =&gt;\n        control.BeginInvoke(continuation);\n    Control control;\n}\n\n\/\/ For both WPF and Windows Forms\nstruct ThreadPoolThreadSwitcher : INotifyCompletion\n{\n    public ThreadPoolThreadSwitcher GetAwaiter() =&gt; this;\n    public bool IsCompleted =&gt;\n        SynchronizationContext.Current == null;\n    public void GetResult() { }\n    public void OnCompleted(Action continuation) =&gt;\n        ThreadPool.QueueUserWorkItem(_ =&gt; continuation());\n}\n\nclass ThreadSwitcher\n{\n    \/\/ For WPF\n    static public DispatcherThreadSwitcher ResumeForegroundAsync(\n        Dispatcher dispatcher) =&gt;\n        new DispatcherThreadSwitcher(dispatcher);\n\n    \/\/ For Windows Forms\n    static public ControlThreadSwitcher ResumeForegroundAsync(\n        Control control) =&gt;\n        new ControlThreadSwitcher(control);\n\n    \/\/ For both WPF and Windows Forms\n    static public ThreadPoolThreadSwitcher ResumeBackgroundAsync() =&gt;\n         new ThreadPoolThreadSwitcher();\n}\n<\/pre>\n<p>The principles for these helper classes are the same as for their UWP counterparts. They are merely adapting to a different control pattern. <\/p>\n<p>WPF uses the <code>System.&shy;Threading.&shy;Dispatcher<\/code> class to control access to the UI thread. The way to check if you are on the dispatcher&#8217;s thread is to call <code>Check&shy;Access()<\/code> and see if it grants you access. If so, then you are already on the dispatcher thread. Otherwise, you are on the wrong thread, and the way to get to the dispatcher thread is to use the <code>Begin&shy;Invoke<\/code> method. <\/p>\n<p>In Windows Forms, controls incorporate their own dispatcher. To determine if you&#8217;re on the control&#8217;s thread, you check the <code>Invoke&shy;Required<\/code> property. If it tells you that you need to invoke, then you call <code>Begin&shy;Invoke<\/code> to get to the correct thread. <\/p>\n<p>Both WPF and Windows Forms use the CLR thread pool. As before, we check the <code>Synchronization&shy;Context<\/code> to determine whether we are on a background thread already. If not, then we use <code>Queue&shy;User&shy;Work&shy;Item<\/code> to get onto the thread pool. <\/p>\n<p>So there we have it, C++\/WinRT-style thread switching for three major C# user interface frameworks. If you feel inspired, you can do the same for Silverlight, Xamarin, or any other C# UI framework I may have forgotten. <\/p>\n","protected":false},"excerpt":{"rendered":"<p>More magic tasks that break out of the thread configuration mold.<\/p>\n","protected":false},"author":1069,"featured_media":111744,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[25],"class_list":["post-102373","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>More magic tasks that break out of the thread configuration mold.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/102373","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/users\/1069"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/comments?post=102373"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/102373\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media\/111744"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media?parent=102373"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=102373"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=102373"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}