We\'ve made a WPF application with a traditional UI (common controls like tabs, buttons, labels, textboxes, and so on).
We need to add a \"night vision\" mode, which
One suggestion is of course Mahapps
Themes.
You could switch between Light and Dark by this :
// get the theme from the current application
var theme = ThemeManager.DetectAppStyle(Application.Current);
// now set the Green accent and dark theme
ThemeManager.ChangeAppStyle(Application.Current,
ThemeManager.GetAccent("Green"),
ThemeManager.GetAppTheme("BaseDark"));
( Mahapps.Styles for ref )
Or you could use DynamicResource for each Brushes and change the SINGLE ResourceDictionary
holding them to change everything in a click :)
Alternatively, consider just using the DWM Magnification functionality to make all of windows go into "Night-Mode".
Example:
See the Magnification API sample, with modifications below:
/*************************************************************************************************
*
* File: FullscreenMagnifierSample.cpp
*
* Description: Implements simple UI to control fullscreen magnification, using the
* Magnification API.
*
* Copyright (C) Microsoft Corporation. All rights reserved.
*
* This source code is intended only as a supplement to Microsoft
* Development Tools and/or on-line documentation. See these other
* materials for detailed information regarding Microsoft code samples.
*
* THIS CODE AND INFORMATION ARE PROVIDED AS IS WITHOUT WARRANTY OF ANY
* KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
* PARTICULAR PURPOSE.
*
*************************************************************************************************/
#include "windows.h"
#include "resource.h"
#include "strsafe.h"
#include "magnification.h"
// Global variables and strings.
const LPWSTR g_pszAppTitle = L"Night Colors";
// Initialize color effect matrices to apply grayscale or restore the colors on the desktop.
MAGCOLOREFFECT g_MagEffectIdentity = {
1.0f, 0.0f, 0.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f, 0.0f, 1.0f };
MAGCOLOREFFECT g_MagEffectWashout = {
0.5f, 0.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.3f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.3f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f, 0.0f, 1.0f };
MAGCOLOREFFECT g_MagEffectWashout2 = {
0.35f, 0.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.2f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.2f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f, 0.0f, 1.0f };
MAGCOLOREFFECT g_MagEffectWashout3 = {
0.25f, 0.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.13f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.13f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f, 0.0f, 1.0f };
/*MAGCOLOREFFECT g_MagEffectGrayscale = {0.3f, 0.3f, 0.3f, 0.0f, 0.0f,
0.6f, 0.6f, 0.6f, 0.0f, 0.0f,
0.1f, 0.1f, 0.1f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f, 0.0f, 1.0f};*/
MAGCOLOREFFECT g_MagEffectGrayscaleInverted = {
-0.3f, 0.0f, 0.0f, 0.0f, 0.0f,
-0.6f, 0.0f, 0.0f, 0.0f, 0.0f,
-0.1f, 0.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f, 0.0f,
1.0f, 0.0f, 0.0f, 0.0f, 1.0f };
MAGCOLOREFFECT g_MagEffectInverted = {
-1.0f, 0.0f, 0.0f, 0.0f, 0.0f,
0.0f, -1.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, -1.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f, 0.0f,
1.0f, 1.0f, 1.0f, 0.0f, 1.0f
};
MAGCOLOREFFECT g_MagEffectGrayscale = {0.3f, 0.0f, 0.0f, 0.0f, 0.0f,
0.6f, 0.0f, 0.0f, 0.0f, 0.0f,
0.1f, 0.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f, 0.0f, 1.0f};
// Forward declarations.
INT_PTR CALLBACK SampleDialogProc(_In_ HWND hwndDlg, _In_ UINT uMsg, _In_ WPARAM wParam, _In_ LPARAM lParam);
void InitDlg(_In_ HWND hwndDlg);
void HandleCommand(_In_ HWND hwndDlg, _In_ WORD wCtrlId);
//
// FUNCTION: WinMain()
//
// PURPOSE: Entry point for the application.
//
int APIENTRY WinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE /*hPrevInstance*/,
_In_ LPSTR /*lpCmdLine*/,
_In_ int /*nCmdShow*/)
{
// Initialize the magnification functionality for this process.
if (MagInitialize())
{
// Present a dialog box to allow the user to control fullscreen magnification.
DialogBox(hInstance, MAKEINTRESOURCE(IDD_DIALOG_FULLSCREENMAGNIFICATIONCONTROL), NULL, SampleDialogProc);
// Any current magnification and color effects will be turned off as a result of calling MagUninitialize().
MagUninitialize();
}
else
{
MessageBox(NULL, L"Failed to initialize magnification.", g_pszAppTitle, MB_OK);
}
return 0;
}
//
// FUNCTION: SampleDialogProc()
//
// PURPOSE: Dialog proc for the UI used for controlling fullscreen magnification.
//
INT_PTR CALLBACK SampleDialogProc(
_In_ HWND hwndDlg,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM /*lParam*/
)
{
INT_PTR ipRet = 0;
switch (uMsg)
{
case WM_INITDIALOG:
InitDlg(hwndDlg);
ipRet = 0;
break;
case WM_COMMAND:
if(HIWORD(wParam) == BN_CLICKED)
{
WORD wCtrlId = LOWORD(wParam);
HandleCommand(hwndDlg, wCtrlId);
ipRet = 1;
}
break;
case WM_CLOSE:
EndDialog(hwndDlg, 0);
break;
}
return ipRet;
}
//
// FUNCTION: InitDlg()
//
// PURPOSE: Initialize the sample dialog box's position and controls.
//
void InitDlg(_In_ HWND hwndDlg)
{
// Position the dialog box in the center of the primary monitor.
RECT rcDlg;
GetWindowRect(hwndDlg, &rcDlg);
int xDlg = (GetSystemMetrics(SM_CXSCREEN) - (rcDlg.right - rcDlg.left)) / 2;
int yDlg = (GetSystemMetrics(SM_CYSCREEN) - (rcDlg.bottom - rcDlg.top)) / 2;
SetWindowPos(hwndDlg, NULL, xDlg, yDlg, 0, 0, SWP_NOZORDER | SWP_NOSIZE);
// Set the default color and invalidate the status
DWORD defaultColor = IDC_CHECK_SETRED_INVERTED;
HWND hwndControl = GetDlgItem(hwndDlg, defaultColor);
SendMessage(hwndControl, BM_SETCHECK, BST_CHECKED, 0);
HandleCommand(hwndDlg, defaultColor);
SetFocus(hwndControl);
}
//
// FUNCTION: HandleCommand()
//
// PURPOSE: Take action in response to user action at the dialog box's controls.
//
void HandleCommand(_In_ HWND hwndDlg, _In_ WORD wCtrlId)
{
switch (wCtrlId)
{
case IDC_CHECK_SETRED:
{
if (IsDlgButtonChecked(hwndDlg, IDC_CHECK_SETRED))
{
MagSetFullscreenColorEffect(&g_MagEffectGrayscale);
}
}
break;
case IDC_CHECK_SETRED_INVERTED:
{
if (IsDlgButtonChecked(hwndDlg, IDC_CHECK_SETRED_INVERTED))
{
MagSetFullscreenColorEffect(&g_MagEffectGrayscaleInverted);
}
}
break;
case IDC_CHECK_SET_INVERTED:
{
if (IsDlgButtonChecked(hwndDlg, IDC_CHECK_SET_INVERTED))
{
MagSetFullscreenColorEffect(&g_MagEffectInverted);
}
}
break;
case IDC_CHECK_SET_WASHOUT:
{
if (IsDlgButtonChecked(hwndDlg, IDC_CHECK_SET_WASHOUT))
{
MagSetFullscreenColorEffect(&g_MagEffectWashout);
}
}
break;
case IDC_CHECK_SET_WASHOUT2:
{
if (IsDlgButtonChecked(hwndDlg, IDC_CHECK_SET_WASHOUT2))
{
MagSetFullscreenColorEffect(&g_MagEffectWashout2);
}
}
break;
case IDC_CHECK_SET_WASHOUT3:
{
if (IsDlgButtonChecked(hwndDlg, IDC_CHECK_SET_WASHOUT3))
{
MagSetFullscreenColorEffect(&g_MagEffectWashout3);
}
}
break;
}
}
You can also do this on a window by window basis by compiling a HLSL shader and setting it as an effect upon the window. This technique also works if you need to vary the intensity.
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.img.Source = new BitmapImage(new Uri("https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_272x92dp.png"));
this.Effect = new ColorComplementEffect();
}
}
public class ColorComplementEffect : ShaderEffect
{
public ColorComplementEffect()
{
PixelShader = _shader;
UpdateShaderValue(InputProperty);
}
public Brush Input
{
get { return (Brush)GetValue(InputProperty); }
set { SetValue(InputProperty, value); }
}
public static readonly DependencyProperty InputProperty = ShaderEffect.RegisterPixelShaderSamplerProperty("Input", typeof(ColorComplementEffect), 0);
private static PixelShader _shader = new PixelShader() { UriSource = new Uri(@"cc.ps") };
}
Shader:
sampler2D implicitInput : register(s0);
float4 main(float2 uv : TEXCOORD) : COLOR
{
float4 color = tex2D(implicitInput, uv);
float4 complement;
complement.r = (color.a - color.r) * 0.2;
complement.g = (color.a - color.g) * 0.2;
complement.b = (color.a - color.b) * 0.2;
complement.a = color.a;
return complement;
}