DBTools.Themes
The DBTools.Themes project provides a unified dark theme system for all DBTools WPF applications. It establishes design tokens, brush definitions, and control styles that ensure visual consistency across the application while avoiding conflicts with Revit's host environment.
Overview
DBTools.Themes solves several key challenges:
Host Isolation: Revit's UI can interfere with WPF resource dictionaries. This project uses vendored, renamed libraries (e.g.,
DBTools.HandyControlinstead ofHandyControl) to prevent conflicts with pyRevit or other add-ins.Consistent Branding: Implements the DBTools brand colors (deep blue
#1946B9and golden yellow#FEC425) across all UI controls.WCAG Accessibility: Text colors are designed to meet WCAG AA contrast requirements (min 4.5:1 ratio on dark backgrounds).
Template Boundary Crossing: The
BrushKeyssystem usingComponentResourceKeyallows brushes to propagate correctly acrossDataTemplateandControlTemplateboundaries.
Source:
src/DBTools.Themes/DBTools.Themes.csproj:1-73
Project Structure
DBTools.Themes/
├── DBTools.Themes.csproj # Project configuration
├── BrushKeys.cs # ComponentResourceKey definitions
├── Assets/
│ └── (linked) db_tools_icon.png # Application icon (source: src/Assets/Icons/db_tools_icon.png)
└── Themes/
├── App.Theme.xaml # Root dictionary (entry point)
├── App.Tokens.xaml # Design tokens (spacing, sizing)
├── App.Brushes.xaml # Color/brush definitions
├── App.Converters.xaml # Value converters
├── App.Controls.Base.xaml # Base control styles
├── App.DataGrid.xaml # DataGrid-specific styles
├── App.Menus.xaml # Menu/ContextMenu styles
├── App.Components.xaml # Higher-level component styles
Source:
src/DBTools.Themes/DBTools.Themes.csproj:38-51
Key Files
App.Theme.xaml - Root Entry Point
The root resource dictionary that merges all theme components. This is what consuming projects reference.
<ResourceDictionary.MergedDictionaries>
<!-- HandyControl Foundation -->
<ResourceDictionary Source="pack://application:,,,/DBTools.HandyControl;component/Themes/SkinDark.xaml"/>
<ResourceDictionary Source="pack://application:,,,/DBTools.HandyControl;component/Themes/Theme.xaml"/>
<!-- DBTools Custom Themes -->
<ResourceDictionary Source="App.Tokens.xaml" />
<ResourceDictionary Source="App.Brushes.xaml" />
<!-- ... additional dictionaries ... -->
</ResourceDictionary.MergedDictionaries>
Source:
src/DBTools.Themes/Themes/App.Theme.xaml:1-22
BrushKeys.cs - ComponentResourceKey System
Defines strongly-typed keys for all theme brushes. This pattern enables brushes to work correctly inside DataTemplate and ControlTemplate boundaries where DynamicResource with string keys may fail.
public static class BrushKeys
{
public static ComponentResourceKey Primary => new(typeof(BrushKeys), "Brush.Primary");
public static ComponentResourceKey Secondary => new(typeof(BrushKeys), "Brush.Secondary");
// ... 100+ additional keys
}
Usage in XAML:
<Border Background="{DynamicResource {x:Static theme:BrushKeys.Primary}}" />
Source:
src/DBTools.Themes/BrushKeys.cs:1-140
Design Tokens
Design tokens provide consistent spacing, sizing, typography, and other visual constants.
Spacing Tokens
| Token | Value | Usage |
|---|---|---|
Spacing4 |
4px | Tight spacing (icon margins) |
Spacing8 |
8px | Standard spacing |
Spacing12 |
12px | Medium spacing |
Spacing16 |
16px | Large spacing |
Spacing32 |
32px | Section spacing |
Scalar variants (Spacing8.Value, etc.) are provided for properties that require Double instead of Thickness.
Source:
src/DBTools.Themes/Themes/App.Tokens.xaml:5-18
Padding Tokens
| Token | Value | Usage |
|---|---|---|
Pad4 |
4px uniform | Compact padding |
Pad8 |
8px uniform | Standard padding |
Pad16 |
16px uniform | Large padding |
Pad8x4 |
8px H, 4px V | Button padding |
Card.Padding |
16px H, 12px V | Card content |
Source:
src/DBTools.Themes/Themes/App.Tokens.xaml:24-56
Gap Tokens
Directional margins for layout:
| Token | Value | Description |
|---|---|---|
TGap8 |
Top 8px | Top margin |
BGap8 |
Bottom 8px | Bottom margin |
LGap8 |
Left 8px | Left margin |
RGap8 |
Right 8px | Right margin |
VGap8 |
Top/Bottom 8px | Vertical margin |
HGap8 |
Left 8px | Horizontal gap |
Source:
src/DBTools.Themes/Themes/App.Tokens.xaml:30-64
Typography Tokens
| Token | Size | Usage |
|---|---|---|
FontSize.Caption |
11px | Captions, timestamps |
FontSize.Body.Small |
12px | Secondary text |
FontSize.Body |
13px | Default body text |
FontSize.Subtitle |
14px | Subtitles |
FontSize.Title |
16px | Section titles |
FontSize.Header |
20px | Page headers |
Source:
src/DBTools.Themes/Themes/App.Tokens.xaml:66-72
Corner Radius Tokens
| Token | Value | Usage |
|---|---|---|
Radius4 |
4px | Buttons, inputs |
Radius6 |
6px | Cards, chips |
Radius8 |
8px | Dialogs, overlays |
Radius12 |
12px | Large surfaces |
Source:
src/DBTools.Themes/Themes/App.Tokens.xaml:43-46
Control Size Tokens
| Token | Value | Usage |
|---|---|---|
MinHeight.Control |
32px | Minimum control height |
Size.CheckBox.Box |
18px | Checkbox dimensions |
Size.ToggleTrack.Width |
44px | Toggle switch track |
Size.DataGridRow.MinHeight |
32px | Grid row height |
Size.ScrollBar.Width |
10px | Scrollbar width |
Source:
src/DBTools.Themes/Themes/App.Tokens.xaml:98-114
Color System (App.Brushes.xaml)
The color system is built around the DBTools brand colors with carefully designed semantic roles.
Brand Colors
| Key | Color | Description |
|---|---|---|
Primary |
#1946B9 |
Deep blue - primary actions |
PrimaryLight |
#3D6AD4 |
Hover state |
PrimaryDark |
#0D2E7A |
Pressed state |
Secondary |
#FEC425 |
Golden yellow - accents |
SecondaryLight |
#FFD54F |
Hover state |
SecondaryDark |
#C79100 |
Pressed state |
Source:
src/DBTools.Themes/Themes/App.Brushes.xaml:14-19
Surface Colors
Neutral dark palette with reduced blue tint:
| Key | Color | Description |
|---|---|---|
Paper |
#181820 |
Window background |
Surface |
#222228 |
Card/panel background |
SurfaceAlt |
#1C1C22 |
Alternate surface |
SurfaceHover |
#2A2A32 |
Hover state |
CardSurface |
#1E1E24 |
Card background |
CardSurfaceElevated |
#282830 |
Elevated cards |
Source:
src/DBTools.Themes/Themes/App.Brushes.xaml:24-30
Text Colors (WCAG Compliant)
| Key | Color | Contrast | Description |
|---|---|---|---|
Body / Text |
#E6E6E6 |
~12:1 | Primary text |
BodyLight / TextSecondary |
#BDBDBD |
~9:1 | Secondary text |
TextMuted / Muted |
#999999 |
~7:1 | Muted text |
OnAccent |
#FFFFFF |
- | Text on colored bg |
OnSecondary |
#181820 |
- | Text on yellow |
Source:
src/DBTools.Themes/Themes/App.Brushes.xaml:35-44
Selection & Highlight Colors
Alpha transparency reference: #33 = 20%, #44 = 27%, #55 = 33%, #66 = 40%, #99 = 60%
| Key | Color | Description |
|---|---|---|
Selection |
#441946B9 (27%) |
Standard selection |
SelectionStrong |
#661946B9 (40%) |
Strong selection |
SelectionGold |
#33FEC425 (20%) |
Row highlighting |
SelectionGoldStrong |
#55FEC425 (33%) |
Strong gold |
Hover |
#33FEC425 (20%) |
Hover state |
Source:
src/DBTools.Themes/Themes/App.Brushes.xaml:59-78
Status Colors
| Key | Color | Description |
|---|---|---|
Success |
#4CAF50 |
Success state |
Warning |
#FFA000 |
Warning state |
Error |
#CF6679 |
Error state |
Info |
#1946B9 |
Informational |
Each status color has Light and Background variants for subtle backgrounds.
Source:
src/DBTools.Themes/Themes/App.Brushes.xaml:84-95
Specialized Brush Categories
The brush system includes specialized categories for:
- DataGrid: Header, row, cell, selection colors
- Input Controls: Background, border, focus states
- Buttons: Primary, secondary, accent, danger variants
- Checkbox/Toggle: Box, checked, indeterminate states
- Tabs: Background, indicator, hover states
- ScrollBar/Slider: Track, thumb, hover/pressed states
- VTC Diff View: Add/remove/missing background colors
Source:
src/DBTools.Themes/Themes/App.Brushes.xaml:100-232
BrushKeys System
Why ComponentResourceKey?
WPF has a limitation where DynamicResource with string keys doesn't always resolve correctly inside DataTemplate or ControlTemplate boundaries. ComponentResourceKey solves this by creating type-safe keys that the resource system can resolve across template boundaries.
Key Categories
The BrushKeys class defines 100+ keys organized into categories:
| Category | Example Keys | Count |
|---|---|---|
| Brand | Primary, Secondary, PrimaryLight |
6 |
| Surface | Paper, Surface, CardSurface |
7 |
| Text | Body, Text, TextMuted |
10 |
| Border | Border, Divider, BorderSubtle |
4 |
| Selection | Selection, SelectionGold, Hover |
12 |
| Status | Success, Warning, Error, Info |
12 |
| DataGrid | DataGridHeader, DataGridRow, etc. |
14 |
| Input | InputBackground, InputBorder |
5 |
| Button | ButtonPrimary, ButtonDanger |
10 |
| Checkbox | CheckBox, CheckChecked |
6 |
| Toggle | ToggleTrackOn, ToggleThumb |
7 |
| Tab | TabBackground, TabIndicator |
5 |
| ScrollBar | ScrollBarTrack, ScrollBarThumb |
4 |
| Slider | SliderTrack, SliderThumb |
5 |
| Progress | ProgressTrack, ProgressFill |
3 |
| Toolbar | ToolbarChipBackground, etc. |
6 |
| VTC Diff | VtcDiffAddBackground, etc. |
4 |
Source:
src/DBTools.Themes/BrushKeys.cs:11-139
Usage Pattern
In XAML:
xmlns:theme="clr-namespace:DBTools.Themes;assembly=DBTools.Themes"
<Border Background="{DynamicResource {x:Static theme:BrushKeys.CardSurface}}"
BorderBrush="{DynamicResource {x:Static theme:BrushKeys.CardBorder}}" />
In Code:
var brush = (Brush)FindResource(BrushKeys.Primary);
Control Styles
Window Styles
The theme provides implicit styles for DbtWindowBase and DbtRibbonWindowBase:
- Sets the DBTools icon
- Applies
Paperbackground andBodyforeground - Includes progress overlay support via
ProgressOverlayService
Source:
src/DBTools.Themes/Themes/App.Controls.Base.xaml:13-55
Base Control Styles
TextBlock
- Foreground:
Bodybrush - TextWrapping:
Wrap - TextTrimming:
CharacterEllipsis
Button
- MinWidth: 88px, MinHeight: 36px
- Hover:
SecondaryHoverbackground,Secondaryborder - Pressed:
PrimaryHoverbackground,Primaryborder
TextBox
- Background:
InputBackground - Border:
InputBorder(hover:Secondary, focus:FocusBorder) - Validation error: Red border with tooltip
ComboBox
- Custom dropdown template with dark popup background
- Drop shadow effect on dropdown
- Proper dark theme item highlighting
CheckBox / RadioButton
- Custom templates with theme-consistent colors
- Checked:
CheckCheckedbackground - Indeterminate:
CheckIndeterminatefill (yellow)
Source:
src/DBTools.Themes/Themes/App.Controls.Base.xaml:61-449
DataGrid Styles
Comprehensive DataGrid theming with:
Row Features:
- Yellow accent stripe on left edge
- Gold hover highlighting (
DataGridRowHover) - Blue selection with yellow accent (
DataGridRowSelected) - Keyboard focus indicator (
DataGridRowFocus)
Cell Features:
- Focus state with primary border
- Edit mode with secondary border
- Conflict highlighting support
Column Header:
- Hover state
- Sort direction indicators (yellow arrows)
- Resizable column grippers
Source:
src/DBTools.Themes/Themes/App.DataGrid.xaml:1-476
Component Styles (App.Components.xaml)
Higher-level UI component styles:
| Style Key | Target | Description |
|---|---|---|
ToolBar |
ToolBar | Dark themed toolbar |
StatusBar |
StatusBar | Dark themed status bar |
ToolbarChip |
ToggleButton | Pill-shaped filter buttons |
OverlayCard |
Border | Modal dialog container |
Card |
Border | Standard card surface |
Card.Elevated |
Border | Card with drop shadow |
Dbt.Section |
GroupBox | Section with accent stripe |
Dbt.Callout |
Border | Info callout box |
WarningBar |
Border | Warning message container |
Typography Styles:
HeaderText,SubtitleText,BodyText,DescriptionText,CaptionText
Source:
src/DBTools.Themes/Themes/App.Components.xaml:1-414
Menu Styles
Custom templates for proper dark theme rendering in Revit:
- ContextMenu: Dark background, rounded corners, drop shadow
- MenuItem: Hover highlighting, keyboard shortcut display
- MenuSeparator: Subtle divider
Source:
src/DBTools.Themes/Themes/App.Menus.xaml:1-136
Vendored Library Integration
Why Vendored Libraries?
Revit hosts multiple add-ins that may use conflicting versions of UI libraries like HandyControl. By vendoring and renaming these libraries, DBTools avoids:
- Assembly version conflicts
- Resource dictionary collisions
- pyRevit theme interference
Vendored Assemblies
| Original | Vendored | Purpose |
|---|---|---|
| HandyControl | DBTools.HandyControl | Control library foundation |
<Reference Include="DBTools.HandyControl">
<HintPath>$(DBT_VendorArtifactsRoot)handycontrol\$(TargetFramework)\DBTools.HandyControl.dll</HintPath>
</Reference>
Source:
src/DBTools.Themes/DBTools.Themes.csproj:55-71
Build Configuration
Target Frameworks
The project multi-targets:
net48(Revit 2024 and earlier)net8.0-windows(Revit 2025+)
XAML Compilation
Some XAML files are kept as raw resources (not compiled to BAML) to avoid requiring a project reference to DBTools.Core:
<Page Remove="Themes\App.Converters.xaml" />
<Resource Include="Themes\App.Converters.xaml" />
Source:
src/DBTools.Themes/DBTools.Themes.csproj:38-46
Dependency Rules
Critical: DBTools.Themes must NOT reference DBTools.Core to avoid circular dependencies. Theme dictionaries that need Core types are defined in Core and merged via pack URIs.
Source:
src/DBTools.Themes/DBTools.Themes.csproj:31-34
How to Extend
Adding New Brushes
Add the
ComponentResourceKeytoBrushKeys.cs:public static ComponentResourceKey MyNewBrush => new(typeof(BrushKeys), "Brush.MyNew");Define the brush in
App.Brushes.xaml:<SolidColorBrush x:Key="{x:Static theme:BrushKeys.MyNewBrush}" Color="#FF123456" />
Adding New Tokens
Add to App.Tokens.xaml following existing patterns:
<sys:Double x:Key="Size.MyNew">24</sys:Double>
<Thickness x:Key="Pad.MyNew">8,4</Thickness>
Creating New Control Styles
- For base controls, add to
App.Controls.Base.xaml - For higher-level components, add to
App.Components.xaml - Use
DynamicResourcewithBrushKeysfor all colors - Use token resources for spacing/sizing
Adding Converters
- Implement converter in
DBTools.Core.UI.Converters - Add resource entry in
App.Converters.xaml:<conv:MyConverter x:Key="Converter.MyConverter" />
Cross-References
- Theme System Architecture - Detailed architecture documentation
- DBTools.Core - Theme loading and initialization
Value Converters
Available converters (defined in App.Converters.xaml):
| Key | Type | Description |
|---|---|---|
Converter.BoolToVisibility |
BooleanToVisibilityConverter | Standard bool-to-visibility |
Converter.InverseBoolToVisibility |
InverseBooleanToVisibilityConverter | Inverted visibility |
Converter.NullToVisibility |
NullToVisibilityConverter | Collapsed when not null |
Converter.NullToInverseVisibility |
NullToInverseVisibilityConverter | Collapsed when null |
Converter.RowKindToVisibility |
RowKindToVisibilityConverter | DataGrid row type filtering |
Source:
src/DBTools.Themes/Themes/App.Converters.xaml:1-12