Skip to content

Commit

Permalink
Added Readme.
Browse files Browse the repository at this point in the history
  • Loading branch information
Aldaviva committed Apr 17, 2021
1 parent bab787e commit f904c60
Show file tree
Hide file tree
Showing 9 changed files with 260 additions and 20 deletions.
239 changes: 239 additions & 0 deletions Readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,239 @@
DarkNet
===

This is a .NET library that you can use to enable Windows 10's dark mode for your application's title bars and system context menus, similar to the dark title bar in Command Prompt.

![WPF window with dark title bar](https://i.imgur.com/yWWyS0J.png)

<!-- MarkdownTOC autolink="true" bracket="round" autoanchor="true" levels="1,2,3,4" -->

- [Requirements](#requirements)
- [Installation](#installation)
- [WPF](#wpf)
- [Windows Forms](#windows-forms)
- [Usage](#usage)
- [WPF](#wpf-1)
- [On application startup](#on-application-startup)
- [Before showing a new window](#before-showing-a-new-window)
- [Complete example](#complete-example)
- [Windows Forms](#windows-forms-1)
- [On application startup](#on-application-startup-1)
- [Before showing a new window](#before-showing-a-new-window-1)
- [Complete example](#complete-example-1)
- [Demo](#demo)
- [WPF](#wpf-2)
- [Windows Forms](#windows-forms-2)
- [Limitations](#limitations)
- [Acknowledgements](#acknowledgements)

<!-- /MarkdownTOC -->

<a id="requirements"></a>
## Requirements

- .NET Framework 4.7.2 or later, or .NET Core 3.1 or later
- Windows 10 version 1809 (October 2018 Update) or later for dark mode to work
- You can run your app on earlier Windows versions, but the title bar won't turn dark
- WPF or Windows Forms

<a id="installation"></a>
## Installation

There are two packages available, one for WPF and one for Windows Forms. You can install the one that corresponds to the GUI technology that your program uses.

<a id="wpf"></a>
### WPF
```ps1
dotnet add package DarkNet-WPF
```
[See **DarkNet-WPF** on NuGet](https://www.nuget.org/packages/DarkNet-WPF/)

<a id="windows-forms"></a>
### Windows Forms
```ps1
dotnet add package DarkNet-Forms
```
[See **DarkNet-Forms** on NuGet](https://www.nuget.org/packages/DarkNet-Forms/)

<a id="usage"></a>
## Usage

<a id="wpf-1"></a>
### WPF

You must do both of the following steps.

<a id="on-application-startup"></a>
#### On application startup

Before showing **any** windows in your application, you must call
```cs
darknet.wpf.DarkNet.SetDarkModeAllowedForProcess(true);
```

A good place to call this is in an event handler for your Application's `Startup` event.

By default, WPF apps have an `App.xaml` file that specifies the first `Window` to show in the `StartupUri` attribute:
```xaml
<Application StartupUri="MainWindow.xaml">
```

This does not allow you to run custom code before showing the window, so remove `StartupUri` and add `Startup`, which specifies an event handler method.
```xaml
<Application Startup="App_OnStartup">
```

In `App.xaml.cs`, create a method to handle this event and call the aforementioned DarkNet method.
```cs
public partial class App: Application {

private void App_OnStartup(object sender, StartupEventArgs e) {
DarkNet.SetDarkModeAllowedForProcess(true);

// Incomplete example; see below for complete example including showing your first window.
}
}
```

<a id="before-showing-a-new-window"></a>
#### Before showing a new window

Before showing each window in your application, you have to enable dark mode for that window.

```cs
darknet.wpf.DarkNet.SetDarkModeAllowedForWindow(window, true);
```

You must do this when the `SourceInitialized` event is fired for the window you are about to show. If you do it before this (such as right before calling the constructor), the Win32 HWND will not exist yet, so the native DLL calls will fail. If you call it too late (such as after the window is shown), the DLL calls will have no effect on Windows.

Add an event handler for the `SourceInitialized` event and call the aforementioned DarkNet method.

```cs
window.SourceInitialized += (_, _) => { DarkNet.SetDarkModeAllowedForWindow(window, true); };
```

You must also perform this step for all subsequent windows you show in your application, not just the first window.

<a id="complete-example"></a>
#### Complete example

```cs
public partial class App: Application {

private void App_OnStartup(object sender, StartupEventArgs e) {
DarkNet.SetDarkModeAllowedForProcess(true);

Window window = new MainWindow();
window.SourceInitialized += (_, _) => { DarkNet.SetDarkModeAllowedForWindow(window, true); };

window.Show();
}

}
```

<a id="windows-forms-1"></a>
### Windows Forms

You must do both of the following steps.

<a id="on-application-startup-1"></a>
#### On application startup

Before showing **any** windows in your application, you must call
```cs
darknet.forms.DarkNet.SetDarkModeAllowedForProcess(true);
```

A good place to call this is at the top of the `Main()` method of your application.

```cs
internal static class Program {

[STAThread]
private static void Main() {
DarkNet.SetDarkModeAllowedForProcess(true);

// Incomplete example; see below for complete example including showing your first window.
}
}
```

<a id="before-showing-a-new-window-1"></a>
#### Before showing a new window

Before showing each window in your application, you have to enable dark mode for that window.

```cs
darknet.forms.DarkNet.SetDarkModeAllowedForWindow(window, true);
```

You must do this before showing the window with `Show()` or `Application.Run()`. If you call it too late (such as after the window is shown), the DLL calls will have no effect on Windows.

Call the aforementioned DarkNet method after the window is constructed.

```cs
Form mainForm = new Form1();
DarkNet.SetDarkModeAllowedForWindow(mainForm, true);
```

You must also perform this step for all subsequent windows you show in your application, not just the first window.

<a id="complete-example-1"></a>
#### Complete example

```cs
internal static class Program {

[STAThread]
private static void Main() {
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
DarkNet.SetDarkModeAllowedForProcess(true);

Form mainForm = new Form1();
DarkNet.SetDarkModeAllowedForWindow(mainForm, true);
mainForm.Show();

Application.Run(mainForm);
}

}
```
<a id="acknowledgements"></a>

<a id="demo"></a>
## Demo

<a id="wpf-2"></a>
### WPF

Download and run `darknet-demo-wpf.exe` from the [latest release](https://github.com/Aldaviva/DarkNet/releases).

![WPF window with dark title bar](https://i.imgur.com/yWWyS0J.png)

You can also clone this repository and build the `darknet-demo-wpf` project yourself using Visual Studio Community 2019.

<a id="windows-forms-2"></a>
### Windows Forms

Download and run `darknet-demo-forms.exe` from the [latest release](https://github.com/Aldaviva/DarkNet/releases).

![Windows Forms window with dark title bar](https://i.imgur.com/3PDwxTy.png)

You can also clone this repository and build the `darknet-demo-forms` project yourself using Visual Studio Community 2019.

<a id="limitations"></a>
## Limitations
- This library currently requires a fairly recent version of Windows and the .NET runtime. This could be relaxed in a future version to allow inclusion in applications that run in a wider range of environments.
- This library currently does not expose whether the active Windows app mode is set to Dark or Light. This may be possible to add in a future version to allow you to implement a "follow Windows app mode" strategy in your application.
- This library only changes the theme of the title bar/window chrome/non-client area, as well as the system context menu (the menu that appears when you right click on the title bar, or left click on the title bar icon, or hit `Alt`+`Space`). It does not change the theme of the client area of your window. It is up to you to make that look different when dark mode is enabled.
- This library currently does not help you persist a user choice for the mode they want your application to use. You can expose an option and persist that yourself, then pass the desired value to the methods in this library (*e.g.* call `DarkNet.SetDarkModeAllowedForProcess(false)` for light mode, or just don't call it at all).

<a id="acknowledgements"></a>
## Acknowledgements

- [Milan Burda](https://github.com/miniak) for explaining how to add this in Electron ([electron/electron #23479: [Windows] Title bar does not respect dark mode](https://github.com/electron/electron/issues/23479))
- [dyasta](https://stackoverflow.com/users/191514/dyasta) for an [exaplanation on Stack Overflow](https://stackoverflow.com/a/58547831/979493)
- [Richard Yu](https://github.com/ysc3839) for [implementing this in a C++ library](https://github.com/ysc3839/win32-darkmode)
- [Berrysoft](https://github.com/Berrysoft) for [implementing this in Mintty, the Cygwin Terminal emulator](https://github.com/mintty/mintty/issues/983) ([further discussion](https://github.com/mintty/mintty/pull/984))
2 changes: 1 addition & 1 deletion darknet-demo-winforms/Form1.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions darknet-demo-winforms/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ internal static class Program {
private static void Main() {
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);

DarkNet.SetDarkModeAllowedForProcess(true);
var mainForm = new Form1();

Form mainForm = new Form1();
DarkNet.SetDarkModeAllowedForWindow(mainForm, true);
mainForm.Show();

Expand Down
10 changes: 6 additions & 4 deletions darknet-demo-winforms/darknet-demo-winforms.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -62,10 +62,12 @@
<None Include="App.config" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\darknet\DarkNet.csproj">
<Project>{8f367ec7-f0f9-4b96-8793-91f06ac78320}</Project>
<Name>DarkNet</Name>
</ProjectReference>
<PackageReference Include="DarkNet-Forms">
<Version>1.0.0</Version>
</PackageReference>
<PackageReference Include="ILRepack.Lib.MSBuild.Task">
<Version>2.0.18.2</Version>
</PackageReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>
3 changes: 1 addition & 2 deletions darknet-demo-wpf/App.xaml
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
<Application x:Class="darknet_wpf.App"
<Application x:Class="darknet_demo_wpf.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:darknet_wpf"
Startup="App_OnStartup">
<Application.Resources>

Expand Down
3 changes: 1 addition & 2 deletions darknet-demo-wpf/App.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

#nullable enable

namespace darknet_wpf {
namespace darknet_demo_wpf {

public partial class App {

Expand All @@ -14,7 +14,6 @@ private void App_OnStartup(object sender, StartupEventArgs e) {
window.SourceInitialized += (_, _) => { DarkNet.SetDarkModeAllowedForWindow(window, true); };

window.Show();

}

}
Expand Down
3 changes: 1 addition & 2 deletions darknet-demo-wpf/MainWindow.xaml
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
<Window x:Class="darknet_wpf.MainWindow"
<Window x:Class="darknet_demo_wpf.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:darknet_wpf"
mc:Ignorable="d"
Title="Windows Presentation Foundation demonstration" Height="450" Width="800" Background="#FF131313">
<Grid>
Expand Down
2 changes: 1 addition & 1 deletion darknet-demo-wpf/MainWindow.xaml.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
namespace darknet_wpf {
namespace darknet_demo_wpf {

public partial class MainWindow {

Expand Down
14 changes: 8 additions & 6 deletions darknet-demo-wpf/darknet-demo-wpf.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{A626852B-6C05-4D42-9E60-45EA30D35513}</ProjectGuid>
<OutputType>WinExe</OutputType>
<RootNamespace>darknet_wpf</RootNamespace>
<AssemblyName>darknet-wpf</AssemblyName>
<RootNamespace>darknet_demo_wpf</RootNamespace>
<AssemblyName>darknet-demo-wpf</AssemblyName>
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
Expand Down Expand Up @@ -82,10 +82,12 @@
<None Include="App.config" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\darknet\DarkNet.csproj">
<Project>{8f367ec7-f0f9-4b96-8793-91f06ac78320}</Project>
<Name>DarkNet</Name>
</ProjectReference>
<PackageReference Include="DarkNet-WPF">
<Version>1.0.0</Version>
</PackageReference>
<PackageReference Include="ILRepack.Lib.MSBuild.Task">
<Version>2.0.18.2</Version>
</PackageReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

0 comments on commit f904c60

Please sign in to comment.