Working with DataForm

3 Sep 202016 minutes to read

Auto-generating DataFormItems for Data field

By default, DataFormItems will be generated based on type of property. For example, DataFormNumericItem will be created for int type property. 
DataFormItem generation depends on the type and attribute defined for the property. The following table lists the several types of DataFormItem and its constraints for auto generation.

Generated DataFormItem Type Editor Data Type / Attribute

DataFormTextItem

Text Default DataFormItem generated for string type and the properties with below attributes. [DataType(DataType.Text)] [DataType(DataType.MultilineText)] [DataType(DataType.Password)]

DataFormNumericItem

Numeric Generated for int, double, float, decimal, long types and its nullable also properties with below attributes. [DataType(DataType.Currency)] [DataType("Percent")]

DataFormDateItem

Date Generated for DateTime type and properties with below attributes. [DataType(DataType.Date)] [DataType(DataType.DateTime)]

DataFormTimeItem

Time Generated for the property with below attribute. [DataType(DataType.Time)]

DataFormPickerItem

Picker Generated for Enum type property and the property with below attribute. [EnumDataTypeAttribute]

DataFormItem

Bool Bool type

You can customize the property settings or cancel the generation of DataFormItem by handling AutoGeneratingDataFormItem event.

Customize auto generated fields

You can customize or cancel the generated DataFormItem by handling AutoGeneratingDataFormItem event. AutoGeneratingDataFormItem event occurs when the field is auto-generated for public and non-static property of the data object.

dataForm.AutoGeneratingDataFormItem += DataForm_AutoGeneratingDataFormItem;

private void DataForm_AutoGeneratingDataFormItem(object sender, AutoGeneratingDataFormItemEventArgs e)
{

}

AutoGeneratingDataFormItemEventArgs provides the information about the auto-generated.  AutoGeneratingDataFormItemEventArgs.DataFormItem  property returns the newly created DataFormItem.

Cancel DataFormItem generation of data field

You can cancel the specific DataFormItem adding to the DataForm by handling AutoGeneratingDataFormItem event or by defining display attribute to avoid the particular data field being displayed in DataForm.

Using attributes

You can use Bindable attribute or set AutoGenerateField as false for canceling DataFormItem generation.

private int id;
[Display(AutoGenerateField = false)]
public int ID
{
    get
    {
        return id;
    }
    set
    {
        id = value;
        RaisePropertyChanged("ID");
    }
}
private string middleName;
[Bindable(false)]
public string MiddleName
{
    get { return this.middleName; }
    set
    {
        this.middleName = value;
    }
}

Using event

In the below code, DataFormItem generation for MiddleName property is canceled by setting Cancel property to true.

dataForm.AutoGeneratingDataFormItem += DataForm_AutoGeneratingDataFormItem;

private void DataForm_AutoGeneratingDataFormItem(object sender, AutoGeneratingDataFormItemEventArgs e)
{
    if (e.DataFormItem.Name == "MiddleName")
        e.Cancel = true;
}

Changing Editor type

You can change the editor of DataFormItem in AutoGeneratingDataFormItem event.
In the below code, editor is changed for Name field from Picker to DropDown.

dataForm.AutoGeneratingDataFormItem += DataForm_AutoGeneratingDataFormItem;

private void DataForm_AutoGeneratingDataFormItem(object sender, AutoGeneratingDataFormItemEventArgs e)
{
    if (e.DataFormItem.Name == "Name")
        e.DataFormItem.Editor = "DropDown";
}

Changing property settings

You can change the property of DataFormItem in AutoGeneratingDataFormItem event.
Here, Salary data field is restricted from being edited in DataForm.

dataForm.AutoGeneratingDataFormItem += DataForm_AutoGeneratingDataFormItem;

private void DataForm_AutoGeneratingDataFormItem(object sender, AutoGeneratingDataFormItemEventArgs e)
{
    if (e.DataFormItem != null)
    {
        if (e.DataFormItem.Name == "Salary")
            e.DataFormItem.IsReadOnly = true;
    }
}

Setting Watermark

You can display watermark in editor by defining display attribute or using AutoGeneratingDataFormItem event.

Using attribute

You can show watermark in editor by setting Prompt in display attribute.

private string middleName;
[Display(Prompt = "Enter middle name")]
public string MiddleName
{
    get { return this.middleName; }
    set
    {
        this.middleName = value;
    }
}

Using event

You can show watermark in editor by using PlaceHolderText property in DataFormItem.

dataForm.AutoGeneratingDataFormItem += DataForm_AutoGeneratingDataFormItem;

private void DataForm_AutoGeneratingDataFormItem(object sender, AutoGeneratingDataFormItemEventArgs e)
{
    if (e.DataFormItem != null)
    {
        if (e.DataFormItem.Name == "Description")
            e.DataFormItem.PlaceHolderText = "Enter description";
    }
}

Changing DataFormItem

You can change created DataFormItem and assign new DataFormItem based on your requirement.
Here,DataFormTextItem with number keyboard loaded for numeric value instead of DataFormNumericItem.

dataForm.AutoGeneratingDataFormItem += DataForm_AutoGeneratingDataFormItem;

private void DataForm_AutoGeneratingDataFormItem(object sender, AutoGeneratingDataFormItemEventArgs e)
{
    if (e.DataFormItem != null)
    {
        if (e.DataFormItem.Name == "ID")
            e.DataFormItem = new DataFormTextItem() { Name = "ID", Editor = "Text", KeyBoardType = UIKeyboardType.NumberPad };
    }
}

Adding or removing Data field displayed in DataForm at runtime

If you want to remove or add data fields item at runtime, you can use RefreshLayout method which auto-generates the DataFormItem’s where you can skip certain item from display. By default, it will generate the items that was canceled initially. If you want to regenerate all the items, you need to pass argument as true.
In the below code snippet, items are auto generated based on ` refreshLayout flag where you can change flag at runtime and call RefreshLayout` method to add or remove items being displayed in DataForm at runtime.

dataForm = new SfDataForm(new CoreGraphics.CGRect(0, 45, this.View.Frame.Width, this.View.Frame.Height - 30));
dataForm.DataObject = new ContactsInfo();
dataForm.AutoGeneratingDataFormItem += DataForm_AutoGeneratingDataFormItem;
var button = new UIButton(new CoreGraphics.CGRect(0, this.View.Frame.Height - 30, this.View.Frame.Width, 30));
button.SetTitle("More Fields", UIControlState.Normal);
button.SetTitleColor(UIColor.Black, UIControlState.Normal);
button.TouchDown += Button_TouchDown;
View.AddSubview(dataForm);
View.AddSubview(button);

private void DataForm_AutoGeneratingDataFormItem(object sender, AutoGeneratingDataFormItemEventArgs e)
{
    if (e.DataFormItem != null)
    {
        if (!refreshLayout)
        {
            if (e.DataFormItem.Name.Equals("MiddleName") || e.DataFormItem.Name.Equals("LastName"))
                e.Cancel = true;
        }
        else
        {
            if (e.DataFormItem.Name == "GroupName")
                e.Cancel = true;
        }
    }
}

Initial rendering of data form items in Xamarin.iOS DataForm

If you want to generate MiddleName and LastName fields at runtime, you need to set refreshLayout flag as true and call RefreshLayout method which triggers AutoGeneratingDataFormItem event again and generates the items based on refreshLayout flag.

private void Button_TouchDown(object sender, EventArgs e)
{
    refreshLayout = true;
    dataForm.RefreshLayout();
}

Here, MiddleName and LastName fields are generated at runtime after clicking more field button.

Adding data form fields at run time in Xamarin.iOS DataForm

GroupName field is displayed initially in DataForm. If you want to remove it at runtime, you need to set refreshLayout flag as true and pass argument as true inRefreshLayout method. It triggers AutoGeneratingDataFormItem event for all the fields where you can cancel `GroupName’ field item generation.

private void Button_TouchDown(object sender, EventArgs e)
{
    refreshLayout = true;
    dataForm.RefreshLayout(true);
}

Here, GroupName field is removed at runtime.

Removing data form fields at run time in Xamarin.iOS DataForm

You can download the sample from here.

DataFormItemManager

DataFormItemManager creates DataFormItems collection and handles value reflection and validation. It also provides overrides to handle get and set property values from and to data object.

Manually generate DataFormItems for DataObject

By default, DataFormItems will be generated based on data object. If you need to generate DataFormItems manually, override DataFormItemManager class and set it to SfDataForm.ItemManager.

To create DataFormItems, override the GenerateDataFormItems method.

public class DataFormItemManagerExt : DataFormItemManager
{       
    public SfDataForm sfDataForm;
    public DataFormItemManagerExt(SfDataForm dataForm) : base(dataForm)
    {
        sfDataForm = dataForm;       
    }
    protected override List<DataFormItemBase> GenerateDataFormItems(PropertyDescriptorCollection itemProperties, List<DataFormItemBase> dataFormItems)
    {
        var items = new List<DataFormItemBase>();
        foreach (PropertyDescriptor propertyInfo in itemProperties)
        {
            DataFormItem dataFormItem;
            if (propertyInfo.Name == "ContactNumber")
                dataFormItem = new DataFormTextItem() { Name = propertyInfo.Name, Editor = "Text", InputType = Android.Text.InputTypes.ClassNumber };
            else if (propertyInfo.Name == "FirstName")
                dataFormItem = new DataFormTextItem() { Name = propertyInfo.Name, Editor = "Text" };
            else
                dataFormItem = new DataFormTextItem() { Name = propertyInfo.Name, Editor = "Text" };
            items.Add(dataFormItem);
        }

        return items;
    }
}

dataForm.DataObject = new ContactsInfo();
dataForm.ItemManager = new DataFormItemManagerExt(dataForm);

You can download the source code of this demo from GenerateDataFormItemsForDataObject

Manually generate DataFormItems for data dictionary

You can load dataform with custom dictionary by generating DataFormItems manually. To create DataFormItems from dictionary, override the GenerateDataFormItems method.

public class DataFormItemManagerExt : DataFormItemManager
{
    Dictionary<string, object> dataFormDictionary;
    public DataFormItemManagerExt(SfDataForm dataForm, Dictionary<string, object> dictionary) : base(dataForm)
    {
        dataFormDictionary = dictionary;
    }


    protected override List<DataFormItemBase> GenerateDataFormItems(PropertyDescriptorCollection itemProperties, List<DataFormItemBase> dataFormItems)
    {
        var items = new List<DataFormItemBase>();
        foreach (var key in dataFormDictionary.Keys)
        {
            DataFormItem dataFormItem;
            if (key == "ID")
                dataFormItem = new DataFormNumericItem() { Name = key, Editor = "Numeric", MaximumNumberDecimalDigits = 0 };
            else if (key == "Name")
                dataFormItem = new DataFormTextItem() { Name = key, Editor = "Text" };
            else
                dataFormItem = new DataFormTextItem() { Name = key, Editor = "Text" };

            items.Add(dataFormItem);
        }
         
        return items;
    }
}

var dictionary = new Dictionary<string, object>();
dictionary.Add("ID", 1);
dictionary.Add("Name", "John");
dataForm.ItemManager = new DataFormItemManagerExt(dataForm, dictionary);

Loading dataform with dictionary in Xamarin.iOS DataForm

Here, the dataform is loaded with field from dictionary.

Handling reading and writing value to and from dictionary

By default, the dictionary value will be shown in corresponding editor and value changes in editor will be committed again in dictionary value by using the GetValue and SetValue override methods in DataFormItemManager.

Here, value is read and written from/to dictionary instead of data object.

public class DataFormItemManagerExt : DataFormItemManager
{
    Dictionary<string, object> dataFormDictionary;
    public DataFormItemManagerExt(SfDataForm dataForm, Dictionary<string, object> dictionary) : base(dataForm)
    {
        dataFormDictionary = dictionary;
    }

    public override object GetValue(DataFormItem dataFormItem)
    {
        var value = dataFormDictionary[dataFormItem.Name];
        return value;
    }

    public override void SetValue(DataFormItem dataFormItem, object value)
    {
        dataFormDictionary[dataFormItem.Name] = value;
    }

}

You can download the source code of this demo from GenerateDataFormItemsForDictionary