WPF Windows上的夜视模式

我们使用传统的UI(常用控件,如标签,按钮,标签,文本框等)制作了WPF应用程序。

我们需要添加一个“夜视”模式,这将使它看起来像Stellarium的夜视模式,因此它可以在几乎没有或根本没有光的地方舒适地使用。

据我所见,我们只有两个选择:

  1. 一种称为“着色”的技术(我不知道如何在WPF中实现)。
  2. 蛮力方式:定义控件的样式模板。 如你所知,这意味着一项巨大的工作,因为我们需要为每个使用的控件(边框,背景,画笔等等)重新定义每个属性。

问题是:

  1. 在WPF中实现这一目标的最佳方法是什么?
  2. 如果我们使用MahApps Metro Style会更复杂吗? 我知道MahApps可以让你自定义他们的风格,但问题就是在不同的模板之间切换(分别用于白天和夜晚的两个模板)。

非常感谢你!

一个建议当然是Mahapps主题。 您可以通过以下方式在Light和Dark之间切换:

 // 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 )

或者您可以为每个Brushes使用DynamicResource并更改SINGLE ResourceDictionary保存它们以更改单击中的所有内容:)

或者,考虑仅使用DWM放大function使所有窗口进入“夜间模式”。

例: Internet Explorer的视图与颜色倒置,并在琥珀色灰度

请参阅Magnification API示例,其中包含以下修改:

 /************************************************************************************************* * * 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; } } 

窗口特定

您也可以通过编译HLSL着色器并将其设置为对窗口的效果,逐个窗口地执行此操作。 如果您需要改变强度,这种技术也有效。

 ///  /// Interaction logic for MainWindow.xaml ///  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") }; } 

着色器:

 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; }