Server-side styles
Server-side styles lets you set properties or attributes of particular controls across the entire application.
The server-side styles are defined as part of configuration in the DotvvmStartup.cs file.
Register style for a control or element
You can manage the styles using the StyleRepository object, which can be accessed from DotvvmConfiguration.
To register the style, you need to specify the type of the control, or use a parameter with tag name of HTML element:
// Modify all controls derived from ButtonBase
config.Styles.Register<ButtonBase>()...
// Modify all HTML elements with tag name input
config.Styles.Register("input")...
If you register the style by specifying the tag name, the behavior of DotVVM controls which use such elements internally will not be modified.
Conditional rules
It is possible to apply a style to all controls matching a condition. To do that, use the Register(Func<StyleMatchContext, bool>) method.
// This will hide every control derived from ButtonBase that does not have the Click property
config.Styles.Register<ButtonBase>(b => !b.HasProperty(ButtonBase.ClickProperty), allowDerived: true)
.SetAttribute("style", "display:none;", StyleOverrideOptions.Overwrite);
Matching by tags
We recommend using the Styles.Tag property for style matching.
It is a dedicated property for this purpose, and it can contain a list of string which can be referenced in the style conditions.
<!-- separate tags by comma -->
<dot:Button Styles.Tag="delete-icon,other-tag" Text="Delete" />
c.Styles.RegisterAnyControl(c => c.HasTag("delete-icon"))
.Prepend(new HtmlGenericControl("img").SetAttribute("src", "~/icons/delete.png"));
You can also match by tags on ancestor controls in the hierarchy:
c.Styles.Register<Literal>(c => c.HasAncestorWithTag("literal-spans"))
.SetProperty(c => c.RenderSpanElement, true);
Matching by view location or data context type
The styles are applied during the compilation of a view. The StyleMatchContext has methods for checking data contexts, ancestors, view file location and any other properties of the control.
config.Styles.Register<GridView>(c =>
c.HasAncestor<Repeater>() &&
c.HasDataContext<AccountInfo>() &&
c.HasViewInDirectory("~/Views/Logs/")
)
.SetDotvvmProperty(GridView.VisibleProperty, ..., StyleOverrideOptions.Ignore);
Define the style properties
The Register method returns an instance of StyleBuilder that lets you modify the control. You can set default values of attributes and properties, or override them completely. These method calls can also be chained.
// This will change the class on all buttons that do not have any
config.Styles.Register<Button>()
.SetAttribute("class", "single-class");
//this will overwrite class of all textboxes
config.Styles.Register<TextBox>()
.SetAttribute("class", "overwritten", StyleOverrideOptions.Overwrite);
//this will append class of all literals
config.Styles.Register<Literal>()
.SetAttribute("class", "appended", StyleOverrideOptions.Append);
//this will overwrite the text of all buttons
config.Styles.Register<Button>()
.SetDotvvmProperty(Button.TextProperty, "Button");
The
SetAttributemethod has the default value ofStyleOverrideOptions.Ignore, while theSetDotvvmPropertymethod hasStyleOverrideOptions.Overwrite. TheStyleOverrideOptions.Appendis allowed only for attributes which supports multiple values, such asclassorstyle, or for properties of a collection type (for example, thePostBack.Handlersattached property).
Work with data-binding expressions
From DotVVM 4.0, it's possible to compute the value for each control by supplying a lambda function. Keep in mind the lambda will be evaluated during view compilation, not at runtime.
// this will apply a confirm postback handler to all commands and staticCommands on this control
c.Styles.RegisterAnyControl(c => c.HasTag("confirm"))
.AppendDotvvmProperty(
PostBack.HandlersProperty,
c => new ConfirmPostBackHandler(c.GetHtmlAttribute(
"data-confirm-msg") ?? "This is a default confirm message")
);
It is also possible to process a bindings in the API. For example, this transforms every usage of the Visible property into a CSS class regardless whether it's a static value or a value / resource binding.
c.Styles.Register<HtmlGenericControl>(c => c.HasProperty(c => c.Visible))
.SetPropertyGroupMember("Class-", "hide", c =>
c.Property(c => c.Visible).Negate())
.SetProperty(c => c.Visible, true); // reset the Visible property
The .Negate() is a extension method defined on the new ValueOrBinding<bool> type. There are many others including .Select(t => ...) where you can supply any lambda function which can be translated to a JavaScript binding.
Modify content of styled controls
Starting with DotVVM 4.0, it is possible to create controls and place them into children, control properties, or append and prepend them to the matched control.
Use .PrependContent, .AppendContent, .SetControlProperty, .Append and .Prepend. You can also replace the entire control with a different one using .ReplaceWith which will also copy all properties onto the new control.
Last but not least, you can use .WrapWith to place a wrapper control around it.