Is there a programming way to access the system theme (i.e., theme for Windows)?
The similar question #UWP get system theme (Light/Dark) is answered here:
var DefaultTheme = new Windows.UI.ViewManagement.UISettings();
var uiTheme = DefaultTheme.GetColorValue(Windows.UI.ViewManagement.UIColorType.Background).ToString();
But as tipa comments, the accepted answer suggests a way to access the theme for applications, not the theme for Windows.
Therefore, I wonder if there are other ways to access the system theme.
Try this:
[DllImport("UXTheme.dll", SetLastError = true, EntryPoint = "#138")]
public static extern bool ShouldSystemUseDarkMode();
If the system uses dark mode, it will return true.
That's not the theme for applications.
Here is a method I have used previously in WPF applications to determine if Windows is in High Contrast or Dark theme.
It hasn't been updated for a while so it maybe out of date, but might be a starting point? You can easily adapt it to return an enum or bool for just light/dark if required.
private static string GetWindowsTheme()
{
string RegistryKeyPath = #"Software\Microsoft\Windows\CurrentVersion\Themes\Personalize";
string RegistryValueName = "AppsUseLightTheme";
if (SystemParameters.HighContrast)
return "High Contrast";
using (RegistryKey key = Registry.CurrentUser.OpenSubKey(RegistryKeyPath))
{
object registryValueObject = key?.GetValue(RegistryValueName);
if (registryValueObject == null)
return "Default";
int registryValue = (int)registryValueObject;
return registryValue > 0 ? "Default" : "Dark Theme";
}
}
In WinUI 3, the enum ApplicationTheme is defined in the Microsoft.UI.Xaml namespace.
public enum ApplicationTheme
{
//
// Summary:
// Use the **Light** default theme.
Light,
//
// Summary:
// Use the **Dark** default theme.
Dark
}
You can get the theme like this.
public App()
{
this.InitializeComponent();
ApplicationTheme theme = RequestedTheme;
}
Related
I am having some difficulty in loading a font from a resource into PrivateFontCollection.
When I started this, I was successful in loading the font from a file, however I wish to embed the font into my project (so there is less file mess on the user side, and a bit less IO while the application is running).
The following code will load the font, gets the proper name, and allows for scaling however none of the characters are showing up properly.
static class Foo {
public static string FontAwesomeTTF { get; set; }
public static Font FontAwesome { get; set; }
public static float Size { get; set; }
public static FontStyle Style { get; set; }
private static PrivateFontCollection pfc { get; set; }
static Foo() {
// This was set when loading from a file.
// FontAwesomeTTF = "fontawesome-webfont.ttf";
Style = FontStyle.Regular;
Size = 20;
if ( pfc==null ) {
pfc=new PrivateFontCollection();
if ( FontAwesomeTTF==null ) {
var fontBytes=Properties.Resources.fontawesome_webfont;
var fontData=Marshal.AllocCoTaskMem( fontBytes.Length );
Marshal.Copy( fontBytes, 0, fontData, fontBytes.Length );
pfc.AddMemoryFont( fontData, fontBytes.Length );
Marshal.FreeCoTaskMem( fontData );
} else {
pfc.AddFontFile( FontAwesomeTTF );
}
}
FontAwesome = new Font(pfc.Families[0], Size, Style);
}
private static string UnicodeToChar( string hex ) {
int code=int.Parse( hex, System.Globalization.NumberStyles.HexNumber );
string unicodeString=char.ConvertFromUtf32( code );
return unicodeString;
}
public static string glass { get { return UnicodeToChar("f000"); } }
}
Example usage :
label1.Font = Foo.FontAwesome;
label1.Text = Foo.glass;
This is what it looks like loading from memory:
This is what it look like loading from file:
I am using the current FontAwesome TTF file in both the embedded resource and the file based tests. It seems that when embedded something is being lost or scrambled in the translation or when loading from embedded. I need help making this work so I can load the font from an embedded resource into PrivateFontCollection.
There are a few 'solutions' I looked at on SO however they are quite dated and some or all of the commands/accessors are no longer available in Visual Studio 2013 (article solution was from 4-5 years ago). Some example 'solutions' and why they don't work:
Solution #1 - This doesn't work as the accessor string for the font returns null. In my case, the accessor is MyProject.Properties.Resources.fontawesome_webfont
Solution #2 - This solution came the closest, but again the method used to access the resource no longer works. My code above implements a harvested version of this taking out the core concept of passing the byte[] array into memory and then loading from memory. Since the get{} property of the resource in my case returns a byte[] array already, there was no need to 'convert' it into a byte array and thus I was (seemingly) safely able to remove that portion of the code by updating it to use the newer accessor.
In either case, I would like a solution for this problem that allows me to load the font file from the embedded resources into PrivateFontCollection.
AddMemoryFont's remarks section says:
To use the memory font, text on a control must be rendered with GDI+. Use the SetCompatibleTextRenderingDefault method, passing true, to set GDI+ rendering on the application, or on individual controls by setting the control's UseCompatibleTextRendering property to true. Some controls cannot be rendered with GDI+.
I reproduced your issue locally and tried it out by changing your usage sample to:
label1.Font = Foo.FontAwesome;
label1.Text = Foo.glass;
label1.UseCompatibleTextRendering = true;
This turns on GDI+ rendering for that label, allowing the font added with AddMemoryFont to render correctly.
Microsoft's own site does not explain in details how to use this interface. They claim that this is the way to get notified if the Fonts & Colors change in Visual Studio.
I tried what seemed to be an obvious choice and implemented the interface on my package, but there were no attributes mentioned I should set on my VSPackage. Unfortunately that doesn't seem to be enough.
Here's a sample of what I did:
public class SceVSIPackage : Package, IVsFontAndColorEvents
{
public int OnApply()
{
return VSConstants.S_OK;
}
public int OnFontChanged(ref Guid rguidCategory, FontInfo[] pInfo, LOGFONTW[] pLOGFONT, uint HFONT)
{
return VSConstants.S_OK;
}
public int OnItemChanged(ref Guid rguidCategory, string szItem, int iItem, ColorableItemInfo[] pInfo, uint crLiteralForeground, uint crLiteralBackground)
{
return VSConstants.S_OK;
}
public int OnReset(ref Guid rguidCategory)
{
return VSConstants.S_OK;
}
public int OnResetToBaseCategory(ref Guid rguidCategory)
{
return VSConstants.S_OK;
}
}
Unfortunately none of the IVsFontAndColorEvent members (all the methods above) get called.
Do I miss something else? Like an attribute? Or proffering the service?
I also tried serviceContainer.AddService(typeof(IVsFontAndColorEvent), this, true); but it didn't help either.
Workaround
Unfortunately I couldn't make IVsFontAndColorEvents working. However, I could achieve the same (getting notified when the Fonts change in Tools\Options\Fonts and Colors\Text Editor) with the code found here.
The idea is to use TextManagerEvents instead of IVsFontAndColorEvents:
//using Microsoft.VisualStudio.TextManager.Interop;
IVsTextManager textManager = GetService(typeof(SVsTextManager)) as IVsTextManager;
if (textManager != null)
{
IConnectionPointContainer container = textManager as IConnectionPointContainer;
if (container != null)
{
IConnectionPoint textManagerEventsConnection;
Guid eventGuid = typeof(IVsTextManagerEvents).GUID;
container.FindConnectionPoint(ref eventGuid, out textManagerEventsConnection);
if (textManagerEventsConnection != null)
{
TextManagerEvents textManagerEvents = new TextManagerEvents();
uint textManagerCookie;
textManagerEventsConnection.Advise(textManagerEvents, out textManagerCookie);
if (textManagerCookie != 0)
{
textManagerEvents.FontColorPreferencesChanged += OnFontColorPreferencesChanged;
}
}
}
}
Notes
1. OnFontColorPreferencesChanged
Just in case you are also interested in how to extract the font and color information, here is how I did it:
private FontInfo prevFontInfo; // Store previous FontInfo to prevent execution of the event handler multiple times.
private void OnFontColorPreferencesChanged(object sender, EventArgs e)
{
IVsFontAndColorStorage fontAndColorStorage = GetService(typeof(SVsFontAndColorStorage)) as IVsFontAndColorStorage;
if (fontAndColorStorage != null)
{
// GlobalValues.FontsAndColors_TextEditor is found in the registry: HKEY_USERS\.DEFAULT\Software\Microsoft\VisualStudio\[VS_VER]_Config\FontAndColors\Text Editor, where VS_VER is the actual Visual Studio version: 10.0, 11.0, 12.0, 14.0, etc.
if (fontAndColorStorage.OpenCategory(GlobalValues.FontsAndColors_TextEditor, (uint)__FCSTORAGEFLAGS.FCSF_LOADDEFAULTS) == VSConstants.S_OK)
{
LOGFONTW[] logFontw = new LOGFONTW[1]; // Only 1 item expected
FontInfo[] fontInfo = new FontInfo[1]; // Only 1 item expected
if (fontAndColorStorage.GetFont(logFontw, fontInfo) == VSConstants.S_OK &&
!prevFontInfo.Equals(fontInfo[0]))
{
prevFontInfo = fontInfo[0];
// FontInfo uses pixels as units, WPF uses points. Conversion between the two is required.
double fontSize = (double)new FontSizeConverter().ConvertFrom(string.Format("{0}pt", fontInfo.wPointSize));
FontFamily fontFamily = new FontFamily(fontInfo.bstrFaceName);
// There you go, you have the FontFamily and size ready to use.
}
fontAndColorStorage.CloseCategory();
}
}
}
2. Limitations
Although this solutions is a usable workaround for me, it has some problems:
when changing the font of the Text Editor, the OnFontColorPreferencesChanged event is raised multiple times. I can't tell if IVsFontAndColorEvents would raise the event only once or had the same problem (as I never got it working.) I solved this issue by introducing prevFontInfo and don't invoke my logic unless this value is different from fontInfo[0], the values I just read.
the event fires only when the Text Editor fonts and colors are changed, but not when any of the rest (e.g. Environment Font or Output Window)
the event does not fire when the bold option is changed. Nevertheless, the font weight is not seemed to be used by the IDE anyway...
the event does not fire when "Use Defaults" is selected in Options/Fonts and Colors. As a matter of fact it doesn't fire either when it's reset to the default values by manually entering them (e.g.: font size to 10)
I hope some of these might be useful for someone stumbling upon this question.
I need to call acadcolor component from visual studio.when i add the component it's fine.
After I need to use that component so just I drag and drop that control to windows form visual studio automatically closed without passed any message.
Can anybody know how to add and how to work with acadcolor component from visual studio?
Thanks advance.
Here's an ADN article on just what Alex Filipovici was mentioning:
Use 64-bit ActiveX Component from a .NET Assembly
There are other alternatives too. Here's an ADN article replicating the control with WPF: WPF Implementation To Mimic Color Layer Controls.
You can also open the color dialog if it's to select a color. That's what I've done most recently:
using acColor = Autodesk.AutoCAD.Colors;
using acWindows = Autodesk.AutoCAD.Windows;
//...
public acColor.Color GetAutoCADColor()
{
acWindows.ColorDialog colorDialog = new acWindows.ColorDialog();
DialogResult dialogResult = new DialogResult();
dialogResult = colorDialog.ShowDialog();
switch (dialogResult)
{
case DialogResult.OK:
return colorDialog.Color;
case DialogResult.Cancel:
return Color.Empty.ConvertToAutoCADColor();
default:
return Color.Empty.ConvertToAutoCADColor();
}
}
Extension methods:
internal static class ColorExtensions
{
internal static Color ConvertToWindowsColor(this acColor.Color acColor)
{
return Color.FromArgb(acColor.ColorValue.ToArgb());
}
internal static acColor.Color ConvertToAutoCADColor(this Color winColor)
{
return acColor.Color.FromRgb(winColor.R, winColor.G, winColor.B);
}
}
Just a thought or two.
I've made a pretty slick Windows 8-ish interface using WPF. It already turns out way better than I could wish for, but I was wondering the following:
Is it somehow possible to retrieve the current window colour set by the user? You know, you can set the Aero colour when you right-click the desktop... My plan is to use that colour for a couple of canvas elements on my GUI.
Thanks in advance!
The SystemColours class exists for this very purpose. You can bind directly to it like so
"{DynamicResource {x:Static SystemColors.WindowColorKey}}"
You can query the ColorizationColor registry key for this.
I've even went a step further and created a method to get the hexadecimal colour value, hope this helps you:
public void SomeMethod()
{
int argbColor = (int)Microsoft.Win32.Registry.GetValue(#"HKEY_CURRENT_USER\Software\Microsoft\Windows\DWM","ColorizationColor", null);
var color = System.Drawing.Color.FromArgb(argbColor);
string hexadecimalColor = ConverterToHex(color);
}
private static String ConverterToHex(System.Drawing.Color c)
{
return String.Format("#{0}{1}{2}", c.R.ToString("X2"), c.G.ToString("X2"), c.B.ToString("X2"));
}
I managed to get the correct colour using the following code:
Little sidenote: It has a small correction in it to ignore the alpha bit of the hex number, so I get the full color rather than the less saturated one.
string colorizationValue = string.Format("{0:x}", Microsoft.Win32.Registry.GetValue(#"HKEY_CURRENT_USER\Software\Microsoft\Windows\DWM", "ColorizationColor", "00000000"));
StringBuilder bl = new StringBuilder(colorizationValue);
bl[0] = 'd';
bl[1] = '9';
colorizationValue = bl.ToString();
BrushConverter bc = new BrushConverter();
Brush brush = (Brush)bc.ConvertFrom("#" + colorizationValue);
cvs_barColor.Background = brush;
I created an open-source library for this here which is also available on NuGet.
install-package aerocolor-wpf.AeroColor
After installing the package, you can refer to a DynamicResource called AeroColor and AeroBrush depending on what you need.
There's some setup code that's needed too, but it isn't much. Just put something in your Loaded event handler of the window, as seen below.
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
Loaded += MainWindow_Loaded;
}
void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
AeroResourceInitializer.Initialize();
}
}
The neat thing about this library is that it installs a hook as well, which updates those resources as the actual Aero color changes in the system too. This means you don't have to handle that either, and if you use a DynamicResource to point to the color in your XAML instead of a StaticResource, WPF will automatically update the color in your UI as well.
Looks very cool when Windows 8 changes the Aero color transitionally and your color follows.
I've been trying to use the guide available at http://geekswithblogs.net/mikebmcl/archive/2010/09/16/using-wp7-themes-in-your-xna-game.aspx but I cannot find the Application name, nor do I seem to be able to find a replacement for SolidColorBrush.
Unfortunately there is no library or easy to use code on the net to programmitcally get the tile colour in XNA on windows phone, even though its simple with Silverlight.
Any ideas how to go about this?
You can get the theme (dark/light) on the phone in a shorter way (works for XNA too):
Visibility darkBackgroundVisibility = (Visibility)Application.Current.Resources["PhoneDarkThemeVisibility"];
if(darkBackgroundVisibility == Visibility.Visible)
//Theme is Dark
else
//Theme is Light
To get the AccentColor, you need a but more code (I got it from this article on MSDN: How to: Apply Theme Resources for Windows Phone). I shortened the code from the switch-statement for readability and put it in a method. I also tested this in an XNA app and this works fine! :)
var currentAccentColorHex = (System.Windows.Media.Color)Application.Current.Resources["PhoneAccentColor"];
string currentAccentColor = ColorNameFromHex(currentAccentColorHex);
private string ColorNameFromHex(System.Windows.Media.Color hexColor)
{
switch(hexColor.ToString())
{
case "#FF1BA1E2": return "Blue";
case "#FFA05000": return "Brown";
case "#FF339933": return "Green";
case "#FFE671B8": return "Pink";
case "#FFA200FF": return "Purple";
case "#FFE51400": return "Red";
case "#FF00ABA9": return "Teal";
case "#FF8CBF26":
case "#FFA2C139": return "Lime";
case "#FFFF0097":
case "#FFD80073": return "Magenta";
case "#FFF09609": return "Mango";
default: return "custom eleventh color"; //Manufacturer color
}
}
Instead of returning a string containin 'Red' you could return a 'real' Color. For that you'll have to change return type of the method and the value.
Hope this helps!
You can get the current theme from the Resources for example getting the background color like this. In an App you could check this in the Application_Launching as well as Application_Activated to see if the theme changed while the App was in the background.
I'm pretty sure you can do a similar thing in an XNA game:
public enum PhoneTheme
{
Light,
Dark
};
public static PhoneTheme CurrentTheme { get; private set; }
Following in your activated/startup code:
string theme = Resources["PhoneBackgroundColor"].ToString();
CurrentTheme = theme == "#FF000000"
? PhoneTheme.Dark
: PhoneTheme.Light;