Control properties
The properties in markup controls with code-behind and code-only controls cannot be simple C# properties with default getter and setter. Such properties could only contain values, but they couldn't store data-binding expressions.
To make the data-binding work, you have to expose those properties as DotvvmProperty objects which contain metadata about the property and which can store binding expressions. It is similar to dependency properties known from Windows Presentation Foundation.
Declare the property in markup-controls with code or code-only controls
DotVVM for Visual Studio adds an easy-to-use code snippet, which makes declaration of these properties simple.
To declare a DotVVM property, type dotprop and press Tab. The property declaration will be generated for you.
If you are using Resharper and type
dotprop, it will not see the code snippet and it will match theDotvvmPropertyclass instead. If this happens, press Escape before pressing Tab, and the snippet will work.
After you invoke the dotprop code snippet, you can change the name of the property, its type, the containing class, and the default value:
public string Title
{
get { return (string)GetValue(TitleProperty); }
set { SetValue(TitleProperty, value); }
}
public static readonly DotvvmProperty TitleProperty
= DotvvmProperty.Register<string, AddressEditor>(c => c.Title, "Address");
Until DotVVM 3.0, the declaration of static
DotvvmPropertyfield was optional - DotVVM inferred the field automatically. However, this behavior had many limitations and we decided to drop this feature. From DotVVM 4.0, the declaration ofDotvvmPropertyis required.
Declare the property in composite controls
Because declaring properties like this is uncomfortable and the code is hard to maintain, DotVVM 4.0 introduced the composite controls which declare the properties as parameters of the GetContents method:
public class MyControl : CompositeControl
{
public static DotvvmControl GetContents(
ValueOrBinding<string> title,
...
)
{
...
}
}
Specify markup options
The properties can be decorated via the MarkupOptions attribute. It allows to specify, whether the property is required, whether it supports value binding or a hard-coded value in the markup, and whether it is mapped as an attribute or the inner element.
The attribute is applied on the property like this:
[MarkupOptions(AllowHardCodedValue = false)]
public string Text
{
get { return (string)GetValue(TextProperty); }
set { SetValue(TextProperty, value); }
}
public static readonly DotvvmProperty TextProperty
= DotvvmProperty.Register<string, TextBoxWithLabel>(c => c.Text, null);
The attribute in the example above tells DotVVM to accept only the value binding as the value of this property:
<!-- only value binding is allowed -->
<cc:TextBoxWithLabel Text="{value: SomeProperty}" ... />
<!-- WRONG - this won't work -->
<cc:TextBoxWithLabel Text="Hello" ... />
<!-- WRONG - the resource binding is evaluated on the server and behaves as a hard-coded value -->
<cc:TextBoxWithLabel Text="{resource: SomeProperty}" ... />
MarkupOptions properties
Use the properties of the attribute to specify the behavior:
AllowBinding(defaulttrue) - specifies whether the value binding is allowed for this property.AllowHardCodedValue(defaulttrue) - specifies whether the hard-coded value or resource binding is allowed for this property.Required(defaultfalse) - specifies whether the property must be set in the markupMappingMode(defaultMappingMode.Attribute) - specifies whether the property value is set as an attribute or inner element (e. g.ItemTemplateproperty of the Repeater control).
The attribute is commonly used in markup controls with code-behind and code-only controls.
The composite controls specify the support for binding or hard-coded values by using special property types described in the following section.
Special property types
If the property accepts only the value binding, you can use the IValueBinding type to represent its value. The same applies to ICommandBinding for command (or static command) properties.
In composite controls, the type ValueOrBinding<T> is often use it indicates that the property can contain both value binding or a value, and it allows to work with binding expressions in a more elegant way.
To represent templates, the ITemplate type is commonly used.
The control can also have properties of collection types. For example, a collection of strings can be mapped from the attribute with comma-separated values. A collection of DotvvmBindableObject or its descendants can be mapped as inner elements (e. g. Columns property of the GridView control).
Control markup options
By default, all DotVVM controls can contain child elements. If you put something inside your control element, it will be placed in the control's Children collection.
Some controls may not support inner content, or want to redirect this content to another property. For example, the Repeater control doesn't support content (its inner content specified in the markup is not placed in the Children collection) - instead, it is using the ItemTemplate property to hold the inner content. Also, the property is marked as default, so it is not necessary to write the <ItemTemplate> element inside the <dot:Repeater> control.
[ControlMarkupOptions(AllowContent = false, DefaultContentProperty = nameof(Repeater.ItemTemplate))]
public class Repeater : DotvvmControl
{
...
}
<dot:Repeater ...>
<ItemTemplate> <!-- this line is optional - ItemTemplate is the DefaultContentProperty-->
My item {{value: Title}}
</ItemTemplate> <!-- this line is optional - ItemTemplate is the DefaultContentProperty-->
</dot:Repeater>
Control capabilities
Often, a group of control properties is used together and represent a common behavior. DotVVM 4.0 introduced a concept of capabilities which are an alternative way to declare properties.
See Control capabilities for more information.