Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[API Suggestion] Introduce Dark Mode for Apps targeting .NET 9 and Win 11 #7641

Open
16 of 20 tasks
Tracked by #6270
KlausLoeffelmann opened this issue Aug 23, 2022 · 42 comments · May be fixed by #10985
Open
16 of 20 tasks
Tracked by #6270

[API Suggestion] Introduce Dark Mode for Apps targeting .NET 9 and Win 11 #7641

KlausLoeffelmann opened this issue Aug 23, 2022 · 42 comments · May be fixed by #10985
Assignees
Labels
api-suggestion (1) Early API idea and discussion, it is NOT ready for implementation area-Theming 🚧 work in progress Work that is current in progress
Milestone

Comments

@KlausLoeffelmann
Copy link
Member

KlausLoeffelmann commented Aug 23, 2022

This has a dedicated Feature branch now:
https://github.com/dotnet/winforms/tree/Feature/DarkMode

Rationale

With a few new APIs which the Windows Team now made publicly available, we can start to introduce DarkMode functionality for WinForms. This is one of our most requested customer features. By introducing CsWin32 to our WinForms repo, adapting more and more Windows DarkMode Features overtime to WinForms is also comparatively easy to achieve.

What this feature is and is not

We have no intention to introduce full-blown theming support in WinForms with this.
We want to be very mindful with this topic, since there are a lot of theming standards already out there.
The API is meant as an opt in: You can use it, but if you do not, nothing should break. Existing theming concepts should continue to work as they are.

We feel though, that not only Dark Mode in particular is one of the most requested features, but it can also impose a real accessibility challenge for people - all the more, when users with visual impairments or on the neuro-diversity spectrum need to deal for example with a 80% dark and 20% bright control (like control's content dark, scrollbars light). We know, we cannot address every control, since some of them are not really themeble, but we want to standardize with this what we can, to honor those requirements as best as possible, und make sure a control can be completely dark themed (or not at all).

This PR will not go in the direction of a complete color theming feature.

General approach for applying Dark Mode

For now, you'd just use...

image

Later I guess we should have an additional project setting, so that also the Designer could pick up that color scheme, and then we generate and inject via ApplicationConfiguration.Initialize(). If you pick Inherits, then the System setting is applied wherever possible. (Problems are TabControl - not natively themable at all, and neither are MonthCalendar and therefore DateTimePicker). Inherits here is a "logical ambient" property, means, the idea is, that any control with that setting looks at its parent, a top-level control without a parent would look at Application.DefaultDarkMode and the Application using Inherits would look at the System.

So, for styling individual (custom) controls: If it's more than ForeColor and BackColor (and since I am working with Git Extensions, I know there is quite some coloring going on), the principal approach would be:

  1. Test, if dark mode is in the current context available by using [Contropl.]IsDarkModeEnabled.
  2. Access the Dark Mode/Current palette for the entire application, by using Application.SystemColors.[SystemColorName].
  3. Get the color from there and style the control with it. This way, the color assignment should then work both for dark- and light mode, since that palette reflects the current setting (and we also have then a hook for future extensions).

And, as usual, Igor and I do our usual "Naming and Convention Dance", so, API names might not be cast in stone quite yet.

Current Progress and Problematic Areas

One thing which is already be important to know (and to have in the docs later, should we get this feature in for .NET 9): We will most likely not achieve dark mode for all controls from the get-go (probably even for some of them ever). Problematic controls maybe MonthCalendar, DateTimePicker and definitely TabControl at this point. There are workarounds, I guess, but they are a bit awkward. @adegeo: I want to ping you for this as early as possible, so you're know about this (literal) development from day 1.

DarkModeDemo

  • New API for DarkMode control on Application.
  • New API for DarkMode control on Control.
  • Mapping SystemColors -> Application.SystemColors/patch for DarkMode
  • New API for controlling Form Titelbar Color/BorderColor/TextColor
  • Scrollbars for Form/ScrollableControl/ListView/TreeView/ListBox/ComboBox
  • Radio Button
  • CheckBox
  • ComboBox DarkMode
  • Button DarkMode
  • TreeView DarkMode
  • ListView DarkMode
  • TextBox/RichtextBox
  • Strips - Still have issues, but the basics work fine!
  • Groupbox Caption
  • ColumnHeaders ListView Forground Text
  • ListView Forground Group Caption (might be an issue to get it brighter).
  • DataGridView (Content renders correctly, Headers/Styles need more work)
  • !!! TabControl (Scrollbars are working in DarkMode alright, but theming this thing would be a very improvised construct. If someone has a good idea or approach, have at it!)
  • !!! MonthCalendar (Honestly: We should have a new one altogether - that thing is a visual and A11Y NIGHTMARE.)
  • !!!DateTimePicker - uses MonthCalendar, so go figure.
*************************************************************
Please take the branch, compile and help testing! :-)
*************************************************************

Current list of new APIs

[Subject to change at this point!]

static System.Windows.Forms.Application.DefaultDarkMode.get -> System.Windows.Forms.DarkMode
static System.Windows.Forms.Application.EnvironmentDarkMode.get -> System.Windows.Forms.DarkMode
static System.Windows.Forms.Application.IsDarkModeEnabled.get -> bool
static System.Windows.Forms.Application.SetDefaultDarkMode(System.Windows.Forms.DarkMode darkMode) -> bool
System.Windows.Forms.Control.DarkMode.get -> System.Windows.Forms.DarkMode
System.Windows.Forms.Control.DarkMode.set -> void
System.Windows.Forms.DarkMode
System.Windows.Forms.DarkMode.Disabled = 3 -> System.Windows.Forms.DarkMode
System.Windows.Forms.DarkMode.Enabled = 2 -> System.Windows.Forms.DarkMode
System.Windows.Forms.DarkMode.Inherits = 1 -> System.Windows.Forms.DarkMode
System.Windows.Forms.DarkMode.NotSupported = 0 -> System.Windows.Forms.DarkMode
System.Windows.Forms.Form.SetWindowBorderColor(System.Drawing.Color color) -> void
System.Windows.Forms.Form.SetWindowCaptionColor(System.Drawing.Color color) -> void
System.Windows.Forms.Form.SetWindowCaptionTextColor(System.Drawing.Color color) -> void
System.Windows.Forms.Form.SetWindowCornerPreference(System.Windows.Forms.Form.WindowCornerPreference cornerPreference) -> void
System.Windows.Forms.Form.WindowCornerPreference
System.Windows.Forms.Form.WindowCornerPreference.Default = 0 -> System.Windows.Forms.Form.WindowCornerPreference
System.Windows.Forms.Form.WindowCornerPreference.DoNotRound = 1 -> System.Windows.Forms.Form.WindowCornerPreference
System.Windows.Forms.Form.WindowCornerPreference.Round = 2 -> System.Windows.Forms.Form.WindowCornerPreference
System.Windows.Forms.Form.WindowCornerPreference.RoundSmall = 3 -> System.Windows.Forms.Form.WindowCornerPreference
System.Windows.Forms.ThemedSystemColors
System.Windows.Forms.ThemedSystemColors.ThemedSystemColors() -> void
virtual System.Windows.Forms.Control.DarkModeSupported.get -> bool
virtual System.Windows.Forms.Control.DefaultDarkMode.get -> System.Windows.Forms.DarkMode
virtual System.Windows.Forms.Control.IsDarkModeEnabled.get -> bool
virtual System.Windows.Forms.Control.SetDarkModeCore(System.Windows.Forms.DarkMode darkModeSetting) -> bool
///
/// Why are these important to have publicly? Custom controls need a way
/// to get the _actual_ proposed color for a certain UI Element. SystemColors
/// cannot provide this for dark-mode, since it will never reflect it. So, custom controls 
/// can query the colors via Application.SystemColors.[UiElementName] to get what
/// they need.
///
virtual System.Windows.Forms.ThemedSystemColors.ActiveBorder.get -> System.Drawing.Color
virtual System.Windows.Forms.ThemedSystemColors.ActiveCaption.get -> System.Drawing.Color
virtual System.Windows.Forms.ThemedSystemColors.ActiveCaptionText.get -> System.Drawing.Color
virtual System.Windows.Forms.ThemedSystemColors.AppWorkspace.get -> System.Drawing.Color
virtual System.Windows.Forms.ThemedSystemColors.ButtonFace.get -> System.Drawing.Color
virtual System.Windows.Forms.ThemedSystemColors.ButtonHighlight.get -> System.Drawing.Color
virtual System.Windows.Forms.ThemedSystemColors.ButtonShadow.get -> System.Drawing.Color
virtual System.Windows.Forms.ThemedSystemColors.Control.get -> System.Drawing.Color
virtual System.Windows.Forms.ThemedSystemColors.ControlDark.get -> System.Drawing.Color
virtual System.Windows.Forms.ThemedSystemColors.ControlDarkDark.get -> System.Drawing.Color
virtual System.Windows.Forms.ThemedSystemColors.ControlLight.get -> System.Drawing.Color
virtual System.Windows.Forms.ThemedSystemColors.ControlLightLight.get -> System.Drawing.Color
virtual System.Windows.Forms.ThemedSystemColors.ControlText.get -> System.Drawing.Color
virtual System.Windows.Forms.ThemedSystemColors.Desktop.get -> System.Drawing.Color
virtual System.Windows.Forms.ThemedSystemColors.GradientActiveCaption.get -> System.Drawing.Color
virtual System.Windows.Forms.ThemedSystemColors.GradientInactiveCaption.get -> System.Drawing.Color
virtual System.Windows.Forms.ThemedSystemColors.GrayText.get -> System.Drawing.Color
virtual System.Windows.Forms.ThemedSystemColors.Highlight.get -> System.Drawing.Color
virtual System.Windows.Forms.ThemedSystemColors.HighlightText.get -> System.Drawing.Color
virtual System.Windows.Forms.ThemedSystemColors.HotTrack.get -> System.Drawing.Color
virtual System.Windows.Forms.ThemedSystemColors.InactiveBorder.get -> System.Drawing.Color
virtual System.Windows.Forms.ThemedSystemColors.InactiveCaption.get -> System.Drawing.Color
virtual System.Windows.Forms.ThemedSystemColors.InactiveCaptionText.get -> System.Drawing.Color
virtual System.Windows.Forms.ThemedSystemColors.Info.get -> System.Drawing.Color
virtual System.Windows.Forms.ThemedSystemColors.InfoText.get -> System.Drawing.Color
virtual System.Windows.Forms.ThemedSystemColors.Menu.get -> System.Drawing.Color
virtual System.Windows.Forms.ThemedSystemColors.MenuBar.get -> System.Drawing.Color
virtual System.Windows.Forms.ThemedSystemColors.MenuHighlight.get -> System.Drawing.Color
virtual System.Windows.Forms.ThemedSystemColors.MenuText.get -> System.Drawing.Color
virtual System.Windows.Forms.ThemedSystemColors.ScrollBar.get -> System.Drawing.Color
virtual System.Windows.Forms.ThemedSystemColors.Window.get -> System.Drawing.Color
virtual System.Windows.Forms.ThemedSystemColors.WindowFrame.get -> System.Drawing.Color
virtual System.Windows.Forms.ThemedSystemColors.WindowText.get -> System.Drawing.Color
@KlausLoeffelmann KlausLoeffelmann added the api-suggestion (1) Early API idea and discussion, it is NOT ready for implementation label Aug 23, 2022
@KlausLoeffelmann KlausLoeffelmann added this to the 8.0 Preview1 milestone Aug 23, 2022
@RussKie
Copy link
Member

RussKie commented Aug 23, 2022

I suggest avoiding "dark" in the API names. At some point in time Windows could introduce a new mode - say, blue - and that wouldn't fit into the proposed API.

Historically, the colours were part of the theme definition, now it appears Windows is making a distinction between "colours" and "themes" - the former is the selection of "light" vs "dark", and the latter is now accessibility related:

image
image

I think IsDarkModeEnabled should be a part of Application type - as this setting affects the application as a whole. As per the discussion with the Windows team, the only option for the Win32 app to find out the current configuration is vie the registry:

Computer\HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Themes\Personalize
• SystemUsesLightTheme=0|1
• AppsUseLightTheme=0|1

NB: we still need to confirm this has been officially documented.

@KlausLoeffelmann
Copy link
Member Author

I suggest avoiding "dark" in the API names. At some point in time Windows could introduce a new mode - say, blue - and that wouldn't fit into the proposed API.

I thought about that for a while. I decided to use Dark Mode in the name, because I followed the public Windows API, which the prototype is based on, and which does the same. Another point is that Dark Mode is meanwhile a buzz word, so I'd argue it helps with discoverability. Therefore, I strongly advocate to continue using Dark Mode.

I think IsDarkModeEnabled should be a part of Application type - as this setting affects the application as a whole.

This is what Application.EnvironmentDarkMode does. It returns either Enabled or Disabled ... or ... NotSupported. And this is why a boolean value does not suffice. You want not only to know, if it's on or off, you also want to know, if it's available altogether on that particular machine/platform.

As per the discussion with the Windows team, the only option for the Win32 app to find out the current configuration is ...

Yes. That's how I implemented the prototype already. There is another way which we already know is supported, but that one does use WinRT projected API, and I want to talk with @JeremyKuhne first, if that is an option for us. Also, that way to achieve it seems a bit stilted, but I am still investigating this, so, we'll see what route will be best.

@paul1956
Copy link
Contributor

How is the prototype/feature going to be exposed? Does it depend on specific version of Windows 7/10/11/next...? Do Control vendors custom controls need to support this?

@kirsan31
Copy link
Contributor

kirsan31 commented Aug 24, 2022

Guys I am sorry, but when it comes to themes / modes - #3691 immediately rings in my head (and I can't get away from it) 🙄

@KlausLoeffelmann
Copy link
Member Author

Sadly true. I am only very carefully optimistic that Windows will change anything in that regard. And I know custom NC-Painting is probably not an option. @RussKie, didn't you have something here?

@DualBrain
Copy link

Yep... yep... yep... yep... and yep!

@RussKie
Copy link
Member

RussKie commented Aug 30, 2022

didn't you have something here?

Yes, I tinkered with NC- and C-painting of the form in the VS designer context. I got some partial progress, but that'd require more time (which is a bit scarce). Custom rendering of MDI windows could be a significant challenge.

@kirsan31
Copy link
Contributor

Yes, I tinkered with NC- and C-painting of the form in the VS designer context. I got some partial progress, but that'd require more time (which is a bit scarce). Custom rendering of MDI windows could be a significant challenge.

Is the Windows team so untouchable? 😕

@paul1956
Copy link
Contributor

Are MDI windows used that much that a 99% solution isn't worth releasing as a start?

@KlausLoeffelmann
Copy link
Member Author

KlausLoeffelmann commented Aug 30, 2022

The issue here also is that MDI-Windows aren't really the best idea for user interfaces, and so neither Windows nor we recommend these. We have no plans to really obsolete them alright, but they aren't really a good idea. That said, the rendering of MDI Windows is one thing. But in WinForms, you can also host a Form as a control in another Form. That then isn't technically an MDI window, although the same (rendering) principle applies. Which leads to the outdated look and feel, that cannot be changed easily (so, also the same applies as for MDI windows). Our own Designer is bitten by that: The reason the Designer Form adornments are looking outdated is the reason for that, so there is some internal motivation to change that. But at the same time, you don't really do much with the (NC) window controls of the Form in the Designer in this case. Actually nothing: The adornments of the Form in the Designer are just supposed to look pretty. Nothing else. The window never really moves inside its container, you can only resize it. With MDI windows that's quite different: And I am afraid, that NC painting will just get its own "dynamics" at one point and opens all other sorts of problems in the Real world. That's why I am personally really hesitant to address the Windows-inside-Windows-look-outdated issue with custom NC painting in the runtime and per se.

@DualBrain: Do you have any experiences here in that regard?

@kirsan31
Copy link
Contributor

kirsan31 commented Aug 30, 2022

@KlausLoeffelmann

The issue here also is that MDI-Windows aren't really the best idea for user interfaces, and so neither Windows nor we recommend these. We have no plans to really obsolete them alright, but they aren't really a good idea.

Can I ask - why (except #3691 of course 😁 )? I often hear a similar statement but without any arguments 🤷‍♂️ But I have arguments in defense of MDI:

  1. MDI is the only multi windows layout that WinForms can offer you out of the box.
  2. This is the most stable (error free) noncommercial multi windows layout for WinForms.
  3. So far great if you need to manage multiple windows that are visible at the same time and can be quickly minimized/restored. I mean for such tasks MDI still better fit then V.S. dock layout...
  4. About obsoleting MDI... Pls look at WinForms repo issues sorted by 👍: image
    I think if you say that MDI is outdated and not worth fixing / maintaining, then all this can be safely projected onto the entire WinForms 😥

@DualBrain
Copy link

But in WinForms, you can also host a Form as a control in another Form.

I will confirm that I do (regularly) utilize this technique and can share that it does present some challenges - with that said, sometimes these challenges are less of an issue than attempting alternative methods (code rewrite, inheritance, etc.); a real pros vs. cons situation where accepting the challenges/limitations of embedding a window within a window.

Now with that said, when I do this it is typically done in a way where the embedded window is treated more like a control rather than something that will move about within the confines of the containing window.

@DualBrain
Copy link

I do tend to agree that MDI (in its current form) is a bit dated; however, there many scenarios where this approach is still very valid. While I don't personally design projects around this model, I do stumble across projects every once and a while that do; as such, I don't see MDI going away any time soon - at least not without a very solid/clear replacement available.

In order to handle "dark mode", what I've currently been doing is pretty much working within the very limited feature set that can do it and trying to design my applications to work within these limitations.

Honestly, I really didn't even realize how limited this really was until I attempted to get @paul1956's project switched over... meaning trying to apply dark mode to an already existing project changing the overall design/layout/interface really isn't that much of an option.

Some components are simply "too difficult" to repaint without effectively replacing them because they don't expose any functionality to affect any sort of color changes (comboboxes) while others are what I would refer to as being 90-95% there, but that last little percent is very visibly annoying (toolbar/statusbar). Menus are actually pretty good.

With all that said, the first thing that is needed is exactly what the original topic of this issue raises... need some way to identify that Windows a) supports dark mode and b) is in dark mode. Sure, you can just have a mechanism in place to allow the end-user to select / switch between; but from my point of view I would like to default my application to what the user has already specified within the system.

And, assuming that is possible, have the ability to tell my application that it is in dark mode or not affecting (automagically) standard components accordingly. This does need to be something that I, as the developer, can manually toggle in a tri-state manner - auto (system setting), enabled (dark mode active), disabled (dark mode inactive).

As to whether or not MDI handles this or if MDI delays this getting done... my opinion is that this feature should be something that could be made available incrementally; meaning it needs to be totally "opt-in" allow for use to take advantage of these pieces if we are willing/able. To say this another way, I don't think dark mode capability should be an all or nothing feature... identify the main sore spots and address those incrementally. Default to application.darkmode = disabled allowing for enabled/auto.

I recognize that I'm making this sound easier than it really is; but I really don't favor the approach of waiting 3 years to get a better combobox, status bar, etc. (meaning the more common of the common controls).

As for the menu... please, please, please feel free to "borrow" from my efforts and use as you see fit. Again, I'd love to just be able to set a single property and "it just work".

@KlausLoeffelmann
Copy link
Member Author

@kirsan31, @DualBrain: When it comes to MDI Windows, WinForms just follows the Windows/Office guidelines. It doesn't have to do with my/general personal preference, it's just a very functional reason: When multi-monitor display scenarios became common even in conservative work environments like Banks, Insurance Companies, Government Departments (all typical WinForms target audiences), MDI user interface just became totally unpractical: You simply can't drag a document to a secondary monitor, when you have a constraining MDI parent on the primary monitor. And with that (I say that from a very strong personal experience as a consultant in the area of migrating/modernizing Win32, VB6 and older WinForms/WPF apps in a previous life) End Users started to demand other UI paradigms.

@KlausLoeffelmann
Copy link
Member Author

Still, I recognize that we need to support existing apps with that - so, no, no one said anything about obsoleting it. All that I am saying is, that it'll be very likely that we (WinForms) won't invest in a scenario, that a) doesn't make sense in modern work environments, and b) that isn't very likely supported (in terms of modernizing) by Windows. Should they decide to introduce theming, then we would very likely pick that up and enable it. But I don't think it would make sense for us (WinForms) to start messing with a NC-Custom-rendering approach.

@DualBrain
Copy link

@KlausLoeffelmann Sorry if it didn't come across properly; but I was trying to clarify that MDI is what it is, pretty much isn't (or rather shouldn't be) going anywhere and although not generally recommended, there are scenarios where it is being used and/or may be useful. As I said, I don't particularly utilize it as I would much rather have docking, tabbed, tear-away model than MDI. ;-)

Additionally, I definitely don't want MDI doing one thing or another preventing/delaying the moving forward with dark mode.

@kirsan31
Copy link
Contributor

kirsan31 commented Aug 31, 2022

I think I've been misunderstood here. I didn't offer to slow down this work because of the MDI. I just wanted to remind that we have an unfixed bug on this topic for a very long time, and it's time to kick the Windows team harder...

@KlausLoeffelmann for not to flood, I answered in the relevant topic.

@Balkoth
Copy link
Contributor

Balkoth commented Sep 8, 2022

Dark mode is easily my most wanted feature for winforms. Second would be a working PMv2 mode...

@driver1998
Copy link

Is the dark common control theme documented now? Last time I checked it is still undocumented. Only the dark title bar attribute is documented and public.

@JeremyKuhne JeremyKuhne added this to the .NET 9.0 milestone Aug 16, 2023
@jonesy-b-dev
Copy link

Any more info if this will be implemented?

@Laim
Copy link

Laim commented Nov 15, 2023 via email

@jonesy-b-dev
Copy link

Thats still really long, thought this was really high requested.

@Laim
Copy link

Laim commented Nov 15, 2023

Thats still really long, thought this was really high requested.

Projected release date for .NET 9 is November 2024, so yeah - I don't have much hope to be honest.

@driver1998
Copy link

driver1998 commented Dec 19, 2023

To do this properly, WinForms would need to have access to public Windows APIs to enable dark mode on Win32 Common Controls. There are some (see microsoft/WindowsAppSDK#41), but these are internal use for the File Explorer dark mode effort only. I don't think WinForms would want to rely on undocumented APIs.

Also, there exists other APIs in uxtheme.dll which might be of interest for people transitioning to WinUI and/or XAML islands:

SetPreferredAppMode:
This allows apps to enable dark theme support for Win32 controls. This is notably used by Windows Explorer for its dark theme.
AllowDarkModeForWindow:
Once the app mode is set to AllowDark using the API above, it is a per-window opt-in.
Once this method is called, the Win32 controls in the window uses dark theme if the system dark theme is enabled, and automatically switches to light theme when the user changes their settings.
Note that some controls might need to have their theme manually set to DarkMode_Explorer for this to be effective
Dark mode ribbon can be opt-in with the window property UI_PKEY_DarkModeRibbon

WinForms supporting dark mode should be a major push of this effort to go public, since native Win32 controls is at the very core of WinForms since day 1.

@paul1956
Copy link
Contributor

@driver1998 File Explorer is not going to lose Dark Mode and WinForms will expose it own public API to switch so why is it an issue to use undocumented API's that are being used elsewhere in critical functionality. In the unlikely event that the API changes WinForms can respond while in parallel work with Windows team to make API public.

@AraHaan
Copy link
Member

AraHaan commented Dec 28, 2023

Instead of relying on dark mode API's why not use SVG images that can provide the actual looks of all of the controls, then have the application developers register theme color xml files that can then be selected for use to recolor said SVG files. Also with SVG being the easiest to manipulate and render it should be a minimal change on that then without the need for any dark mode API's. Also another + is the developer could then define their own colors they want used for their application as well and it would make it look professional as well with no added complexity or work for them which would make it worth it to them. Also plus is the theme would apply globally to every form and control automatically as well.

@MagicAndre1981
Copy link

Also another + is the developer could then define their own colors they want used for their application as well

I need to do this color defining in xmls for Xamarin.Forms and hate it. I don't want to do this for Winforms, too. I would like to have something like in UWP with RequestedTheme Property which as an enum of Dark, Default, Light to request how the control are rendered.

@AraHaan
Copy link
Member

AraHaan commented Dec 31, 2023

Also another + is the developer could then define their own colors they want used for their application as well

I need to do this color defining in xmls for Xamarin.Forms and hate it. I don't want to do this for Winforms, too. I would like to have something like in UWP with RequestedTheme Property which as an enum of Dark, Default, Light to request how the control are rendered.

The color defines in that case would be for text that would be rendered on the svg images 😄. I have a good function that basically does in memory edits to svg contents before converting them in memory to a System.Drawing.Bitmap that then gets rendered on an image control to basically look and feel like a normal button 😄.

@KlausLoeffelmann KlausLoeffelmann pinned this issue Mar 6, 2024
@KlausLoeffelmann KlausLoeffelmann linked a pull request Mar 6, 2024 that will close this issue
@dotnet-policy-service dotnet-policy-service bot added the 🚧 work in progress Work that is current in progress label Mar 6, 2024
@KlausLoeffelmann KlausLoeffelmann changed the title [WIP][API Suggestion] Introduce Win11 Dark Mode to Forms and default application settings [API Suggestion] Introduce Dark Mode for Apps targeting .NET 9 and Win 11 Mar 6, 2024
@KlausLoeffelmann
Copy link
Member Author

Just as a general disclaimer:

We have no intention to introduce full-blown theming support in WinForms with this.
We want to be very mindful with this topic, since there are a lot of theming standards already out there.
The API is meant as an opt in: You can use it, but if you do not, nothing should break. Existing theming concepts should continue to work as they are.

We feel though, that not only Dark Mode in particular is one of the most requested features, but it can also impose a real accessibility challenge for people - all the more, when users with visual impairments or on the neuro-diversity spectrum need to deal for example with a 80% dark and 20% bright control (like control's content dark, scrollbars light). We know, we cannot address every control, since some of them are not really themeble, but we want to standardize with this what we can, to honor those requirements as best as possible, und make sure a control can be completely dark themed (or not at all).

This PR will not go in the direction of a complete color theming feature.

@paul1956
Copy link
Contributor

paul1956 commented Mar 7, 2024

First @KlausLoeffelmann thanks for tackling this. A few questions

  1. a medical (display info only) app I am working on uses a lot of dark themed graphics with hard coded colors. Will there be a way for it to get the current color palette?
  2. Will there be an application wide notification if theme changes while app is running so I can update custom control and graph colors?
  3. Will it support high visibility themes as a lot of users of the app have vision contrast issues.
  4. What is best way to try it on an existing app and when?

@AraHaan
Copy link
Member

AraHaan commented Mar 10, 2024

Just as a general disclaimer:

We have no intention to introduce full-blown theming support in WinForms with this. We want to be very mindful with this topic, since there are a lot of theming standards already out there. The API is meant as an opt in: You can use it, but if you do not, nothing should break. Existing theming concepts should continue to work as they are.

We feel though, that not only Dark Mode in particular is one of the most requested features, but it can also impose a real accessibility challenge for people - all the more, when users with visual impairments or on the neuro-diversity spectrum need to deal for example with a 80% dark and 20% bright control (like control's content dark, scrollbars light). We know, we cannot address every control, since some of them are not really themeble, but we want to standardize with this what we can, to honor those requirements as best as possible, und make sure a control can be completely dark themed (or not at all).

This PR will not go in the direction of a complete color theming feature.

And then there are some people with eyes extremely sensitive to light based colors but can see clearly with white text on black backgrounds, which for some software is a must to be able to support a "dark mode" for when the user ticks it on in their software.

@AraHaan
Copy link
Member

AraHaan commented Mar 10, 2024

First @KlausLoeffelmann thanks for tackling this. A few questions

1. a medical (display info only) app I am working on uses a lot of dark themed graphics with hard coded colors. Will there be a way for it to get the current color palette?

2. Will there be an application wide notification if theme changes while app is running so I can update custom control and graph colors?

3. Will it support high visibility themes as a lot of users of the app have vision contrast issues.

4. What is best way to try it on an existing app and when?

Agreed, not to mention people might have issues like for example red + green color blindness but otherwise can see things normally other than when that happens.

@KlausLoeffelmann
Copy link
Member Author

Hey guys, thanks for the questions - which are really good!

  1. The problem is that when Windows switches into dark mode, it does NOT change the SystemColor palette. So, as a workaround, the current concept is to introduce a read-only SystemColors collection on Application, that is reflecting what SystemColors reflect EXCEPT if we (WinForms) can detect dark mode. In that case, we provide a palette that makes sense for the theming which is provided through the common controls, but also what folks are used to in terms of WPF styling (like in VS) or other Windows elements, which Windows themes itself.

  2. Probably not. And the reason is, the effort is currently not worth the prioritization. In LOB apps, there isn't classically a continuing switching between DarkMode and LightMode. So, while this feature isn't at all out of the question, I'd say it not having it now shouldn't be a showstopper for the time being.

  3. Nothing changes in terms of HighContrast modes. If a HighContrast mode is detected, DarkMode is off the table. You cannot force it in. It would be an accessibility deal breaker, even if the HighContrast mode looks like a dark mode.

  4. After the summit is over, I'll prepare a branch when we're more confident about the API naming. Then, you can get it, build it, and mess with it. But, I need to "lick my wounds" (German saying) for a couple of days after the Summit! ;-)

And please - keep your ideas and concerns coming!!

@KlausLoeffelmann
Copy link
Member Author

KlausLoeffelmann commented Mar 12, 2024

(Oh, and @paul1956: I know I still need to take care of a few VB issues, but I have been so swamped with work on Designer issues, feature dev and preparing demos, and I think this (DarkMode) is more important right now than the debt we still have in the VB code base. That said, we need to make sure, that we integrate the DarkMode controlling in the VB App Framework "VB-style"! So, by any means kick-ping me, when the time comes, should I forget!)

@paul1956
Copy link
Contributor

paul1956 commented Mar 13, 2024 via email

@KlausLoeffelmann
Copy link
Member Author

Agreed, not to mention people might have issues like for example red + green color blindness but otherwise can see things normally other than when that happens.

I am red-green blind, btw. So, my vision (ha!) of dark mode should actually take that into account! 😄

@greatawesome
Copy link

Will this get released even if the TabControl and DateTimePicker aren't completed?

Since those may be the least theme-able common controls in WinForms, there are quite a few custom drawn drop in replacements available. If I could get a native dark mode for everything but those two controls, I'd be pretty happy.

@RussKie
Copy link
Member

RussKie commented Apr 11, 2024

TabControl is widely and heavily used.

@xPaw
Copy link
Contributor

xPaw commented Apr 17, 2024

Even if things like TabControl end up not supporting dark mode initially (I say this as a TabControl user), I would still like to see dark mode to be merged for NET9 release to get the ball rolling. This issue has changed milestones multiple times.

Is there a way for us to test #10985 on our projects to test for any possible issues before the release?

@weltkante
Copy link
Contributor

weltkante commented Apr 17, 2024

Is there a way for us to test #10985 on our projects to test for any possible issues before the release?

Can grab daily builds of the SDK for painless testing of new features before a preview is published, or (if its not yet merged) clone the repo and build it yourself.

@AraHaan
Copy link
Member

AraHaan commented Apr 28, 2024

I responded inside of the Pull Request with a few things that I think needs changed.

Please migrate from Application.SystemColors in this change to prefer application registered and provided ProfessionalColorTable subclasses. I also have existing code that provides dark version colors of the items inside of that as well.

Also it would allow for me to have very minimal changes to my code to allow using it globally as well as remove any code that needed to be provided to manually dark theme my program (most of it copied from ShareX btw).

https://github.com/Elskom/Els_kom_new/blob/main/Els_kom/Themes/DarkColorTable.cs https://github.com/Elskom/Els_kom_new/blob/main/Els_kom/Themes/Theme.cs

Basically applications can then do this and register it using Application.SetColorTable(ProfessionalColorTable) and then winforms would use that color table globally from then on until the user tells it to change color tables which would cause a repaint on everything according to the new color table. Also would need a new public method of Application.GetColorTable (or expose it as a property) and it would do the same thing if not BETTER than the SystemColors option. Besides they get used for special coloring on ContextMenuStrips, etc anyways so why not extend it to work with all of Windows Forms for free (along with non-client area painting).

Specifically this.

I am starting to think that with dark theme support, it might be better to have it mature a bit more and have it be slated for .NET 10, also with more of that time being invested would mean a much deeper integrated dark theme support and with it perhaps support for all controls + the default scrollbars in the ScrollableControls all based on the user's provided ProfessionalColorTable that gets registered into the Application class in WinForms.

And this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
api-suggestion (1) Early API idea and discussion, it is NOT ready for implementation area-Theming 🚧 work in progress Work that is current in progress
Projects
None yet
Development

Successfully merging a pull request may close this issue.