{"componentChunkName":"component---src-components-post-layout-post-layout-tsx","path":"/2017/04/04/await-your-event-handlers-completion-with-deferred-events/","result":{"data":{"mdx":{"id":"1e7bf0e5-a082-5d06-8fe9-1ae192bd0f65","body":"function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }\n\nfunction _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }\n\nfunction _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }\n\n/* @jsx mdx */\nvar _frontmatter = {\n  \"title\": \"Await your event handlers completion with Deferred Events\",\n  \"date\": \"2017-04-04T13:55:59.000Z\",\n  \"last_modified_at\": \"2019-11-13T19:06:45.000Z\",\n  \"layout\": \"post\",\n  \"categories\": [\"Windows\"],\n  \"tags\": [\"Async\", \"Events\", \"Deferred Events\", \".NET\", \".NET Standard\"]\n};\n\nvar makeShortcode = function makeShortcode(name) {\n  return function MDXDefaultShortcode(props) {\n    console.warn(\"Component \" + name + \" was not imported, exported, or provided by MDXProvider as global scope\");\n    return mdx(\"div\", props);\n  };\n};\n\nvar layoutProps = {\n  _frontmatter: _frontmatter\n};\nvar MDXLayout = \"wrapper\";\nreturn function MDXContent(_ref) {\n  var components = _ref.components,\n      props = _objectWithoutProperties(_ref, [\"components\"]);\n\n  return mdx(MDXLayout, _extends({}, layoutProps, props, {\n    components: components,\n    mdxType: \"MDXLayout\"\n  }), mdx(\"p\", null, \"Developers should avoid \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"async void\"), \" methods, but there are some situations where this is a \\u201Cnecessary evil\\u201D, and event handlers are one of those cases.\"), mdx(\"p\", null, \"If one needs to use the \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"await\"), \" keyword inside an event handler code, the method itself must be \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"async void\")), mdx(\"p\", null, \"The following is an example of this:\"), mdx(\"pre\", null, mdx(\"code\", _extends({\n    parentName: \"pre\"\n  }, {\n    \"className\": \"language-csharp\"\n  }), \"public sealed partial class MainPage : Page\\n{\\n    public MainPage()\\n    {\\n        InitializeComponent();\\n\\n        Loaded += MainPage_Loaded;\\n    }\\n\\n    private async void MainPage_Loaded(object sender, Windows.UI.Xaml.RoutedEventArgs e)\\n    {\\n        await DoSomethingAsync();\\n\\n        await DoSomethingMoreAsync();\\n    }\\n}\\n\")), mdx(\"p\", null, \"On the above example, the \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"MainPage_Loaded\"), \" is an \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"async void\"), \" method that will as it needs to await for the completion of some of its calls, but sometimes we also need to allow the event invoker to wait for all handlers to complete.\"), mdx(\"p\", null, \"Inspired on how the background tasks use a deferral approach to solving this problem (as they too are \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"void\"), \" methods), I came up with a similar approach!\"), mdx(\"h2\", null, \"Introducing the Deferred Events\"), mdx(\"p\", null, \"A \\u201Cdeferred event\\u201D is basically an event that allows the invoker to wait for the completion of all event handlers.\"), mdx(\"p\", null, \"My personal implementation is available on the \", mdx(\"a\", _extends({\n    parentName: \"p\"\n  }, {\n    \"href\": \"https://www.nuget.org/packages/DeferredEvents/\"\n  }), \"DeferredEvents NuGet package\"), \" that you can install by running \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"Install-Package DeferredEvents\"), \" on the \", mdx(\"a\", _extends({\n    parentName: \"p\"\n  }, {\n    \"href\": \"https://docs.nuget.org/docs/start-here/using-the-package-manager-console\"\n  }), \"Package Manager Console\"), \", or add with Visual Studio NuGet Packages Manager.\"), mdx(\"p\", null, \"This is a .NET Standard 1.0 package, so you should be able to use it on any .NET project!\"), mdx(\"p\", null, \"If you want to take a look at what\\u2019s inside, the full source code is available \", mdx(\"a\", _extends({\n    parentName: \"p\"\n  }, {\n    \"href\": \"https://github.com/PedroLamas/DeferredEvents\"\n  }), \"here\"), \".\"), mdx(\"h2\", null, \"Usage\"), mdx(\"p\", null, \"Here is an example of a deferred event:\"), mdx(\"pre\", null, mdx(\"code\", _extends({\n    parentName: \"pre\"\n  }, {\n    \"className\": \"language-csharp\"\n  }), \"public event EventHandler<DeferredEventArgs> MyEvent;\\n\")), mdx(\"p\", null, \"The only difference here to a regular event is that the event arguments have to be of type \", mdx(\"a\", _extends({\n    parentName: \"p\"\n  }, {\n    \"href\": \"https://github.com/PedroLamas/DeferredEvents/blob/master/DeferredEvents/DeferredEventArgs.cs\"\n  }), \"DeferredEventArgs\"), \" (or a custom class inheriting from them), and that\\u2019s what allows the whole thing to work!\"), mdx(\"p\", null, \"Now take a look at how we raise this event:\"), mdx(\"pre\", null, mdx(\"code\", _extends({\n    parentName: \"pre\"\n  }, {\n    \"className\": \"language-csharp\"\n  }), \"await MyEvent.InvokeAsync(sender, new DeferredEventArgs());\\n\")), mdx(\"p\", null, \"The \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"InvokeAsync()\"), \" is an extension method that will wait for all event handlers to finish their work before we proceed.\"), mdx(\"p\", null, \"And finally, here\\u2019s how our event handler looks like:\"), mdx(\"pre\", null, mdx(\"code\", _extends({\n    parentName: \"pre\"\n  }, {\n    \"className\": \"language-csharp\"\n  }), \"public async void OnMyEvent(object sender, DeferredEventArgs e)\\n{\\n    var deferral = e.GetDeferral();\\n\\n    await DoSomethingAsync();\\n\\n    deferral.Complete();\\n}\\n\")), mdx(\"p\", null, \"The trick here is to call \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"e.GetDeferral()\"), \" to retrieve a deferral object, and just before we exit the method, we do \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"deferral.Complete()\"), \" to notify the invoker that we have completed our work!\"), mdx(\"p\", null, \"There are a few rules that you have to be aware of:\"), mdx(\"ul\", null, mdx(\"li\", {\n    parentName: \"ul\"\n  }, \"You only need to call \", mdx(\"inlineCode\", {\n    parentName: \"li\"\n  }, \"e.GetDeferral()\"), \" if you actually want to the event caller to wait for the completion of the event handler; if you don\\u2019t call it, it will just behave as a regular event handler.\"), mdx(\"li\", {\n    parentName: \"ul\"\n  }, \"You \", mdx(\"strong\", {\n    parentName: \"li\"\n  }, \"must\"), \" call \", mdx(\"inlineCode\", {\n    parentName: \"li\"\n  }, \"e.GetDeferral()\"), \" to get an \", mdx(\"inlineCode\", {\n    parentName: \"li\"\n  }, \"EventDeferral\"), \" instance before any \", mdx(\"inlineCode\", {\n    parentName: \"li\"\n  }, \"await\"), \" call in your code to ensure that the event caller knows that it should wait for \", mdx(\"inlineCode\", {\n    parentName: \"li\"\n  }, \"deferral.Complete()\"), \"; ideally, it should be the first thing you do in the event handler code.\"), mdx(\"li\", {\n    parentName: \"ul\"\n  }, \"If you have indeed called \", mdx(\"inlineCode\", {\n    parentName: \"li\"\n  }, \"e.GetDeferral()\"), \", then you \", mdx(\"strong\", {\n    parentName: \"li\"\n  }, \"must\"), \" call \", mdx(\"inlineCode\", {\n    parentName: \"li\"\n  }, \"deferral.Complete()\"), \" to signal that the event handler has finished.\")), mdx(\"p\", null, \"To ensure the correct usage of the deferred events, use the following as a template for your event handlers:\"), mdx(\"pre\", null, mdx(\"code\", _extends({\n    parentName: \"pre\"\n  }, {\n    \"className\": \"language-csharp\"\n  }), \"public async void OnMyEvent(object sender, DeferredEventArgs e)\\n{\\n    var deferral = e.GetDeferral();\\n\\n    try\\n    {\\n        // awaiteable code\\n    }\\n    finally\\n    {\\n        deferral.Complete();\\n    }\\n}\\n\")), mdx(\"p\", null, \"Alternatively, you can also use the \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"using\"), \" pattern like this:\"), mdx(\"pre\", null, mdx(\"code\", _extends({\n    parentName: \"pre\"\n  }, {\n    \"className\": \"language-csharp\"\n  }), \"public async void OnMyEvent(object sender, DeferredEventArgs e)\\n{\\n    using (e.GetDeferral())\\n    {\\n        // awaiteable code\\n    }\\n}\\n\")));\n}\n;\nMDXContent.isMDXComponent = true;","excerpt":"Developers should avoid  async void  methods, but there are some situations where this is a \"necessary evil\", and event handlers are one of those cases. If one needs to use the  await  keyword inside an event handler code, the method itself must be…","fields":{"slug":"/2017/04/04/await-your-event-handlers-completion-with-deferred-events/"},"frontmatter":{"categories":["Windows"],"date":"2017-04-04T13:55:59.000Z","dateFormatted":"April 4, 2017","image":null,"last_modified_at":"2019-11-13T19:06:45.000Z","layout":"post","tags":["Async","Events","Deferred Events",".NET",".NET Standard"],"title":"Await your event handlers completion with Deferred Events"},"file":{"__typename":"File","base":"2017-04-04-await-your-event-handlers-completion-with-deferred-events.md"}},"previousMdx":{"id":"d3d82068-4267-53e7-b55c-45aac93d0389","fields":{"slug":"/2017/03/21/setting-a-custom-user-agent-in-the-uwp-webview-control/"},"frontmatter":{"dateFormatted":"March 21, 2017","title":"Setting a custom User-Agent in the UWP WebView control"}},"nextMdx":{"id":"a3431ce0-e5d7-533f-b6bc-574ce31c5401","fields":{"slug":"/2017/04/24/creating-custom-build-configurations-for-the-dotnet-core-project-format/"},"frontmatter":{"dateFormatted":"April 24, 2017","title":"Creating custom build configurations for the .NET Core project format"}}},"pageContext":{"id":"1e7bf0e5-a082-5d06-8fe9-1ae192bd0f65","previousId":"d3d82068-4267-53e7-b55c-45aac93d0389","nextId":"a3431ce0-e5d7-533f-b6bc-574ce31c5401","lastModified":"2019-11-13T19:06:45.000Z"}}}