Form

in namespace DotVVM.AutoUI.Controls

Usage & Scenarios

Generates a form for the object in the current binding context based on DotVVM Auto UI model metadata.

This control renders table-based form which works for the basic scenarios and doesn't require many CSS styling.

There are also other versions of this control which produce HTML and CSS classes expected by popular CSS frameworks:

Sample 1: Basic Form

The DataContext property set on the form or its closest ancestor defines the object for which the form will be auto-generated.

The model metadata or conventions set in Auto UI configuration are used to determine how the editing control for each property will be generated.

<auto:Form DataContext="{value: Customer}" />
public class ViewModel : DotvvmViewModelBase
{
    public CustomerModel Customer { get; set; } = new();
}

public class CustomerModel 
{
    [Display(Name = "Person or company name")]
    public string Name { get; set; }

    [Display(Name = "Is company")]
    public bool IsCompany { get; set; }
}

Sample 2: Groups of properties

To create more complex layouts or generate editors just for some properties, you can use the GroupName property to tell the control which group of properties shall be considered.

The property can be assigned to a specific group using the Display attribute:

[Display(..., GroupName = "basic")]
public string FirstName { get; set; }
<div class="two-columns">
    <div>
        <auto:Form DataContext="{value: Customer}" GroupName="BasicInfo" />
    </div>
    <div>
        <auto:Form DataContext="{value: Customer}" GroupName="ContactInfo" />
    </div>
</div>
public class ViewModel : DotvvmViewModelBase
{
    public CustomerModel Customer { get; set; } = new();
}

public class CustomerModel 
{
    [Display(Name = "Person or company name", GroupName = "BasicInfo")]
    public string Name { get; set; }

    [Display(Name = "Is company", GroupName = "BasicInfo")]
    public bool IsCompany { get; set; }


    [Display(Name = "E-mail address", GroupName = "ContactInfo")]
    public string Email { get; set; }

    [Display(Name = "Phone number", GroupName = "ContactInfo")]
    public string Phone { get; set; } 
}

Sample 3: Explicit property listing

If you prefer explicit listing of the properties, you can use the IncludeProperties and ExcludeProperties properties to specify which properties shall be generated.

<div class="two-columns">
    <div>
        <auto:Form DataContext="{value: Customer}" IncludeProperties="Name,IsCompany" />
    </div>
    <div>
        <auto:Form DataContext="{value: Customer}" ExcludeProperties="Name,IsCompany" />
    </div>
</div>
public class ViewModel : DotvvmViewModelBase
{
    public CustomerModel Customer { get; set; } = new();
}

public class CustomerModel 
{
    [Display(Name = "Person or company name")]
    public string Name { get; set; }

    [Display(Name = "Is company")]
    public bool IsCompany { get; set; }


    [Display(Name = "E-mail address")]
    public string Email { get; set; }

    [Display(Name = "Phone number")]
    public string Phone { get; set; } 
}

Sample 4: Include properties based on view

Sometimes you want to reuse the same model object in multiple contexts, a.k.a. "views".

You can decorate the properties with the Visible attribute to define in which views they shall appear.

// will be shown only when ViewName == "List"
[Visible(ViewNames = "List")]
public string CountryName { get; set; }
 
// will be shown only when ViewName == "Insert" || ViewName == "Edit"
[Visible(ViewNames = "Insert | Edit")]
public int CountryId { get; set; }
 
// will be shown only when ViewName != "Insert" && ViewName != "Edit"
[Visible(ViewNames = "!Insert & !Edit")]
public int UserId { get; set; }

The ViewName property specifies the view name for the current context. That's why only the editor for the CountryId property is displayed in the sample.

<auto:Form DataContext="{value: Customer}" ViewName="Edit" />
public class ViewModel : DotvvmViewModelBase
{
    public CustomerModel Customer { get; set; } = new();
}

public class CustomerModel 
{
    [Visible(ViewNames = "List")]
    public string CountryName { get; set; }

    [Visible(ViewNames = "Insert | Edit")]
    public int CountryId { get; set; }
}

Sample 5: Adding extra properties

You can include additional properties to those coming from the current binding context by using the Property-* property group.

If a property with the same name is present in the current binding context, it will be overriden by this settings.

<auto:Form DataContext="{value: Customer}" 
           Property-AgreeWithConditions="{value: _root.AgreeWithConditions}" />
public class ViewModel : DotvvmViewModelBase
{
    public CustomerModel Customer { get; set; } = new();

    public bool AgreeWithConditions { get; set; }
}

public class CustomerModel 
{
    [Display(Name = "Person or company name")]
    public string Name { get; set; }

    [Display(Name = "Is company")]
    public bool IsCompany { get; set; }
}

Sample 6: Responding to changes and enabling properties

You can use the Changed-* and Enabled-* property groups to specify commands triggered when the user changes the value, and to specify whether the field is editable.

There is also Visible-* property group which guides the field visibility, and Label-* property group which can override property labels.

<auto:Form DataContext="{value: Customer}" 
           Enabled-CompanyNumber="{value: IsCompany}" 
           Changed-CompanyNumber="{command: _root.LookupCompanyAddress()}" 
           Visible-CountryName="{value: IsInternational}" 
           Label-Name="{value: IsCompany ? 'Company name' : 'Person name'}" />
public class ViewModel : DotvvmViewModelBase
{
    public CustomerModel Customer { get; set; } = new();

    public void LookupCompanyAddress() 
    {
        // TODO
    }
}

public class CustomerModel 
{
    public string Name { get; set; }

    [Display(Name = "Is company")]
    public bool IsCompany { get; set; }

    [Display(Name = "Company number")]
    public string CompanyNumber { get; set; }

    [Display(Name = "International customer")]
    public bool IsInternational { get; set; }

    [Display(Name = "Country")]
    public string CountryName { get; set; }
}

Sample 7: Overriding generated templates

You can use the EditorTemplate-* property group to override the generated editor control with your own content.

If you need to override the entire form field (including the label element), use the FieldTemplate-* instead.

In our sample, we are providing file upload and image preview experience for the ImageUrl, and selection of values from a viewmodel collection for the Type property.

You can use the Selector attribute to auto-generate selection controls.

<auto:Form DataContext="{value: Image}">
    <EditorTemplate-Type>
        <dot:ComboBox DataSource="{value: _root.Types}" 
                      SelectedValue="{value: Type}" />
    </EditorTemplate-Type>
    <FieldTemplate-ImageUrl>
        <!-- Please note that you are responsible to render the structual elements produced by the Form control -->
        <tr>
            <td colspan="2">    
                <img src="{value: ImageUrl}" />

                <dot:FileUpload UploadedFiles="{value: _root.ImageUpload}" 
                                UploadCompleted="{command: _root.ProcessImage()}" />
            </td>
        </tr>
    </FieldTemplate-ImageUrl>
</auto:Form>
public class ViewModel : DotvvmViewModelBase
{
    public ImageModel Image { get; set; } = new();

    public UploadedFilesCollection ImageUpload { get; set; } = new();

    public string[] Types => new[] { "Small", "Large" };

    public void ProcessImage() 
    {
        // TODO
    }
}

public class ImageModel 
{
    public string ImageUrl { get; set; }

    public string Type { get; set; }
}

Properties

Name Type Description Notes Default Value
property icon EditorCellCssClass String
attribute
inner element
static value
bindable
default
null
property icon ExcludeProperties String[] The specified properties will not be included in this form.
attribute
inner element
static value
bindable
default
[]
property icon GroupName String Gets or sets the group of fields that should be rendered. If not set, fields from all groups will be rendered.
attribute
inner element
static value
bindable
default
null
property icon IncludeProperties String[] Only the specified properties will be included in this form. Using ViewName, GroupName or ExcludedProperties at the same time as IncludedProperties does not make sense. The properties will be listed in the exact order defined in this property.
attribute
inner element
static value
bindable
default
null
property icon LabelCellCssClass String
attribute
inner element
static value
bindable
default
null
property icon ViewName String Gets or sets the view name (e.g. Insert, Edit, ReadOnly). Some fields may have different metadata for each view.
attribute
inner element
static value
bindable
default
null

HTML produced by the control

<table class="autoui-form-table">
  <tr>
    <td class="autoui-label autoui-required">
      <label for="Name__input">Person or company name</label>
    </td>
    <td class="autoui-editor">
      <input type="text" required id="Name__input" ... />
    </td>
  </tr>
  <tr>
    <!-- CheckBox editors doesn't use the label cell, the text is placed behind the control -->
    <td class="autoui-label"></td>
    <td class="autoui-editor">
      <label id="IsCompany__input">
        <input type="checkbox" ... >
        <span>Is company</span>
      </label>
    </td>
  </tr>
</table>