Nevron Open Vision Documentation
User Interface / UI Themes / Custom Themes
In This Topic
    Custom Themes
    In This Topic

    NOV makes it easy to create custom UI themes based on any of the existing ones. This lets you quickly change the appearance of one or more widgets in order to make your application look exactly the way you like. This topic will teach you how to create a custom theme and how to modify different aspects of the theme and its skins.

     Create Custom Theme

    A UI theme contains a lot of CSS-like rules that shape the appearance of the UI widgets available in NOV applications. To avoid the complexity of declaring all of these rules yourself, it is best to base your custom theme on one of the predefined UI themes of NOV. For example, to create a custom UI theme that extends the NWindows10Theme you can use the following piece of code:

    Create custom theme
    Copy Code
    public class CustomTheme : NWindows10Theme
    {
    }
    
     Override Widget Styles

    Once you have created your custom theme you can override any of its Create...Styles methods to modify the appearance of a specific widget or set of widgets. In these method overrides you will typically use the GetRule and GetSkin methods to modify the appearance of a specific state of a widget. You can also use the GetSkinner method if you need to modify all states of a widget.

    The following example demonstrates how to make the border of text boxes - red:

    Modify text boxes' border
    Copy Code
    protected override void CreateTextBoxStyles()
    {
        base.CreateTextBoxStyles();
    
        // Make text boxes border red
        NThemeSkin skin = GetSkin(NTextBox.NTextBoxSchema);
        ThinBorder(skin, NColor.Red);
    }
    

    To modify the appearance of widgets inside other widget, you should make sure that you've built a proper selector that matches the widget hierarchy exactly. You can use any of the In...Context selector parts to built the selector. The following example demonstrates how to set a border to image boxes placed in buttons:

    Modify nested widgets appearance
    Copy Code
    protected override void CreateButtonStyles()
    {
        base.CreateButtonStyles();
    
        // Skin the image box of a button
        // An image box for buttons that have both image and text is usually placed in a
        // pair box and then in a button, so to match it we need the following selector
        // "image box -> in parent -> in button"
        NThemeRule rule = GetRule(NImageBox.NImageBoxSchema, InParentContext, InButtonBaseContext);
        ThinBorder(rule, Colors.ControlDark);
    
        // To skin image boxes for buttons that contain only an image, i.e. the image box is
        // placed directly in the button, we need the following selector:
        // "image box -> in button"
        rule = GetRule(NImageBox.NImageBoxSchema, InButtonBaseContext);
        ThinBorder(rule, Colors.ControlDark);
    }
    

    When modifying the appearance of the widgets you can use any color, but it's best to use colors from the Colors collection of the theme.
     Custom States and Contexts

    Sometimes the predefined selector parts (states and contexts) may not be enough to create the selector that you want. In such cases you can create your own custom states and contexts using the helper method that the NTheme base class provides, for example CreateState, CreateChildOfTypeContext, etc.

    Imagine the following scenario: you use a lot of OK and Cancel buttons in different dialogs of your application and you want to make these buttons to stand out by making the OK button's background fill green and that of the Cancel button - red. To achieve this you need to set the WindowResult property of the buttons in your code first like this:

    Create an OK and a Cancel button
    Copy Code
    NButton okButton = new NButton("OK");
    okButton.WindowResult = ENWindowResult.OK;
    stack.Add(okButton);
    
    NButton cancelButton = new NButton("Cancel");
    cancelButton.WindowResult = ENWindowResult.Cancel;
    stack.Add(cancelButton);
    

    You can then create custom states in your theme that match a specific value of the WindowResult property and then use these states to set a specific appearance to each button in the theme:

    Create and use custom theme states
    Copy Code
    protected override void CreateButtonStyles()
    {
        base.CreateButtonStyles();
    
        // Declare some custom theme states
        NThemingState okButtonState = CreateState(delegate (NSelectorBuilder sb) { sb.ValueEquals(NButton.WindowResultProperty, ENWindowResult.OK); });
        NThemingState cancelButtonState = CreateState(delegate (NSelectorBuilder sb) { sb.ValueEquals(NButton.WindowResultProperty, ENWindowResult.Cancel); });
    
                
        // Skin the OK button
        NThemeRule rule = GetRule(NButton.NButtonSchema, okButtonState);
        Background(rule, NColor.LightGreen);
    
        // Skin the Cancel button
        rule = GetRule(NButton.NButtonSchema, cancelButtonState);
        Background(rule, NColor.OrangeRed);
    }
    
     Custom Skins

    In some cases you might want to modify the skin for a specific widget in order to alter its appearance in one or more of its states. To do so, you should simply get a reference to and modify the skins you are interested in. You can also create and assign a completely new skin. The following is a custom UI theme that inherits the Window 10 theme and modifies the appearance of buttons and tabs.

    Modify skins
    Copy Code
    /// <summary>
    /// A custom NOV theme based on the Windows 10 theme.
    /// </summary>
    public class NCustomTheme : NWindows10Theme 
    {
        /// <summary>
        /// Static constructor.
        /// </summary>
        static NCustomTheme()
        {
            NCustomThemeSchema = NSchema.Create(typeof(NCustomTheme), NWindows10ThemeSchema);
        }
    
        /// <summary>
        /// Creates button styles.
        /// </summary>
        protected override void CreateButtonStyles()
        {
            // Change mouse over background fill to orange
            NColorSkinState mouseOverState = (NColorSkinState)Skins.Button.GetState(NSkinState.MouseOver);
            mouseOverState.BackgroundFill = new NColorFill(NColor.Orange);
            // Change pressed button border to 3px purple border, background fill to dark red and text fill to white
            NColorSkinState pressedState = (NColorSkinState)Skins.Button.GetState(NSkinState.Pressed);
            pressedState.SetBorderFill(new NColorFill(NColor.Green));
            pressedState.BorderThickness = new NMargins(3);
            pressedState.BackgroundFill = new NColorFill(NColor.DarkRed);
            pressedState.TextFill = new NColorFill(NColor.White);
            // Call base to skin the buttons
            base.CreateButtonStyles();
        }
        /// <summary>
        /// Creates flat button styles, which are buttons commonly in ribbon and toolbars.
        /// </summary>
        protected override void CreateFlatButtonStyles()
        {
            NColorSkinState mouseOverState = (NColorSkinState)Skins.FlatButton.GetState(NSkinState.MouseOver);
            mouseOverState.BackgroundFill = new NColorFill(NColor.Orange);
            // Call base to skin flat buttons
            base.CreateFlatButtonStyles();
        }
        /// <summary>
        /// Creates the tab styles. Overriden to make the mouse over state orange.
        /// </summary>
        protected override void CreateTabStyles()
        {
            // Modify the tab skins
            NColor backgroundColor = NColor.Orange;
            NSkin[] tabSkins = new NSkin[] {
                TabSkins.Top.FarTabPageHeaderSkin,
                TabSkins.Top.InnerTabPageHeaderSkin,
                TabSkins.Top.NearAndFarTabPageHeaderSkin,
                TabSkins.Top.NearTabPageHeaderSkin };
            for (int i = 0; i < tabSkins.Length; i++)
            {
                NColorSkinState state = (NColorSkinState)tabSkins[i].GetState(NSkinState.MouseOver);
                state.BackgroundFill = new NColorFill(backgroundColor);
            }
            // Call base to skin the tab widget
            base.CreateTabStyles();
        }
    
        /// <summary>
        /// Schema associated with NCustomTheme.
        /// </summary>
        public static readonly NSchema NCustomThemeSchema;
    }
    

    You can also modify symbols of skins, for example, the code below demonstrates how to make the check box symbol an X instead of a check and how to make the radio button filled circle blue:

    Modify symbols
    Copy Code
    internal class CustomTheme : NWindows10Theme
    {
        protected override void CreateCheckBoxStyles()
        {
            // Modify the checked state symbol to x instead of check
            NColorSkinState checkedState = (NColorSkinState)Skins.CheckBox.GetState(Checked);
            NSize symbolSize = checkedState.Symbol.DesiredSize - new NSize(1, 1);
            checkedState.Symbol = NSymbol.Create(ENSymbolShape.StrokedX, symbolSize, Colors.ControlText);
    
            // Call base to skin check boxes
            base.CreateCheckBoxStyles();
        }
    
        protected override void CreateRadioButtonStyles()
        {
            // Modify the checked state of the radio button skin
            NColorSkinState checkedState = (NColorSkinState)Skins.RadioButton.GetState(Checked);
            NFillableSymbolShape symbolShape = (NFillableSymbolShape)checkedState.Symbol[0];
            symbolShape.Fill = new NColorFill(NColor.Blue);
    
            // Call base to skin radio buttons
            base.CreateRadioButtonStyles();
        }
    }
    
    The NOV Themes are available in FULL SOURCE CODE upon request. Please contact us at support@nevron.com if you would like to receive them. The easiest way to build a custom theme is to simply modify one of the existing ones.
    See Also