Answered Use my Renderer and select one of the ProfessionalColorTables color sets

aaaron

Well-known member
Joined
Jan 23, 2011
Messages
216
Programming Experience
10+
Is it possible to use my Renderer which inherits ToolStripProfessionalRenderer, passing a ProfessionalColorTable, and I select the KnownColors in the ProfessionalColorTable setto be used (for example, InitOliveLunaColors)
 
I don't think so. ProfessionalColorTable uses shared properties of ProfessionalColors class, which depends on system color scheme setting, and since it is shared it is probably used by the "whole framework".
Each time a color property is read it goes through its method FromKnownColor, which first verifies ProfessionalColors shared scheme and possibly reset the table, then goes to its ColorTable property that looks up system settings (from VisualStyleInformation.ColorScheme) and reinitialize the table.
ProfessionalColorTable is intended to inherit from and override the color properties to return your own values, from my quick browse though the source code it doesn't seem possible to hack its default behaviour the way you're thinking of.
 
I had a play with this and came up with a perhaps peculiar solution :rolleyes: What I did was to get the source code for ProfessionalColorTable with .Net Reflector (ILSpy could also be used) and use some regex to extract the overridable properties, those that return the color to use, and output these to a xml file. There are 56 such properties that almost all look like this:
source extract:
Public Overridable ReadOnly Property ButtonCheckedGradientEnd As Color
    Get
        Return Me.FromKnownColor(KnownColors.msocbvcrCBGradSelectedEnd)
    End Get
End Property
I extracted the property name and the return statement. Then I used a T4 (design time) template to generate a partial class with overrides for each of these properties. The code without the directives is short:
T4 template:
Partial Public Class CustomProfessionalColorTable
<#
    Dim doc As XDocument = XDocument.Load(Host.ResolvePath("bin/Debug/properties.xml"))
    For Each prop As XElement In doc...<Property>
#>
    Public Overrides ReadOnly Property <#= prop.<Name>.Value #> As Color
        Get
            <#= prop.<Return>.Value #>
        End Get
    End Property          
<#
    Next
#>
End Class
The output goes like this:
T4 output:
Partial Public Class CustomProfessionalColorTable

    Public Overrides ReadOnly Property ButtonCheckedGradientBegin As Color
        Get
            Return Me.FromKnownColor(KnownColors.msocbvcrCBGradSelectedBegin)
        End Get
    End Property
Then I wrote another partial class that inherits ProfessionalColorTable and adds the FromKnownColor method:
custom inherited class:
Partial Public Class CustomProfessionalColorTable
    Inherits ProfessionalColorTable

    Private ColorTable As New Dictionary(Of KnownColors, Color)

    Private Function FromKnownColor(color As KnownColor) As Color
        Return ColorTable.Item(color)
    End Function

    Public Sub InitThemeColors(theme As ColorTheme)

    End Sub
End Class
InitThemeColors basically contains the reflection code I posted in your other thread Question - How to extract colors from ProfessionalColorTable
It is required that this class knows the KnownColors enum, so I copied that plain from ProfessionalColorTable class where it is declared Friend (only accessible within that assembly). So "my" definition and that definition contains the same values, but are different types. After the reflection code that initialize a dictionary with the color table I copy it "locally" to this class:
transfer to local ColorTable:
For Each key In dict.Keys
    ColorTable(CInt(key)) = dict(key)
Next
I also defined an enum ColorTheme that is used to select the theme, and by reflection code to call the friend methods, for example InitOliveLunaColors.
theme selection:
Public Enum ColorTheme
    BlueLuna
    OliveLuna
    SilverLuna
    Themed
End Enum
Now an instance of CustomProfessionalColorTable can be created and initialized with the different color themes, and use with ToolStripProfessionalRenderer.
Finally I added a toolstrip to the form and tested the class:
test code:
Dim customtable As New CustomProfessionalColorTable
customtable.InitThemeColors(ColorTheme.OliveLuna)
Me.ToolStrip1.Renderer = New ToolStripProfessionalRenderer(customtable)
It looks nice and Olive:
1582934029170.png
(y)

That was fun! :cool: I attached the mockup project here. It is not necessary with the T4 template to use this in another project, since the generated properties will not change, you only need both partial class files CustomProfessionalColorTable.vb and ProfessionalColorTableProperties.vb. Maybe you want to merge them, or set up otherwise, but I think this serves the purpose of the example.
ProfessionalColorTable source code and regex extraction code is also included in attachment by the way.
 

Attachments

  • ProfTableMockup.zip
    31.6 KB · Views: 14
For .Net 7 where the Luna methods are changed to Shared you can for example do:
VB.NET:
Dim bflags = If(theme = ColorTheme.Themed, BindingFlags.Instance, BindingFlags.Static) Or BindingFlags.NonPublic
Dim mInfo = table.GetType.GetMethod(methodname, bflags)
 
I wonder if the following means something.

Actualy I was trying to see if it worked in .Net 8 and got an error when it looked for the ButtonSelectedHighlight color.

So I checked the 4.8 code and it looks like there is such a known collor but it's not in the color table even in the 4.8 code.

Maybe they were just gettig ready for an update. I noticed LastKnownColor did not include the 210-212



Untitled.jpg
 
Last edited:
about those in source code:
1685473212475.png


The Init...LunaColors methods doesn't add these to the tables, InitThemedColors does (through InitCommonColors).
.Net: Source Browser
.Net Framework: Reference Source
 
Back
Top