{"id":3044,"date":"2025-10-25T22:40:49","date_gmt":"2025-10-26T03:40:49","guid":{"rendered":"https:\/\/badecho.com\/?p=3044"},"modified":"2025-10-25T22:40:53","modified_gmt":"2025-10-26T03:40:53","slug":"wpf-with-generic-host","status":"publish","type":"post","link":"https:\/\/badecho.com\/index.php\/2025\/10\/25\/wpf-with-generic-host\/","title":{"rendered":"Running WPF Applications with a Generic Host"},"content":{"rendered":"\n<div class=\"wp-block-image hide-thumbnail\"><figure class=\"aligncenter size-thumbnail\"><img loading=\"lazy\" width=\"150\" height=\"150\" src=\"https:\/\/badecho.com\/wp-content\/uploads\/2025\/10\/WPFHostThumbnail-150x150.png\" alt=\"Running WPF Applications with a Generic Host\" class=\"wp-image-3087\" srcset=\"https:\/\/badecho.com\/wp-content\/uploads\/2025\/10\/WPFHostThumbnail-150x150.png 150w, https:\/\/badecho.com\/wp-content\/uploads\/2025\/10\/WPFHostThumbnail-300x300.png 300w, https:\/\/badecho.com\/wp-content\/uploads\/2025\/10\/WPFHostThumbnail-768x768.png 768w, https:\/\/badecho.com\/wp-content\/uploads\/2025\/10\/WPFHostThumbnail-480x480.png 480w, https:\/\/badecho.com\/wp-content\/uploads\/2025\/10\/WPFHostThumbnail.png 1000w\" sizes=\"(max-width: 150px) 100vw, 150px\" \/><\/figure><\/div>\n\n\n\n<p>Running a console application using a .NET Generic Host is simple enough; doing the same with a WPF application is another thing altogether.<\/p>\n\n\n\n<p>A WPF app, being a UI application, has its own internal &#8220;hosting&#8221; and lifetime mechanisms that are incompatible with the out-of-the-box .NET Generic Host.<\/p>\n\n\n\n<p>But that doesn&#8217;t mean it cannot be done; and, in fact, it can be done relatively cleanly.<\/p>\n\n\n\n<h2>Generic Host: Using vs Running<\/h2>\n\n\n\n<p>This article demonstrates how to set up a Generic Host to <em>run<\/em> a WPF application. But you might not need to do this.<\/p>\n\n\n\n<p>You can still <em>use<\/em> a Generic Host and take advantage of many of its features, such as dependency injection, configuration, and logging, all without needing it to run your application.<\/p>\n\n\n\n<p>If that&#8217;s all you require, simply start the host and run your WPF application. Don&#8217;t run the host.<\/p>\n\n\n\n<h6>App.xaml.cs &#8211; Using the host without running it<\/h6>\n\n\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\n[STAThread]\npublic static void Main()\n{\n    var builder = Host.CreateApplicationBuilder();\n\n    builder.Services\n           .AddSingleton&lt;MainWindow&gt;()\n           .AddSingleton&lt;MainViewModel&gt;()\n           .AddTransient&lt;FooViewModel&gt;()\n           .AddTransient&lt;BarViewModel&gt;(); \/\/etc.\n\n    IHost host = builder.Build();\n\n    host.Start();\n\n    var app = new App();\n\n    app.InitializeComponent();\n    app.MainWindow = host.Services.GetRequiredService&lt;MainWindow&gt;();\n    app.Run();\n}\n<\/pre>\n\n\n<p>All you need is something similar to the code above, and you&#8217;ll be able to inject view models into views, loggers into view models, etc. You don&#8217;t need to do anything else described in this article.<\/p>\n\n\n\n<p>Conversely, if you want the host to be in charge of the application&#8217;s lifetime (perhaps the application is meant to run in the background, whether a UI is currently displayed or not), or to take advantage of lifetime-related features such as IHostedService, then read on to find out how.<\/p>\n\n\n\n<h2>Running the Host: What&#8217;s the Problem?<\/h2>\n\n\n\n<p>The issue with running a host and a WPF application quickly becomes apparent.<\/p>\n\n\n\n<p>To run the host, we want to call <code>IHost.Run<\/code> instead of <code>IHost.Start<\/code>. Doing so will cause the current thread to block until the host shuts down.<\/p>\n\n\n\n<p>Consider the following WPF initialization code we were using previously:<\/p>\n\n\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\n    var app = new App();\n\n    app.InitializeComponent();\n    app.MainWindow = host.Services.GetRequiredService&lt;MainWindow&gt;();\n    app.Run();\n<\/pre>\n\n\n<p>This code will, of course, never run, because <code>IHost.Run<\/code> blocks. OK, resolving that is simple enough: we&#8217;ll move it to some place that will execute after the host has started.<\/p>\n\n\n\n<p>A perfect place for that is an <code>IHostedService<\/code>. We can start up our <code>App<\/code> instance in the service&#8217;s <code>StartAsync<\/code> implementation. Two big problems with that, however:<\/p>\n\n\n\n<ul><li><code>App.Run<\/code>, like <code>IHost.Run<\/code> also blocks, which will cause the <code>IHostedService<\/code> never to return and lock up the host&#8217;s launch.<\/li><li>The WPF application, being a UI and all, can only be run on a STA (single-threaded apartment) thread.<\/li><\/ul>\n\n\n\n<p>Both of these issues will prevent the application from successfully launching.<\/p>\n\n\n\n<h3>Using a BackgroundService Instead?<\/h3>\n\n\n\n<p>Instead of our own <code>IHostedService<\/code> implementation, we could derive from <code>BackgroundService<\/code>, which offers the <code>ExecuteAsync<\/code> override.<\/p>\n\n\n\n<p>Unlike a basic <code>IHostedService.StartAsync<\/code> implementation, <code>ExecuteAsync<\/code> (which will be called at host startup), can block as long as it wants without interfering with the host&#8217;s launch.<\/p>\n\n\n\n<p>Unfortunately, we will run smack dab into our second issue: the STA thread requirement. <code>ExecuteAsync<\/code> is invoked via a <code>Task.Run<\/code> call (which is not awaited, but is still tracked by assigning the <code>Task<\/code> to a field in the service instance).<\/p>\n\n\n\n<p>This will spawn a <code>Task<\/code> using the default <code>TaskScheduler<\/code>, which will not be on an STA thread.<\/p>\n\n\n\n<p>As you can see, a little work is required here.<\/p>\n\n\n\n<h2>Creating a UI Context<\/h2>\n\n\n\n<p>The rest of the code presented in this article is part of the <a href=\"https:\/\/github.com\/BadEcho\/presentation\" target=\"_blank\" rel=\"noreferrer noopener\">BadEcho.Presentation framework<\/a>, where you can find the most up-to-date versions of said code.<\/p>\n\n\n\n<p>Let&#8217;s first create a service\/construct that provides a context in which UI components can execute:<\/p>\n\n\n\n<h6>UserInterfaceContext.cs<\/h6>\n\n\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\n\/\/\/ &lt;summary&gt;\n\/\/\/ Provides a context for hosting UI components.\n\/\/\/ &lt;\/summary&gt;\npublic sealed class UserInterfaceContext\n{\n    private const int HRESULT_DISPATCHER_SHUTDOWN = unchecked((int)0x80131509);\n\n    private readonly Action _uiFunction;\n    private readonly Thread _uiThread;\n\n    private Dispatcher? _dispatcher;\n\n    \/\/\/ &lt;summary&gt;\n    \/\/\/ Initializes a new instance of the &lt;see cref=&quot;UserInterfaceContext&quot;\/&gt; class.\n    \/\/\/ &lt;\/summary&gt;\n    \/\/\/ &lt;param name=&quot;uiFunction&quot;&gt;The function to run in a UI-appropriate context.&lt;\/param&gt;\n    public UserInterfaceContext(Action uiFunction)\n    {\n        Require.NotNull(uiFunction, nameof(uiFunction));\n\n        _uiFunction = uiFunction;\n        \n        _uiThread = new Thread(UIFunctionRunner)\n                    {\n                        IsBackground = true\n                    };\n    \n        _uiThread.SetApartmentState(ApartmentState.STA);\n    }\n\n    \/\/\/ &lt;summary&gt;\n    \/\/\/ Occurs when this context's UI-related functionality has finished executing.\n    \/\/\/ &lt;\/summary&gt;\n    public event EventHandler&lt;EventArgs&gt;? Completed;\n\n    \/\/\/ &lt;summary&gt;\n    \/\/\/ Gets a value indicating if this context's UI-related functionality is executing.\n    \/\/\/ &lt;\/summary&gt;\n    public bool IsExecuting\n    { get; private set; }\n\n    \/\/\/ &lt;summary&gt;\n    \/\/\/ Gets the &lt;see cref=&quot;System.Windows.Threading.Dispatcher&quot;\/&gt; instance running within this\n    \/\/\/ context.\n    \/\/\/ &lt;\/summary&gt;\n    public Dispatcher Dispatcher\n        =&gt; _dispatcher ?? throw new InvalidOperationException(Strings.ContextHasNoDispatcher);\n\n    \/\/\/ &lt;summary&gt;\n    \/\/\/ Starts the execution of UI-related functionality.\n    \/\/\/ &lt;\/summary&gt;\n    public void Start()\n        =&gt; _uiThread.Start();\n\n    \/\/\/ &lt;summary&gt;\n    \/\/\/ Blocks the calling thread until the UI thread represented by this context exits.\n    \/\/\/ &lt;\/summary&gt;\n    public void Join()\n        =&gt; _uiThread.Join();\n\n    private void UIFunctionRunner()\n    {\n        try\n        {\n            _dispatcher = Dispatcher.CurrentDispatcher;\n            \n            var context = new DispatcherSynchronizationContext(_dispatcher);\n            SynchronizationContext.SetSynchronizationContext(context);\n            \n            IsExecuting = true;\n\n            _uiFunction();\n\n            IsExecuting = false;\n\n            Completed?.Invoke(this, EventArgs.Empty);\n        }\n        catch (InvalidOperationException invalidEx)\n        {\n            if (invalidEx.HResult != HRESULT_DISPATCHER_SHUTDOWN)\n                throw;\n\n            Logger.Debug(Strings.ContextDispatcherManuallyShutdown);\n        }\n    }\n}\n<\/pre>\n\n\n<p>This can be used to run any WPF component (such as a <code>Window<\/code>), ensuring it&#8217;s hosted on an STA thread. For our purposes, we&#8217;ll use it to start our WPF application&#8217;s <code>App<\/code> instance.<\/p>\n\n\n\n<p>The method responsible for invoking <code>App.Run<\/code> will be passed as an argument to the <code>UserInterfaceContext <\/code>constructor.<\/p>\n\n\n\n<h3>Application Runner UI Function<\/h3>\n\n\n\n<p>The <a href=\"https:\/\/github.com\/BadEcho\/presentation\" target=\"_blank\" rel=\"noreferrer noopener\">Bad Echo Presentation framework<\/a> includes a class, <code>UserInterface<\/code>, that provides several management-related functions for WPF applications and objects.<\/p>\n\n\n\n<p>Of note to us is the following function:<\/p>\n\n\n\n<h6>UserInterface.cs<\/h6>\n\n\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\n\/\/\/ &lt;summary&gt;\n\/\/\/ Runs the specified application in a context appropriate for hosting UI components.\n\/\/\/ &lt;\/summary&gt;\n\/\/\/ &lt;typeparam name=&quot;TApplication&quot;&gt;\n\/\/\/ The type of &lt;see cref=&quot;Application&quot;\/&gt; to instantiate and run in the context.\n\/\/\/ &lt;\/typeparam&gt;\n\/\/\/ &lt;param name=&quot;appFactory&quot;&gt;A factory method that creates the application.&lt;\/param&gt;\n\/\/\/ &lt;param name=&quot;configureApp&quot;&gt;A method that configures the application.&lt;\/param&gt;\n\/\/\/ &lt;returns&gt;The context hosting the application.&lt;\/returns&gt;\npublic static UserInterfaceContext RunApplication&lt;TApplication&gt;(Func&lt;TApplication&gt; appFactory,\n                                                                Action&lt;TApplication&gt; configureApp)\n    where TApplication : Application\n{\n    Require.NotNull(appFactory, nameof(appFactory));\n    Require.NotNull(configureApp, nameof(configureApp));\n\n    return new UserInterfaceContext(() =&gt;\n    {\n        TApplication app = appFactory();\n\n        configureApp(app);\n        \n        app.Run();\n    });\n}\n<\/pre>\n\n\n<p>You could certainly simplify things by integrating this code directly into <code>UserInterfaceContext<\/code>. This code comes from my library and is used for additional things unrelated to this article.<\/p>\n\n\n\n<h2>Starting Things Up with a Hosted Service<\/h2>\n\n\n\n<p>Our WPF application cannot begin running until the host has started. The simplest way to hook into a host&#8217;s lifecycle events is via an <code>IHostedService<\/code>, so let&#8217;s create an implementation that starts up our UI context once the host starts.<\/p>\n\n\n\n<h6>ApplicationHostedService.cs<\/h6>\n\n\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\n\/\/\/ &lt;summary&gt;\n\/\/\/ Provides a hosted service that runs a WPF application.\n\/\/\/ &lt;\/summary&gt;\ninternal sealed class ApplicationHostedService : IHostedService\n{\n    private readonly UserInterfaceContext _context;\n    private readonly IHostApplicationLifetime _lifetime;\n    \n    \/\/\/ &lt;summary&gt;\n    \/\/\/ Initializes a new instance of the &lt;see cref=&quot;ApplicationHostedService&quot;\/&gt; class.\n    \/\/\/ &lt;\/summary&gt;\n    public ApplicationHostedService(UserInterfaceContext context, IHostApplicationLifetime lifetime)\n    {\n        _context = context;\n        _lifetime = lifetime;\n        \n        _context.Completed += HandleContextCompleted;\n    }\n\n    \/\/\/ &lt;inheritdoc\/&gt;\n    public Task StartAsync(CancellationToken cancellationToken)\n    {\n        _context.Start();\n\n        return Task.CompletedTask;\n    }\n\n    \/\/\/ &lt;inheritdoc\/&gt;\n    public async Task StopAsync(CancellationToken cancellationToken)\n    {\n        if (!_context.IsExecuting)\n            return;\n\n        await _context.Dispatcher.InvokeAsync(() =&gt; Application.Current?.Shutdown());\n    }\n\n    private void HandleContextCompleted(object? sender, EventArgs e)\n    {\n        _lifetime.StopApplication();\n    }\n}\n<\/pre>\n\n\n<p>This hosted service starts a <code>UserInterfaceContext<\/code>, which spawns our WPF application and tears it down when our host shuts down.<\/p>\n\n\n\n<p>This service will also stop our host if the WPF application has been shut down. This occurs because a WPF <code>Application<\/code> object cannot simply be restarted if it has stopped.<\/p>\n\n\n\n<p>While this may sound like the WPF application will always control the host&#8217;s lifetime (as opposed to the other way around), the code in the next section will ensure that is not the case (when desired).<\/p>\n\n\n\n<h2>Extending the Service Collection<\/h2>\n\n\n\n<p>The last piece of our puzzle is a set of <code>IServiceCollection<\/code> extension methods that will bring all our previous code into play.<\/p>\n\n\n\n<h6>ServiceCollectionExtensions.cs<\/h6>\n\n\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\n\/\/\/ &lt;summary&gt;\n\/\/\/ Provides extensions methods for setting up services that integrate the Bad Echo Presentation\n\/\/\/ framework and Windows Presentation Foundation with a hosted application.\n\/\/\/ &lt;\/summary&gt;\npublic static class ServiceCollectionExtensions\n{\n    \/\/\/ &lt;summary&gt;\n    \/\/\/ Adds services that enable support for hosting the specified Windows Presentation Foundation\n    \/\/\/ application.\n    \/\/\/ &lt;\/summary&gt;\n    \/\/\/ &lt;typeparam name=&quot;TApplication&quot;&gt;The type of &lt;see cref=&quot;Application&quot;\/&gt; to host.&lt;\/typeparam&gt;\n    \/\/\/ &lt;param name=&quot;services&quot;&gt;\n    \/\/\/ The &lt;see cref=&quot;IServiceCollection&quot;\/&gt; instance to add services to.\n    \/\/\/ &lt;\/param&gt;\n    \/\/\/ &lt;returns&gt;\n    \/\/\/ The current &lt;see cref=&quot;IServiceCollection&quot;\/&gt; instance so that additional calls\n    \/\/\/ can be chained.\n    \/\/\/ &lt;\/returns&gt;\n    \/\/\/ &lt;remarks&gt;\n    \/\/\/ This method will configure any running application host so that its lifetime is shared with\n    \/\/\/ the WPF application. When the last window is closed, the application host will stop.\n    \/\/\/ &lt;\/remarks&gt;\n    public static IServiceCollection AddApplication&lt;TApplication&gt;(this IServiceCollection services)\n        where TApplication : Application\n    {\n        return services.AddApplication&lt;TApplication&gt;(true);\n    }\n\n    \/\/\/ &lt;summary&gt;\n    \/\/\/ Adds services that enable support for hosting the specified Windows Presentation Foundation\n    \/\/\/ application.\n    \/\/\/ &lt;\/summary&gt;\n    \/\/\/ &lt;typeparam name=&quot;TApplication&quot;&gt;The type of &lt;see cref=&quot;Application&quot;\/&gt; to host.&lt;\/typeparam&gt;\n    \/\/\/ &lt;param name=&quot;services&quot;&gt;\n    \/\/\/ The &lt;see cref=&quot;IServiceCollection&quot;\/&gt; instance to add services to.\n    \/\/\/ &lt;\/param&gt;\n    \/\/\/ &lt;param name=&quot;useWpfLifetime&quot;&gt;\n    \/\/\/ Value indicating if the lifetime of the host is tied to the lifetime of the WPF application.\n    \/\/\/ &lt;\/param&gt;\n    \/\/\/ &lt;returns&gt;\n    \/\/\/ The current &lt;see cref=&quot;IServiceCollection&quot;\/&gt; instance so that additional calls\n    \/\/\/ can be chained.\n    \/\/\/ &lt;\/returns&gt;\n    \/\/\/ &lt;remarks&gt;\n    \/\/\/ If &lt;paramref name=&quot;useWpfLifetime&quot;\/&gt; is &lt;c&gt;true&lt;\/c&gt;, the WPF application will shut down when\n    \/\/\/ the last window is closed, and any running application host will stop.\n    \/\/\/ &lt;\/remarks&gt;\n    public static IServiceCollection AddApplication&lt;TApplication&gt;(this IServiceCollection services, \n                                                                  bool useWpfLifetime)\n        where TApplication : Application\n    {\n        Require.NotNull(services, nameof(services));\n\n        var shutdownMode = useWpfLifetime\n            ? ShutdownMode.OnLastWindowClose\n            : ShutdownMode.OnExplicitShutdown;\n\n        services.AddSingleton&lt;Application, TApplication&gt;();\n        services.AddSingleton(CreateContext);\n\n        services.AddHostedService&lt;ApplicationHostedService&gt;();\n\n        return services;\n\n        UserInterfaceContext CreateContext(IServiceProvider serviceProvider)\n        {\n            return UserInterface.RunApplication(serviceProvider.GetRequiredService&lt;Application&gt;,\n                                                app =&gt; app.ShutdownMode = shutdownMode);\n        }\n    }\n}\n<\/pre>\n\n\n<p>Calling this will make the dependency injection container responsible for initializing the <code>Application<\/code> object and running it on a user interface context thread.<\/p>\n\n\n\n<p>If <code>useWpfLifetime<\/code> is false, the host controls the lifetime of the overall application; otherwise, the WPF application does. This is achieved by setting the appropriate <code>ShutdownMode<\/code> for the <code>Application<\/code> object.<\/p>\n\n\n\n<p>When the shutdown mode is <code>OnExplicitShutdown<\/code>, the <code>Application<\/code> will only shut down on the call to <code>Application.Shutdown<\/code> is made by our <code>ApplicationHostedService<\/code> when the host shuts down.<\/p>\n\n\n\n<h3>Additional Shutdown Protections<\/h3>\n\n\n\n<p>None of this prevents code within the WPF application from calling <code>Application.Shutdown<\/code> itself. If that happens, then ultimately the WPF application is in control of the host&#8217;s lifetime, since <code>ApplicationHostedService<\/code> will call <code>StopApplication<\/code> when the context thread is done running.<\/p>\n\n\n\n<p>Because the WPF application is our own code, it&#8217;s up to us to ensure that doesn&#8217;t happen. But if we wanted greater assurance that the host is in complete control of its lifetime, we could add code that prevents <code>ApplicationHostedService<\/code> from calling <code>StopApplication<\/code> if the context thread is no longer running during a host shutdown.<\/p>\n\n\n\n<p>However, doing that requires that our context thread be restartable, which, at the moment, I don&#8217;t feel is worth the effort or additional complexity.<\/p>\n\n\n\n<h2>Example Usage<\/h2>\n\n\n\n<p>We can now easily set up our WPF application to be hosted by a Generic Host:<\/p>\n\n\n\n<h6>Program.cs<\/h6>\n\n\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\nvar builder = Host.CreateApplicationBuilder();\n\nbuilder.Services\n       .AddApplication&lt;App&gt;()\n       .AddSingleton&lt;MainWindow&gt;()\n       .AddSingleton&lt;MainViewModel&gt;()\n       .AddSingleton&lt;NavigationPaneViewModel&gt;()\n       .AddTransient&lt;HomeViewModel&gt;()\n       .AddTransient&lt;ActionsViewModel&gt;();\n\nvar host = builder.Build();\n\nhost.Run();\n<\/pre>\n\n\n<p>And that&#8217;s it! Nice and easy.<\/p>\n\n\n\n<h2>One Additional Caveat<\/h2>\n\n\n\n<p>This pertains more to the dependency injection container than to the Generic Host, but I thought it&#8217;d be helpful to address one issue you may run into.<\/p>\n\n\n\n<p>Because the dependency injection container now creates the <code>Application<\/code> object, we&#8217;ll want to take advantage of that and have our main window (which will itself be injected with its own view model and other dependencies) as well as any other desired services injected into it.<\/p>\n\n\n\n<p>To do that, we&#8217;d change our constructor to look like the following:<\/p>\n\n\n\n<h6>App.xaml.cs<\/h6>\n\n\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\n\/\/\/ &lt;summary&gt;\n\/\/\/ Initializes a new instance of the &lt;see cref=&quot;App&quot;\/&gt; class.\n\/\/\/ &lt;\/summary&gt;\npublic App(MainWindow window, ILogger&lt;Application&gt; logger)\n{\n    _logger = logger;\n\n    InitializeComponent();\n\n    window.InitializeComponent();\n    window.Show();\n}\n<\/pre>\n\n\n<p>We would, of course, also remove the <code>StartupUri<\/code> from the <code>Application<\/code> element in <code>App.xaml<\/code>.<\/p>\n\n\n\n<p>However, errors will arise if we attempt to compile our project. They will originate from an MSBuild task that runs during WPF application compilation. <\/p>\n\n\n\n<p>This task is responsible for creating the application entry point, and will run even though our own entry point in <code>Program.cs<\/code> (where we set up the host) will ultimately supersede it.<\/p>\n\n\n\n<p>This MSBuild task generates code that initializes our <code>Application<\/code> class, and it expects the <code>Application<\/code> derivative to have a default constructor, which it normally does.<\/p>\n\n\n\n<p>So, to rectify this issue, don&#8217;t forget to add a private default constructor to <code>App.xaml.cs<\/code>:<\/p>\n\n\n\n<h6>App.xaml.cs<\/h6>\n\n\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\nprivate App()\n{\n    InitializeComponent();\n}\n<\/pre>\n\n\n<p>The call to <code>InitializeComponent<\/code> is required for the XAML designer to work properly at design time.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Running a console application using a .NET Generic Host is simple enough; doing the same with a WPF application is [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[10],"tags":[41,42,93,64],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v14.9 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\r\n<title>Running WPF Applications with a Generic Host - omni&#039;s hackpad<\/title>\r\n<meta name=\"description\" content=\"A .NET Generic Host doesn&#039;t support running a WPF application out of the box. This post shows how to rectify that.\" \/>\r\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\r\n<link rel=\"canonical\" href=\"https:\/\/badecho.com\/index.php\/2025\/10\/25\/wpf-with-generic-host\/\" \/>\r\n<meta property=\"og:locale\" content=\"en_US\" \/>\r\n<meta property=\"og:type\" content=\"article\" \/>\r\n<meta property=\"og:title\" content=\"Running WPF Applications with a Generic Host - omni&#039;s hackpad\" \/>\r\n<meta property=\"og:description\" content=\"A .NET Generic Host doesn&#039;t support running a WPF application out of the box. This post shows how to rectify that.\" \/>\r\n<meta property=\"og:url\" content=\"https:\/\/badecho.com\/index.php\/2025\/10\/25\/wpf-with-generic-host\/\" \/>\r\n<meta property=\"og:site_name\" content=\"omni&#039;s hackpad\" \/>\r\n<meta property=\"article:published_time\" content=\"2025-10-26T03:40:49+00:00\" \/>\r\n<meta property=\"article:modified_time\" content=\"2025-10-26T03:40:53+00:00\" \/>\r\n<meta property=\"og:image\" content=\"https:\/\/badecho.com\/wp-content\/uploads\/2025\/10\/WPFHostThumbnail-150x150.png\" \/>\r\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\r\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"WebSite\",\"@id\":\"https:\/\/badecho.com\/#website\",\"url\":\"https:\/\/badecho.com\/\",\"name\":\"omni&#039;s hackpad\",\"description\":\"Game Code Disassembly. Omnified Modification. Madness.\",\"publisher\":{\"@id\":\"https:\/\/badecho.com\/#\/schema\/person\/3de67496328be7ae6e1f52faf582e9d2\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":\"https:\/\/badecho.com\/?s={search_term_string}\",\"query-input\":\"required name=search_term_string\"}],\"inLanguage\":\"en-US\"},{\"@type\":\"ImageObject\",\"@id\":\"https:\/\/badecho.com\/index.php\/2025\/10\/25\/wpf-with-generic-host\/#primaryimage\",\"inLanguage\":\"en-US\",\"url\":\"https:\/\/badecho.com\/wp-content\/uploads\/2025\/10\/WPFHostThumbnail.png\",\"width\":1000,\"height\":1000,\"caption\":\"Running WPF Applications with a Generic Host\"},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/badecho.com\/index.php\/2025\/10\/25\/wpf-with-generic-host\/#webpage\",\"url\":\"https:\/\/badecho.com\/index.php\/2025\/10\/25\/wpf-with-generic-host\/\",\"name\":\"Running WPF Applications with a Generic Host - omni&#039;s hackpad\",\"isPartOf\":{\"@id\":\"https:\/\/badecho.com\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/badecho.com\/index.php\/2025\/10\/25\/wpf-with-generic-host\/#primaryimage\"},\"datePublished\":\"2025-10-26T03:40:49+00:00\",\"dateModified\":\"2025-10-26T03:40:53+00:00\",\"description\":\"A .NET Generic Host doesn't support running a WPF application out of the box. This post shows how to rectify that.\",\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/badecho.com\/index.php\/2025\/10\/25\/wpf-with-generic-host\/\"]}]},{\"@type\":\"Article\",\"@id\":\"https:\/\/badecho.com\/index.php\/2025\/10\/25\/wpf-with-generic-host\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/badecho.com\/index.php\/2025\/10\/25\/wpf-with-generic-host\/#webpage\"},\"author\":{\"@id\":\"https:\/\/badecho.com\/#\/schema\/person\/3de67496328be7ae6e1f52faf582e9d2\"},\"headline\":\"Running WPF Applications with a Generic Host\",\"datePublished\":\"2025-10-26T03:40:49+00:00\",\"dateModified\":\"2025-10-26T03:40:53+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/badecho.com\/index.php\/2025\/10\/25\/wpf-with-generic-host\/#webpage\"},\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/badecho.com\/#\/schema\/person\/3de67496328be7ae6e1f52faf582e9d2\"},\"image\":{\"@id\":\"https:\/\/badecho.com\/index.php\/2025\/10\/25\/wpf-with-generic-host\/#primaryimage\"},\"keywords\":\".NET,C#,DI,WPF\",\"articleSection\":\"General Dev\",\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/badecho.com\/index.php\/2025\/10\/25\/wpf-with-generic-host\/#respond\"]}]},{\"@type\":[\"Person\",\"Organization\"],\"@id\":\"https:\/\/badecho.com\/#\/schema\/person\/3de67496328be7ae6e1f52faf582e9d2\",\"name\":\"Matt Weber\",\"image\":{\"@type\":\"ImageObject\",\"@id\":\"https:\/\/badecho.com\/#personlogo\",\"inLanguage\":\"en-US\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/7e345ac2708b3a41c7bd70a4a0440d41?s=96&d=mm&r=g\",\"caption\":\"Matt Weber\"},\"logo\":{\"@id\":\"https:\/\/badecho.com\/#personlogo\"}}]}<\/script>\r\n<!-- \/ Yoast SEO plugin. -->","_links":{"self":[{"href":"https:\/\/badecho.com\/index.php\/wp-json\/wp\/v2\/posts\/3044"}],"collection":[{"href":"https:\/\/badecho.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/badecho.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/badecho.com\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/badecho.com\/index.php\/wp-json\/wp\/v2\/comments?post=3044"}],"version-history":[{"count":41,"href":"https:\/\/badecho.com\/index.php\/wp-json\/wp\/v2\/posts\/3044\/revisions"}],"predecessor-version":[{"id":3089,"href":"https:\/\/badecho.com\/index.php\/wp-json\/wp\/v2\/posts\/3044\/revisions\/3089"}],"wp:attachment":[{"href":"https:\/\/badecho.com\/index.php\/wp-json\/wp\/v2\/media?parent=3044"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/badecho.com\/index.php\/wp-json\/wp\/v2\/categories?post=3044"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/badecho.com\/index.php\/wp-json\/wp\/v2\/tags?post=3044"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}