Working with DataForm in Xamarin DataForm (SfDataForm)
26 Sep 202324 minutes to read
Auto-generating DataFormItems for the data field
By default, the DataFormItems will be generated based on the property type. For example, the DataFormNumericItem will be created for the int
type property.
The DataFormItem generation depends on the type and attribute defined for the property.
The following tables lists the several types of DataFormItem
and its constraints for auto generation:
Generated DataFormItem Type | Editor | Data Type / Attribute |
---|---|---|
Text | Default DataFormItem generated for the String type and the properties with [DataType(DataType.Text)], [DataType(DataType.MultilineText)] and [DataType(DataType.Password)] attributes. | |
Numeric | Generated for Int, Double, Float, Decimal, Long types and also its nullable property with [DataType(DataType.Currency)] and [DataType("Percent")] attributes. | |
Date | Generated for DateTime type and properties with [DataType(DataType.Date)] and [DataType(DataType.DateTime)] attributes. | |
Time | Generated for the property with [DataType(DataType.Time)] attribute. | |
Picker | Generated for Enum type property and the property with [EnumDataTypeAttribute] attribute. | |
DropDown | Generated for Enum type property and the property with [EnumDataTypeAttribute] attribute. | |
AutoComplete | Generated for Enum type property and the property with [EnumDataTypeAttribute] attribute. | |
MaskedEditText | Generated for the PhoneNumber type property. [DataType(DataType.PhoneNumber)] | |
CheckBox | Bool type |
You can customize the property settings or cancel the generation of DataFormItem
by handling the AutoGeneratingDataFormItem event.
Customize auto generated fields
You can customize or cancel the generated DataFormItem
by handling the AutoGeneratingDataFormItem event. This event occurs when the field is auto-generated for public and non-static property of the data object.
<?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" AutoGeneratingDataFormItem="DataForm_AutoGeneratingDataFormItem"/>
</ContentPage.Content>
</ContentPage>
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 the data field
You can cancel the specific DataFormItem adding to the data form by handling the AutoGeneratingDataFormItem
event or by defining display attribute to avoid the particular data field being displayed.
Using attributes
You can set AutoGenerateField to false
for canceling the DataFormItem
generation.
private int id;
[Display(AutoGenerateField = false)]
public int ID
{
get
{
return id;
}
set
{
id = value;
RaisePropertyChanged("ID");
}
}
Using event
In the following code, the DataFormItem
generation for the MiddleName
property is canceled by setting the 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 the DataFormItem in the AutoGeneratingDataFormItem
event.
In the following code, the editor is changed for IsAvailable
field from Bool
to Switch
.
dataForm.AutoGeneratingDataFormItem += DataForm_AutoGeneratingDataFormItem;
private void DataForm_AutoGeneratingDataFormItem(object sender, AutoGeneratingDataFormItemEventArgs e)
{
if (e.DataFormItem.Name == "IsAvailable")
e.DataFormItem.Editor = "Switch";
}
Changing property settings
You can change the property of DataFormItem in the AutoGeneratingDataFormItem
event.
Here, Salary
data field is restricted from being edited in the data form.
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;
}
}
Changing DataFormItem visibility
You can change the DataFormItem visibility by using the IsVisible property in the DataFormItem
.
Here, Salary
data field will be hidden.
dataForm.AutoGeneratingDataFormItem += DataForm_AutoGeneratingDataFormItem;
private void DataForm_AutoGeneratingDataFormItem(object sender, AutoGeneratingDataFormItemEventArgs e)
{
if (e.DataFormItem != null)
{
if (e.DataFormItem.Name == "Salary")
e.DataFormItem.IsVisible = false;
}
}
Changing DataFormItem FontSize
Using the EditorFontSize, LabelFontSize, and ValidationLabelFontSize properties from DataFormItem
, you can define the font size of the Editor
, Label
, and ValidationLabel
. Changing the font size will be handled in the AutoGeneratingDataFormItem
event.
You can define the font size as described as follows.
- Set the value to font size directly or use the named font sizes such as
Small
,Medium
, andLarge
.
dataForm.AutoGeneratingDataFormItem += DataForm_AutoGeneratingDataFormItem;
private void DataForm_AutoGeneratingDataFormItem(object sender,AutoGeneratingDataFormItemEventArgs e)
{
if (e.DataFormItem != null)
{
// Setting Fontsize using NamedSize.
e.DataFormItem.EditorFontSize = Device.GetNamedSize(NamedSize.Small, typeof(Label));
e.DataFormItem.LabelFontSize = Device.GetNamedSize(NamedSize.Large, typeof(Label));
e.DataFormItem.ValidationLabelFontSize = Device.GetNamedSize(NamedSize.Micro, typeof(Label));
// Setting value to FontSize directly.
e.DataFormItem.EditorFontSize = 8;
e.DataFormItem.LabelFontSize = 8;
e.DataFormItem.ValidationLabelFontSize = 8;
}
}
Setting watermark
You can display the watermark in the editor by defining the display attribute or using theAutoGeneratingDataFormItem
event.
Using attribute
You can show the watermark in the editor by setting the 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 the watermark in the editor by using the 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 the created DataFormItem and assign new DataFormItem
in the AutoGeneratingDataFormItem event.
Here, DataFormTextItem with number keyboard is 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", KeyBoard = Keyboard.Numeric };
}
}
Adding or removing the data field displayed in the dataForm at runtime
If you want to remove or add data fields item at runtime, you can use the RefreshLayout method which auto-generates the DataFormItem where you can skip certain item from display. By default, it will generate the canceled items initially. If you want to regenerate all the items, you should pass argument as true
.
In the following 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 the data form 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>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<dataForm:SfDataForm Grid.Row="0" x:Name="dataForm" AutoGeneratingDataFormItem="DataForm_AutoGeneratingDataFormItem"/>
<Button x:Name="Commit" Grid.Row="1" WidthRequest="100" HeightRequest="50" Text="MORE FIELDS" Clicked="Button_Clicked"/>
</Grid>
</ContentPage.Content>
</ContentPage>
dataForm.DataObject = new ContactsInfo();
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;
}
}
}
If you want to generate the MiddleName and LastName fields at runtime, you should set refreshLayout
flag to true
and call the RefreshLayout method which triggers AutoGeneratingDataFormItem
event again and generates the items based on refreshLayout
flag.
private void Button_Click(object sender, System.EventArgs e)
{
refreshLayout = true;
dataForm.RefreshLayout();
}
Here, the MiddleName and LastName fields are generated at runtime after clicking the more field button.
TheGroupName
field is displayed initially in the data form. If you want to remove it at runtime, you should set refreshLayout flag to true and pass the argument as true inRefreshLayout method. It triggers AutoGeneratingDataFormItem
event for all the fields where you can cancel `GroupName’ field item generation.
private void Button_Click(object sender, System.EventArgs e)
{
refreshLayout = true;
dataForm.RefreshLayout(true);
}
Here, the GroupName field is removed at runtime.
You can download the sample from here
DataFormItemManager
The DataFormItemManager creates DataFormItems collection and handles value reflection and validation. It also overrides to handle the get and set property values from and to the data object.
Manually generate DataFormItems for DataObject
By default, DataFormItems will be generated based on DataObject. If you need to generate DataFormItems
manually, override the DataFormItemManager class and set it to SfDataForm.ItemManager.
To create DataFormItems
, override the GenerateDataFormItems method.
// dataform item creating by setting DataObject.
dataForm.DataObject = new ContactsInfo();
dataForm.ItemManager = new DataFormItemManagerExt(dataForm);
public class DataFormItemManagerExt : DataFormItemManager
{
SfDataForm sfDataForm;
public DataFormItemManagerExt(SfDataForm dataForm) : base(dataForm)
{
sfDataForm = dataForm;
}
protected override List<DataFormItemBase> GenerateDataFormItems(PropertyInfoCollection itemProperties, List<DataFormItemBase> dataFormItems)
{
var items = new List<DataFormItemBase>();
foreach (var propertyInfo in itemProperties)
{
DataFormItem dataFormItem;
if (propertyInfo.Key == "ID")
dataFormItem = new DataFormNumericItem() { Name = propertyInfo.Key, Editor = "Numeric", MaximumNumberDecimalDigits = 0 };
else if (propertyInfo.Key == "Name")
dataFormItem = new DataFormTextItem() { Name = propertyInfo.Key, Editor = "Text" };
else
dataFormItem = new DataFormTextItem() { Name = propertyInfo.Key, Editor = "Text" };
items.Add(dataFormItem);
}
return items;
}
}
You can download the source code of this demo from GenerateDataFormItemsForDataObjects
Manually generate DataFormItems for data dictionary
You can load the dataform with custom dictionary by generating DataFormItems manually. To create DataFormItems
from dictionary, override the GenerateDataFormItems method.
// dataform item creating using dictionary.
dataForm.DataObject = new object();
var dictionary = new Dictionary<string, object>();
dictionary.Add("ID", 1);
dictionary.Add("Name", "John");
dataForm.ItemManager = new DataFormItemManagerExt(dataForm, dictionary);
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(PropertyInfoCollection 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;
}
}
Handling reading and writing values to and from the 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, the value is read and written from/to dictionary instead of the 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;
}
}
Here, the dataform is loaded with field from dictionary.
You can download the source code of this demo from GenerateDataFormItemsForDictionary
Binding with dynamic data object
You can also load the dynamic object in SfDataForm DataObject
and by default text editor will be generated for each dynamic object property. You can change the editor of DataFormItem for dynamic object property data type (default string) by using the AutoGeneratingDataFormItem event. You can find details about this here
Limitations
DynamicObject supports only in Xamarin.Forms Android and data form item will be created for each dynamic object property. Currently Dynamic object is not supported in UWP and iOS platform and you can find more details about this for iOS platform under the following links.
https://forums.xamarin.com/discussion/53941/expandoobject-crashing-ios
https://learn.microsoft.com/en-us/xamarin/ios/internals/limitations
dataForm.DataObject =new DynamicDataModel().ExpandoObject;
dataForm.AutoGeneratingDataFormItem += DataForm_AutoGeneratingDataFormItem;
private void DataForm_AutoGeneratingDataFormItem(object sender, AutoGeneratingDataFormItemEventArgs e)
{
if (e.DataFormItem != null && e.DataFormItem.Name == "DateOfBirth")
e.DataFormItem.Editor = "Date";
}
public class DynamicDataModel
{
public dynamic ExpandoObject;
public dynamic DynamicObject;
public DynamicDataModel()
{
ExpandoObject = new ExpandoObject();
ExpandoObject.FirstName = "John";
ExpandoObject.LastName = "";
ExpandoObject.DateOfBirth = DateTime.Now.Date;
ExpandoObject.Email = "";
DynamicObject = new Data();
DynamicObject.FirstName = "John";
DynamicObject.LastName = "";
DynamicObject.DateOfBirth = DateTime.Now.Date;
DynamicObject.Email = "";
}
}
public class Data : DynamicObject, IDictionary<string, object>
{
Dictionary<string, object> list = new Dictionary<string, object>();
public override bool TrySetMember(SetMemberBinder binder, object value)
{
list[binder.Name] = value;
return true;
}
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
return list.TryGetValue(binder.Name, out result);
}
public override IEnumerable<string> GetDynamicMemberNames()
{
return list.Keys;
}
public void Add(string key, object value)
{
this.list.Add(key, value);
}
public bool ContainsKey(string key)
{
return this.list.ContainsKey(key);
}
public ICollection<string> Keys
{
get { return this.list.Keys; }
}
public bool Remove(string key)
{
return this.list.Remove(key);
}
public bool TryGetValue(string key, out object value)
{
return this.list.TryGetValue(key, out value);
}
public ICollection<object> Values
{
get { return this.list.Values; }
}
object IDictionary<string, object>.this[string key]
{
get { return this.list[key]; }
set { this.list[key] = value; }
}
public void Add(KeyValuePair<string, object> item)
{
this.list.Add(item.Key, item.Value);
}
public void Clear()
{
this.list.Clear();
}
public bool Contains(KeyValuePair<string, object> item)
{
return this.list.Contains(item);
}
public void CopyTo(KeyValuePair<string, object>[] array, int arrayIndex)
{
}
public int Count
{
get { return this.list.Count; }
}
public bool IsReadOnly
{
get { return false; }
}
public bool Remove(KeyValuePair<string, object> item)
{
return this.list.Remove(item.Key);
}
public IEnumerator<KeyValuePair<string, object>> GetEnumerator()
{
return this.list.GetEnumerator();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return this.list.GetEnumerator();
}
}
You can download the sample from here
Adding custom DataFormItems
Support has been provided to generate custom DataFormItems for the defined business model using the Items property of the SfDataForm
class. You need to set the AutoGenerateItems property to false to restrict the auto generation of DataFormItems.
<?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.BindingContext>
<local:ViewModel x:Name="bindingContext"/>
</ContentPage.BindingContext>
<ContentPage.Content>
<dataForm:SfDataForm x:Name="dataForm" DataObject="{Binding Details}" AutoGenerateItems="false">
<dataForm:SfDataForm.Items>
<dataForm:DataFormTextItem Name="Name" Editor="Text"/>
<dataForm:DataFormTextItem Name="Password" Editor="Password"/>
<dataForm:DataFormMaskedEditTextItem Name="Phone" Editor="MaskedEditText"/>
<dataForm:DataFormTextItem Name="Address" Editor="MultilineText"/>
<dataForm:DataFormAutoCompleteItem Name="Countries" Editor="AutoComplete" ItemsSource = "{Binding CountryNames}"/>
<dataForm:DataFormDateItem Name="BirthTime" Editor="Date"/>
</dataForm:SfDataForm.Items>
</dataForm:SfDataForm>
</ContentPage.Content>
</ContentPage>
ObservableCollection<DataFormItemBase> items = new ObservableCollection<DataFormItemBase>();
items.Add(new DataFormTextItem() { Name = "Name", Editor = "Text" });
items.Add(new DataFormTextItem() { Name = "Password", Editor = "Password" });
items.Add(new DataFormMaskedEditTextItem() { Name = "Phone", Editor = "MaskedEditText" });
items.Add(new DataFormTextItem() { Name = "Address", Editor = "MultilineText" });
items.Add(new DataFormAutoCompleteItem() { Name = "Countries", Editor = "AutoComplete", ItemsSource = this.GetItemSource("Countries")});
items.Add(new DataFormTimeItem() { Name = "BirthTime", Editor = "Time" });
dataForm.AutoGenerateItems = false;
dataForm.Items = items;
public class ViewModel
{
private DataFormModel details;
private IList<string> countryNames;
public ViewModel()
{
details = new DataFormModel();
countryNames = new List<string>
{
"United states",
"United Kingdom",
"France",
"Belgium",
"Germany"
};
}
public DataFormModel Details
{
get { return this.details; }
set { this.details = value; }
}
public IList<string> CountryNames
{
get { return this.countryNames; }
set { this.countryNames = value; }
}
}
private IList GetItemSource(string sourceName)
{
var list = new List<string>();
if (sourceName == "Countries")
{
list.Add("Afghanistan");
list.Add("Akrotiri");
list.Add("Albania");
list.Add("Algeria");
list.Add("American Samoa");
list.Add("Andorra");
list.Add("Angola");
list.Add("Anguilla");
list.Add("Antarctica");
list.Add("Antigua and Barbuda");
}
return list;
}
Dynamically add custom dataform items
Support has been provided to dynamically add the dataform items to collections using the Items property of SfDataForm
.
dataForm.Items.Add(new DataFormDropDownItem()
{ Name = "StateName",
Editor = "DropDown",
ItemsSource = this.GetItemSource("StateName"),
PlaceHolderText = "Select a State"
});
dataForm.Items.Add(new DataFormItem()
{ Name = "Save",
Editor = "Switch"
});
Dynamically remove custom dataform items
Support has been provided to dynamically remove the dataform items from collections using the Items property of SfDataForm
.
dataForm.Items.RemoveAt(2);
Dynamically clear custom dataform items
Support has been provided to dynamically clear the dataform items using the Items property of SfDataForm
.
dataForm.Items.Clear();
Dynamically reset custom dataform items
Support has been provided to reset the dataform items using the Items property of SfDataForm
.
var item = dataForm.Items[2];
item = new DataFormNumericUpDownItem() { Name = "Age", Editor = "NumericUpDown" };
dataForm.Items[2] = item;
Dynamically add custom dataform group items
Support has been provided to dynamically add custom group items using Items property of SfDataForm
.
DataFormGroupItem dataFormGroupItem = new DataFormGroupItem();
dataFormGroupItem.GroupName = "GroupItem";
dataFormGroupItem.IsExpanded = true;
dataFormGroupItem.DataFormItems = new DataFormItems();
dataFormGroupItem.DataFormItems.Add(new DataFormTextItem() { Name = "First Name", Editor = "Text", GroupName = "GroupItem" });
dataFormGroupItem.DataFormItems.Add(new DataFormTextItem() { Name = "Middle Name", Editor = "Text", GroupName = "GroupItem" });
dataFormGroupItem.DataFormItems.Add(new DataFormTextItem() { Name = "Last Name", Editor = "Text", GroupName = "GroupItem" });
dataForm.Items.Add(dataFormGroupItem);