Tuesday, July 7, 2009

Silverlight 3 DataFrom Control

Hi All,

As I have create a small Lab Manual for Changes in Accessing WCF Service in Silverlight 3.0 , I am starting with DataForm Control introduced in Silverlight 3.0 Beta to design a Rich Data Forms for Business applications.

So Let’s get started then !!

1) Create a Silverlight Application with the Name “SL3DataForm_CompleteDemo”.

2) To work with DataForm control we will have to add few references to our Silverlight Project as shown bellow-

System.ComponentModel
System.ComponentModel.Annotation
System.Windows.Controls.Data.DataForm

3) Once you add a the references, let’s add a Class in Silverlight Project with the name “Customer.cs” and add few properties as shown bellow-

public class Customer
{
public string CustomerID { get; set; }
public string CustomerName { get; set; }
public string Address { get; set; }
public string City { get; set; }
public string DOB { get; set; }
public string ContactName { get; set; }
public int ContactNo { get; set; }
public string State { get; set; }
public string Country { get; set; }
public string WebSiteURL { get; set; }
}





4) Now we will have to make few changes in MainPage.xaml file in order to call our Customer class in XAML as well as use the DataForm control as shown bellow-




1: xmlns:dataFrm="clr-namespace:System.Windows.Controls;
assembly=System.Windows.Controls.Data.DataForm"
2: xmlns:local="clr-namespace:SL3DataForm_CompleteDemo"





Add the above two namespaces in the UserControl Element. First namespace will allow us to use DataForm control and Second namespace will allow us to use Customer class as a resource in our MainPage.xaml.



5) Now let’s add the code in MainPage.xaml file as shown bellow-




<UserControl x:Class="SL3DataForm_CompleteDemo.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="400" Height="400"
xmlns:dataFrm="clr-namespace:System.Windows.Controls;
assembly=System.Windows.Controls.Data.DataForm"

xmlns:local="clr-namespace:SL3DataForm_CompleteDemo">
<UserControl.Resources>
<local:Customer x:Key="myCustomerDetails"
CustomerID="PRAV"
CustomerName="Pravinkumar R. D."
Address="Sinhgad Road,Pune"
DOB="21/Oct/1977"
ContactName="Pravin"
ContactNo="828992892"
City="Pune"
State="Maharashtra"
Country="India"
WebSiteURL="http://pkrd.blogspot.com"/>
</UserControl.Resources>
<Grid x:Name="LayoutRoot" Background="White">
<dataFrm:DataForm x:Name="CustomerForm"
CurrentItem="{StaticResource myCustomerDetails}"
Background="Black"
Header="Customer Entry Form"
CommitButtonContent="Save This Customer"/>
</Grid>
</UserControl>









In the above code, Customer class is getting utilized as Resource and DataForm control is using this resource by a property called “CurrentItem”. So, If you observe, you will see the current item of the resource is getting displayed in the DataForm.



6) Hit F5 and see the result.



clip_image002



7) Click the Edit Button highlited by RED colour and make changes.



8) Now let’s make few changes in a class called “Customer” as shown bellow-




a. First import a namespace as shown bellow-





using System.ComponentModel





b. This namespace will provide an attribute which will decide wherther the class is Bindable or not. As well if the class is Bindable, then what kind of binding it should support? It is decided by BindingDirection. By default it is OneWay-





          i. OneWay.





         ii. TwoWay.





c. When you don’t want your class to be Bindable with DataForm Control, apply attribute to a class called [Bindable(false)].



d. When you want to bind your class to be Bindable with DataForm and it should be in ReadOnly format, then apply attribute to a class called [Bindable(true,BindingDirection.OneWay)].



e. You can apply the same attrtibute to the properties of your class with all above parameters as shown bellow-



f. Apply [Bindable(false)] attribute to the property called Country in our customer class. Hit F5 and you will see that the Country is not shown in our DataForm.



g. Now, Apply [Bindable(true,BindingDirection.OneWay)] attribute to the property called Country in our customer class and [Bindable(true,BindingDirection.TwoWay)] to the class. Hit F5 and you will see that the Country is not Editable in our DataForm.



h. Now you got an idea how this can be used, please try out with multiple combinations.




9) Now as you have tried possible options, let move ahead and see some other options which are available with DataForm.



10) One thing if you observe, when you Edit the form, you can not see the “Cancel Button”. So the question is what if I want to give Save as well as Cancel option? So, let’s give both the options.



11) In order to get Cancel functionality, you will have to implement an Interface called, “IEditableObject”.



IEditableObject : This interface provides the functionality to either Save the changes or Rollback the changes to the object which is used as a Data Source.



12) So, Let’s implement the interface called “IEditableObject” in our Customer class and write a code for the same-



Now, let’s see the class code -



i) I have added one property to my Customer Class by the Name “Status”. This will show the status of the record whether it is “Edited” Or “Committed” Or “Roll backed”.



So, the class code after implementing IEditableObject Interface will look like bellow-




[Bindable(true, BindingDirection.TwoWay)]
public class Customer:IEditableObject
{
public string CustomerID { get; set; }
public string CustomerName { get; set; }
public string Address { get; set; }
public string City { get; set; }
public string DOB { get; set; }
public string ContactName { get; set; }
public int ContactNo { get; set; }
public string State { get; set; }
public string Country { get; set; }
public string WebSiteURL { get; set; }
[Bindable(true,BindingDirection.OneWay)]
public string Status { get; set; }

#region IEditableObject Members

public void BeginEdit()
{
Status = "Customer is in Edit Mode !!";
}

public void CancelEdit()
{
Status = "Edit has been cancelled??";
}

public void EndEdit()
{
Status = "Customer Record is Commited";
}

#endregion
}





13) Now One more change which we will do is instead of binding single item we will bind collection of customers with our DataForm and will see how DataForm can handle it implicitly. For that let Write a code in MainPage.xaml.cs file as follows-




public partial class MainPage : UserControl
{
ObservableCollection<Customer> customerCollection;
public MainPage()
{
InitializeComponent();
this.Loaded += new RoutedEventHandler(MainPage_Loaded);
}

void MainPage_Loaded(object sender, RoutedEventArgs e)
{
customerCollection = new ObservableCollection<Customer>()
{
new Customer()
{
CustomerID="PRAV",
CustomerName="Pravinkumar R. D.",
Address="Sinhgad Road,Pune",
DOB="21/Oct/1977",
ContactName="Pravin",
ContactNo=828992892,
City="Pune",
State="Maharashtra",
Country="India",
WebSiteURL="http://pkrd.blogspot.com"
},
new Customer()
{
CustomerID="YASH",
CustomerName="Yash P. D.",
Address="Sinhgad Road,Pune",
DOB="22/Sept/2005",
ContactName="Yash",
ContactNo=828996792,
City="Pune",
State="Maharashtra",
Country="India",
WebSiteURL="http://www.yash.com"
},
new Customer()
{
CustomerID="MAND",
CustomerName="Mandar M.",
Address="Karve Road,Pune",
DOB="21/Aug/1979",
ContactName="Mandar",
ContactNo=828994592,
City="Pune",
State="Maharashtra",
Country="India",
WebSiteURL="http://www.mandar.com"
},
new Customer()
{
CustomerID="PRIT",
CustomerName="Priti P. D.",
Address="Sinhgad Road,Pune",
DOB="06/Mar/1980",
ContactName="Priti",
ContactNo=828923892,
City="Pune",
State="Maharashtra",
Country="India",
WebSiteURL="http://priti.blogspot.com"
},
new Customer()
{
CustomerID="AVIN",
CustomerName="Avinash D.",
Address="Baner Road,Pune",
DOB="1/Jun/1977",
ContactName="Avinash",
ContactNo=828992892,
City="Pune",
State="Maharashtra",
Country="India",
WebSiteURL="http://avi.blogspot.com"
},
};
LayoutRoot.DataContext = customerCollection;
}
}







14) Once you are done, let’s make a small change to access this customers collection in our DataForm as follows-




<dataFrm:DataForm x:Name="CustomerForm" 
ItemsSource="{Binding}"
Background="Black"
Header="Customer Entry Form"
CommitButtonContent="Save This Customer"
CancelButtonContent="Cancel This Save" />







In the above code, instead of CurrentItem property we are using ItemSource property to be Bindable with the DataContext which we have set to our LayoutRoot that is Grid Panel.



15) Now as you have finished with changes, let’s Hit F5 and see the result !!



OutPut2



If you see the output,



i) DataForm will automatically provide a navigation facility for collection of records.



ii) As you Edit the Record, “BeginEdit” method will get fired where we have written our logic for notification.



iii) And now you can see the “Cancel” Button which will allow us to Rollback the changes.



16) Now Let’s see other features. Let’s open Customer class and give some nice titles to our Fields as shown bellow-



To do this first import a namespace -




using System.ComponentModel.DataAnnotations;





To give titles to our fields we are going to use an attribute called “Display”You can pass multiple parameters to this attributes. We will try to use few of them here-




[Display(Name="Customer ID",
Description="This is for Customer ID",Order=1)]
public string CustomerID { get; set; }
[Display(Name = "Customer Name",
Description = "This is for Customer Name", Order = 2)]
public string CustomerName { get; set; }
[Display(Name = "Customer Address",
Description = "This is for Customer Address", Order = 3)]
public string Address { get; set; }
[Display(Name = "Customer City",
Description = "This is for Customer City", Order = 4)]
public string City { get; set; }
[Display(Name = "Date of Birth",
Description = "This is Customer ID", Order = 7)]
public string DOB { get; set; }
[Display(Name = "Contact Name",
Description = "This is for Customer Contact Person", Order = 5)]
public string ContactName { get; set; }
[Display(Name = "Contact No.",
Description = "This is for Customer Contact No.", Order = 6)]
public int ContactNo { get; set; }
[Display(Name = "State",
Description = "This is for Customer State", Order = 8)]
public string State { get; set; }
[Display(Name = "Country",
Description = "This is for Customer Country", Order = 9)]
public string Country { get; set; }
[Display(Name = "Customer WebSite",
Description = "This is for Customer Web Site", Order = 10)]
public string WebSiteURL { get; set; }
[Display(Name = "Record Status",
Description = "This is for Customer Record Status", Order = 11)]
[Bindable(true,BindingDirection.OneWay)]
public string Status { get; set; }





17) Attributes which we are using are-



i) Name – To display title of the field.



ii) Description – Details description about the field.



iii) Order – In which order the Form should display fields.



18) Hit F5 and see the result-



OutPut3



19) Now let’s Validate our field data by different ways provided by different attributes like-



i) RegularExpression – Can be used to validate formats for string, integer, date, time and many more  Let’s apply this Validator to our property called WebSiteURL as shown bellow-




[Display(Name = "Customer WebSite",
Description = "This is for Customer Web Site", Order = 10)]
[RegularExpression(@"http(s)?://([\w-]+\.)+[\w-]+(/[\w- ./?%&=]*)?",
ErrorMessage="URL of the site is not valide?")]
public string WebSiteURL { get; set; }





ii) Range – Can be used to specify range between. For example, Age should be between 1 to 99 or Salary should be between 3000-10000. Let’s apply this Validator to our ContactNo (Just to show example!!) as shown bellow-



[Display(Name = "Contact No.", 
Description = "This is for Customer Contact No.", Order = 6)]
[Range(1,50000,ErrorMessage="No. should not be more than 50000??")]
public int ContactNo { get; set; }





iii) Required – To make fields Mandatory.  Let’s apply this Validator to multiple fields as shown bellow-




[Display(Name="Customer ID",Description="This is for Customer ID",Order=1)]
[Required(ErrorMessage="CustomerID is a required field")]
public string CustomerID { get; set; }
[Required(ErrorMessage = "Customer Name is a required field")]
[Display(Name = "Customer Name",
Description = "This is for Customer Name", Order = 2)]
public string CustomerName { get; set; }





iv) StringLength- Can be applied to string for checking the length.  Let’s apply this validator to CustomerID property as shown bellow-




[Display(Name="Customer ID",Description="This is for Customer ID",Order=1)]
[Required(ErrorMessage="CustomerID is a required field")]
[StringLength(4,ErrorMessage="Customer ID should
not exceed more than 4 charaters"
)]
public string CustomerID { get; set; }





v) Enum Datatype-



vi) CustomValidator – You can apply this to a complete class or a specific field. Let’s apply this validator to City property as shown bellow-



First write a Customer Validator class as bellow-




public class CustomerValidation
{
public static bool ValidateCity(string City)
{
return true;
}
}



Then Apply this to City Property



[Display(Name = "Customer City",
Description = "This is for Customer City", Order = 4)]
[CustomValidation(typeof(CustomerValidation), "ValidateCity")]
public string City { get; set; }





OR you can do it Normal way also. Look at the bellow code-




[Display(Name = "Contact No.", 
Description = "This is for Customer Contact No.", Order = 6)]
[Range(1, 5000, ErrorMessage = "Telephone No. should not cross 10 digits??")]
public int ContactNo
{
get
{
return _ContactNo;
}
set
{
if (value <= 0)
throw new ArgumentException("Contact No.
must be greater than Zero"
);
_ContactNo = value;
}
}





DataForm will capture the above exception as well.



20) Hit F5 !! and test the result !!



OutPut4



21) Now as we are done with Validation, Let’s do few Customization with DataForm. The code is as bellow-




<Grid x:Name="LayoutRoot" Background="White">
<StackPanel Orientation="Vertical">
<dataFrm:DataForm x:Name="CustomerForm"
ItemsSource="{Binding}"
Background="Pink"
Header="Customer Entry Form"
CommitButtonContent="Save This Customer"
CancelButtonContent="Cancel This Save"
Foreground="Black"
AutoGenerateFields="False"
>
<dataFrm:DataForm.Fields>
<dataFrm:DataFormTextField FieldLabelContent="Customer ID"
Binding="{Binding CustomerID}"/>
<dataFrm:DataFormTextField FieldLabelContent="Customer Name"
Binding="{Binding CustomerName}"/>
<dataFrm:DataFormTextField FieldLabelContent="Customer Address"
Binding="{Binding Address}"/>
<dataFrm:DataFormTemplateField FieldLabelContent="Birth Date" >
<dataFrm:DataFormTemplateField.DisplayTemplate>
<DataTemplate>
<TextBlock Text="{Binding DOB}"/>
</DataTemplate>
</dataFrm:DataFormTemplateField.DisplayTemplate>
<dataFrm:DataFormTemplateField.EditTemplate>
<DataTemplate>
<TextBox Text="{Binding DOB}"/>
</DataTemplate>
</dataFrm:DataFormTemplateField.EditTemplate>
</dataFrm:DataFormTemplateField>
<dataFrm:DataFormTextField FieldLabelContent="Contact Name"
Binding="{Binding ContactName}"/>
<dataFrm:DataFormTextField FieldLabelContent="Contact No."
Binding="{Binding ContactNo}"/>
<dataFrm:DataFormTextField FieldLabelContent="City"
Binding="{Binding City,Mode=TwoWay}"/>
<dataFrm:DataFormTextField FieldLabelContent="State"
Binding="{Binding State,Mode=TwoWay}"/>
<dataFrm:DataFormTextField FieldLabelContent="Country"
Binding="{Binding Country,Mode=TwoWay}"/>
<dataFrm:DataFormTextField FieldLabelContent="WebSite URL"
Binding="{Binding WebSiteURL}"/>
<dataFrm:DataFormTextField FieldLabelContent="Notification"
Binding="{Binding Status}"/>
</dataFrm:DataForm.Fields>
</dataFrm:DataForm>
</StackPanel>
</Grid>





22) Too Many things !! So, Let’s start looking at each thing one by one-















1) If you want, you can customize the complete DataForm Template as per you specifications. For that DataForm will give you couple of controls. You can even change/Customize the Edit, Insert templates as well.



So, to generate your own fields you have to set DataForm property called “AutoGenerateFields=False”. Once you do that, DataForm will not not show the default template with default fields.



Now, you can use bellow listed fields for designing your own template or you can use standard Silverlight controls as a “Data template”.



1) DataFormTextField- This field will render a TextBox under DataForm.



2) DataFormCheckBoxField – This field will render a CheckBox under DataForm.



3) DataFormComboBoxField – This field will render a ComboBox under DataForm.



4) DataFormDateField – This field will render a calendar under DataForm.



5) DataFormTemplateField – This field will allow you to design your template.



There are many more features available in DataForm.



I will try to capture these features and will come back with other set of labs-



Till the time Enjoy!!

No comments:

Post a Comment