Editing in Xamarin DataForm (SfDataForm)

The data form supports several built-in editors.

Supported editors and associated DataFormItem

Editor name Editor class Data Type/Attribute Input control loaded
Text

DataFormTextEditor

The String type property and any other type apart from the following specified cases.

Entry

MultilineText

DataFormMultiLineTextEditor

The String type property with multi line text. [DataType(DataType.MultilineText)]

Editor

Numeric

DataFormNumericEditor

The property of Int, Double, Float, Decimal, Long types and also its nullable property.

SfNumericTextBox

Percent

DataFormNumericEditor

The property of Int, Double, Float, Decimal, Long types and also its nullable property with [DataType(“Percent”)] attribute.

SfNumericTextBox

Currency

DataFormNumericEditor

The property of Int, Double, Float, Decimal, Long types and also its nullable property with [DataType(DataType.Currency)] attribute.

SfNumericTextBox

Date

DataFormDateEditor

The DateTime type property and the property with [DataType(DataType.Date)] and [DataType(DataType.DateTime)] attributes.

DatePicker

Time

DataFormTimeEditor

The property with [DataType(DataType.Time)] attribute.

TimePicker

NumericUpDown

DataFormNumericUpDownEditor

Int or Double type property.

SfNumericUpDown

Segment

DataFormSegmentedEditor

Enum type property.

SfSegmentedControl

Bool

DataFormCheckBoxEditor

Bool type property.

SfCheckBox

Switch

DataFormSwitchEditor

Bool type property.

Switch

Picker

DataFormPickerEditor

Enum and List type property. [EnumDataTypeAttribute]

Picker

DropDown

DataFormDropDownEditor

Enum and List type property. [EnumDataTypeAttribute]

SfComboBox

AutoComplete

DataFormAutoCompleteEditor

Enum and List type property. [EnumDataTypeAttribute]

SfAutoComplete

Password

DataFormPasswordEditor

The String type property and property with [DataType(DataType.Password)] attribute.

Entry

RadioGroup

DataFormRadioGroupEditor

Enum and List type property. [EnumDataTypeAttribute]

SfRadioGroup

MaskedEditText

DataFormMaskedEditTextEditor

The property with [DataType(DataType.PhoneNumber)] attribute.

SfMaskedEdit

Changing editor for type

By default, the editors will be loaded based on the previous table. To change the editor for any type, use the RegisterEditor method and specify the type and editor.

dataForm.RegisterEditor(typeof(int), "NumericUpDown");

Here, the NumericUpDown editor will be loaded for the integer type instead of numeric editor.

Changing editor for property

To change the editor for any property, use the RegisterEditor method and specify the property name and editor.

dataForm.RegisterEditor("IsAvailable", "Switch");

Here, the Switch editor will be loaded for the IsAvailable property (bool type) instead of CheckBox editor.

Customizing existing editor

The existing editors defined in the previous table can be customized by overriding the default editors.

Here, the DataFormTextEditor is customized to set different foreground for the FirstName property text editor.

public class CustomTextEditor : DataFormTextEditor
{
    public CustomTextEditor(SfDataForm dataForm) : base(dataForm)
    {
    }

    protected override void OnInitializeView(DataFormItem dataFormItem, Entry view)
    {
        if (dataFormItem.Name == "FirstName")
            view.TextColor = Color.Green;
        base.OnInitializeView(dataFormItem, view);
    }
}

dataForm.RegisterEditor("Text", new CustomTextEditor(dataForm));

Customizing existing editor of data form item in Xamarin.Forms DataForm

Creating new custom editor

Create the custom editor by overriding the DataFormEditor class.

Property settings, commit, data validation can be handled by overriding the required methods. Here, the Entry is loaded for Age editor.

public class CustomTextEditor : DataFormEditor<Entry>
{
	public CustomTextEditor(SfDataForm dataForm) : base(dataForm)
	{
	}

	protected override Entry OnCreateEditorView(DataFormItem dataFormItem)
	{
		return new Entry();
	}
	protected override void OnInitializeView(DataFormItem dataFormItem, Entry view)
	{
		base.OnInitializeView(dataFormItem, view);
		view.Keyboard = Keyboard.Numeric;
		this.OnUpdateValue(dataFormItem, view);
        this.OnUpdateReadOnly(dataFormItem, view);
	}

	protected override void OnWireEvents(Entry view)
	{
		view.TextChanged += OnViewTextChanged;
		view.Focused += OnViewFocused;
		view.Unfocused += OnViewUnfocused;
	}

	private void OnViewPropertyChanged(object sender, PropertyChangedEventArgs e)
	{
		OnValidateValue(sender as Entry);
	}

	private void OnViewFocused(object sender, FocusEventArgs e)
	{
		var view = (sender as Entry);
		view.TextColor = Color.Green;
	}

	protected override bool OnValidateValue(Entry view)
	{
		return this.DataForm.Validate("Age");
	}
	private void OnViewUnfocused(object sender, FocusEventArgs e)
	{
		var view = sender as Entry;
		view.TextColor = Color.Red;

		if (this.DataForm.CommitMode == Syncfusion.XForms.DataForm.CommitMode.LostFocus || this.DataForm.ValidationMode == ValidationMode.LostFocus)
			this.OnValidateValue(view);
		if (this.DataForm.CommitMode != Syncfusion.XForms.DataForm.CommitMode.LostFocus) return;
		this.OnCommitValue(view);
		OnValidateValue(sender as Entry);
	}
	private void OnViewTextChanged(object sender, TextChangedEventArgs e)
	{
		var view = sender as Entry;
		if (DataForm.CommitMode == Syncfusion.XForms.DataForm.CommitMode.PropertyChanged || DataForm.ValidationMode == ValidationMode.PropertyChanged)
			this.OnValidateValue(view);
		if (this.DataForm.CommitMode != Syncfusion.XForms.DataForm.CommitMode.PropertyChanged) return;
		this.OnCommitValue(view);
	}

	protected override void OnCommitValue(Entry view)
	{
		var dataFormItemView = view.Parent as DataFormItemView;
		this.DataForm.ItemManager.SetValue(dataFormItemView.DataFormItem, view.Text);
	}

	 protected override void OnUpdateValue(DataFormItem dataFormItem, Entry view)
    {
        var cellValue = this.DataForm.ItemManager.GetValue(dataFormItem);
        if (cellValue != null && view.Text == cellValue.ToString())
            return;
        view.Text = cellValue == null ? string.Empty : cellValue.ToString();
    }

    protected override void OnUpdateReadOnly(DataFormItem dataFormItem, Entry view)
    {
		base.OnUpdateReadOnly(dataFormItem, view);
    }
	
	protected override void OnUnWireEvents(Entry view)
	{
		view.TextChanged -= OnViewTextChanged;
		view.Focused -= OnViewFocused;
		view.Unfocused -= OnViewUnfocused;
	}
}

dataForm.RegisterEditor("numeric", new CustomTextEditor(dataForm));
dataForm.RegisterEditor("Age", "numeric");
dataForm.ValidationMode = ValidationMode.LostFocus;

You should manually commit the custom DataFormItem editor value by using OnCommitValue override method of DataFormEditor class on custom editor Value or Focus changed event which is used to update the custom editor value in respective property in DataObject based on dataform commit mode set.

Also , you should manually validate the custom editor value in by using OnValidateValue override method of DataFormEditor class on custom editor Value or Focus changed event which is used to validate the custom editor value based on data form validation mode set . In the override method for OnValidateValue, you need to return DataForm.Validate(string) method in order to validate the particular data item.

Also, you should manually update the value to the custom editor by using OnUpdateValue override method of DataFormEditor class on custom editor while bound the value from the Model class.

Creating custom editor for the data form item in Xamarin.Forms DataForm

Support for Email editor

You can load the Email editor by changing KeyBoard type in the AutoGeneratingDataFormItem event.

dataForm.AutoGeneratingDataFormItem += DataForm_AutoGeneratingDataFormItem;
private void DataForm_AutoGeneratingDataFormItem(object sender, AutoGeneratingDataFormItemEventArgs e)
{
    if (e.DataFormItem != null && e.DataFormItem.Name == "Email")
       (e.DataFormItem as DataFormTextItem).KeyBoard = Keyboard.Email;
}

Loading Email editor to the data form item in Xamarin.Forms DataForm

Commit mode

The CommitMode determines when the value should be committed to the data object.

The supported commit modes are as follows:

  • LostFocus
  • PropertyChanged
  • Explicit
<?xml version="1.0" encoding="utf-8" ?>
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:GettingStarted"
             xmlns:dataForm ="clr-namespace:Syncfusion.XForms.DataForm;assembly=Syncfusion.SfDataForm.XForms"
             x:Class="GettingStarted.MainPage">
    <ContentPage.Content>        
            <dataForm:SfDataForm x:Name="dataForm" CommitMode="LostFocus"/>                    
    </ContentPage.Content>
</ContentPage>
dataForm.CommitMode = CommitMode.LostFocus;

LostFocus

If the commit mode is LostFocus, the value is committed when the editor lost its focus.

PropertyChanged

The value will be committed immediately when it is changed.

Explicit

The value should be committed manually by calling the SfDataForm.Commit or SfDataForm.Commit(propertyName) method.

The following code commits the value of all the properties in the data object:

dataForm.Commit();

To commit the specific property value, pass the property name as argument.

dataForm.Commit("Name");

Update editor value based on another editor

You can the update the editor value by using the SfDataForm.UpdateEditor method at runtime.

<?xml version="1.0" encoding="utf-8" ?>
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:GettingStarted"
             xmlns:dataForm ="clr-namespace:Syncfusion.XForms.DataForm;assembly=Syncfusion.SfDataForm.XForms"
             x:Class="GettingStarted.MainPage">
    <ContentPage.Content>        
            <dataForm:SfDataForm x:Name="dataForm"/>                    
    </ContentPage.Content>
</ContentPage>
var expenseInfo = new ExpenseInfo();
expenseInfo.PropertyChanged += ExpenseInfo_PropertyChanged;
dataForm.DataObject = expenseInfo;

private void ExpenseInfo_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
    if (e.PropertyName == "Budget" || e.PropertyName == "Expense")
    {
        var item = sender as ExpenseInfo;
        item.Balance = item.Budget - item.Expense;
        dataForm.UpdateEditor("Balance");               
    }
}

Here, the Balance property value is updated based on Budget and Expense properties. For updating value in editor, the UpdateEditor method is called.

You can download the sample from here.

Converter

To show the original value in different format or as different value, use the Converter attribute.

Changing original value of the DataForm property value using converter

Here, the original value is multiplied by 10 and shown in editor. While committing, it is divided by 10 and stored in the data object.

public class ValueConverterExt : IPropertyValueConverter
{
    public object Convert(object value)
    {            
        var amount = double.Parse(value.ToString());
        return amount * 10;
    }

    public object ConvertBack(object value)
    {
        var amount = double.Parse(value.ToString());
        return amount / 10;
    }
}

private double? amount = 1000;

[Converter(typeof(ValueConverterExt))]
public double? Amount
{
    get
    {
        return amount;
    }
    set
    {
        amount = value;
        RaisePropertyChanged("Amount");
    }
}

Using date editor for DateTimeOffset DataForm property data type

In SfDataForm, you cannot use date editor for DateTimeOffset property data type. To overcome this, you need to use Converter attribute to convert DateTimeOffset to DateTime value and vice-versa.

private DateTimeOffset displayDate;

[Converter(typeof(ValueConverterExt))]
public DateTimeOffset DisplayDate
{
    get
    {
        return displayDate;
    }
    set
    {
        displayDate = value;
    }
}
public class ValueConverterExt : IPropertyValueConverter
{
    public object Convert(object value)
    {
        DateTime baseTime = new DateTime(2008, 6, 19, 7, 0, 0);
        DateTime targetTime;

        var dateTimeOffset = (DateTimeOffset)value;
        dateTimeOffset = new DateTimeOffset(baseTime,
                                            TimeZoneInfo.Local.GetUtcOffset(baseTime));
        targetTime = dateTimeOffset.DateTime;
        return targetTime;
    }
    public object ConvertBack(object value)
    {
        var dateTime = (DateTime)value;
        dateTime = new DateTime(2008, 6, 19, 7, 0, 0);
        dateTime = DateTime.SpecifyKind(dateTime, DateTimeKind.Local);
        DateTimeOffset dateTimeOffset = dateTime;
        return dateTimeOffset;
    }
}

You can download the source code of this demo from here DateTimeOffsetConverter

Disable editing

You can disable editing by setting the IsReadOnly property of the data form.

<?xml version="1.0" encoding="utf-8" ?>
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:GettingStarted"
             xmlns:dataForm ="clr-namespace:Syncfusion.XForms.DataForm;assembly=Syncfusion.SfDataForm.XForms"
             x:Class="GettingStarted.MainPage">
    <ContentPage.Content>        
            <dataForm:SfDataForm x:Name="dataForm" IsReadOnly="True"/>                    
    </ContentPage.Content>
</ContentPage>
dataForm.IsReadOnly = true;

You can also change the editing behavior by setting the IsReadOnly property of the DataFormItem.

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;
    }
}

You can also change the editing behavior at runtime.

private void Button_Click(object sender, System.EventArgs e)
{
    var dataFormItem = dataForm.ItemManager.DataFormItems["FirstName"];
    dataFormItem.IsReadOnly = true;
}

NOTE

DataFormItem.IsReadOnly takes higher priority than SfDataForm.IsReadOnly.

Two-way data binding

When the DataForm business object properties are updated with two-way data binding support, the value will sync with underlying DataForm editors.

To enable two-way data binding support, set the value of NotifyPropertyChanges property to true in DataForm.

<?xml version="1.0" encoding="utf-8" ?>
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:GettingStarted"
             xmlns:dataForm ="clr-namespace:Syncfusion.XForms.DataForm;assembly=Syncfusion.SfDataForm.XForms"
             x:Class="GettingStarted.MainPage">
    <ContentPage.Content>        
            <dataForm:SfDataForm x:Name="dataForm" NotifyPropertyChanges="True"/>                    
    </ContentPage.Content>
</ContentPage>
dataForm.NotifyPropertyChanges = true;

You can download the entire source code of this demo from here Two-wayDataBinding