Friday, June 5, 2009

Silverlight 3 DataForm 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!!

Tuesday, June 2, 2009

Silverlight 3.0 Beta and WCF Services

Hi All,

I was just looking at changes from Silverlight 2.0 to Silverlight 3.0 for accessing WCF services. Fantastic !!

First change is introduction of “Binary XML” message transport over http and Second change is introduction of new tool called as “SLsvcUtil.exe” for generating Client Proxy for WCF Service.

Advantages of using Binary XML –:

1) You will see size of the message reduced up to some extend.

2) It is optimized for Speed.

3) Can be effectively used for Binary Large objects.

Important Note – It is not optimized for small messages. It is even not optimized for Strings.

So, I thought let’s prepare a simple Lab manual which will help people to see, Visualize and implement WCF Services in Silverlight 3.0.

Pre-requisites for this Lab are as follows-

1) Silverlight 3.0 must be installed on your machine-

2) For designing optionally you can have Microsoft Expression Blend 3.0 Preview-

3) Visual Studio 2008 or Visual Studio 2010 Beta-

So, let’s get started by -

1) Create Silverlight project by the name “InvokingWCFInSL3”.

2) Now, let’s add a DAL (Data Access Layer) which will allow us to access the data from the Database of your choice. For doing the same I am using my own database which is configured on SQLExpress instance on my machine.

Here I am using ADO.NET Entity Data Model as a DAL (Data Access Layer).

3) First add a new item in the web application with the name “CustomersEDM.edmx” and follow the wizard to configure the database table as shown bellow-

EDMPicture

4) Now, let’s add a WCF Service in the web application with the name “FindCustomer.svc”.You can do the same by adding a “Silverlight- enabled WCF Service” which will automatically do the necessary settings for you in “Web.Config” file which we will see within few minutes.

5) Once you are done, let’s write the Service logic to access the data through the ADO.NET Entity data model by using LINQ as shown bellow-

[OperationContract]
public IEnumerable<CustomerInformation> GetCustomersByCity(string City)
{
CustomersEntities ed=new CustomersEntities();
var query = from c in ed.CustomerInformation
where c.City.Contains(City)
select c;
return query;
}





6) Now as you finished writing WCF Service, let’s browse it by right click to “FindCustomer.svc” and view it in Browser.



7) Now, Let’s see one more new feature of Silverlight 3.0 Beta. In Silverlight 3.0 SDK, you will find a tool called “SLsvcutil.exe” for creating a client proxy. This is a similar tool which people use for generating Client proxy in WCF called “Svcutil.exe”.



Here is a path -



C:\Program Files\Microsoft SDKs\Silverlight\v3.0\Tools



8) So, How to use this tool? Well let’s see- you can see all the options available with SLSvcutil.exe tool by “SLsvcutil.exe /?” command.



For convenience I am making a copy of the tool under C:\Try folder.



9) Open “Visual Studio 2008 command prompt” and change the directory to C:\Try- as shown bellow-



commandprompt







10) Now copy the URL of WCF Service with WSDL and write bellow command on command prompt-



GenerateProxy



So, after pressing enter key, you will see there are two files generated in C:\Try folder.



i) CustomerProxy.cs.



ii) ServiceReferences.ClientConfig.



If you do not give config file name, default config file name is “ServiceReerences.ClientConfig”. I am using default name.



11) Now as you have generated a proxy and configuration file, let’s see our Web application’s Web.Config file. You will see the major change their itself.



WebConfigPict



12) So, here is a custom binding which will allow your SOAP Message to be transported as Binary over http. WOW !!



13) Now let’s copy both the files (CustomerProxy.cs and ServiceReferences.ClientConfig) from C:\Try folder and paste it inside Silverlight application and start writing the code for accessing the proxy as bellow-



14) For showing data in a nice way I have made a small design in “MainPage.xaml” as bellow-




<UserControl 
x:Class="WCFInSL3_WhatIsNew_PartI.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="400" Height="300">
<Grid x:Name="LayoutRoot" Background="Black">
<StackPanel Orientation="Vertical">
<StackPanel Orientation="Horizontal">
<TextBlock x:Name="txtCityLabel"
Text="Enter City -"
FontSize="12"
Foreground="Yellow"
Margin="10"/>
<TextBox x:Name="txtSearchCustomerByCity"
Width="200"
Height="20"/>
<Button x:Name="btnSearch"
Content="Search Customer"
Height="20"
Width="100"
Margin="5,0,0,0"
Click="btnSearch_Click"/>
</StackPanel>

<StackPanel>
<ListBox x:Name="listCustomers"
ItemsSource="{Binding}"
Background="Black">
<ListBox.ItemTemplate>
<DataTemplate>
<Border CornerRadius="10,10,10,10"
BorderThickness="5"
BorderBrush="Yellow"
Background="Green"
Width="380" >
<StackPanel HorizontalAlignment="Left">
<TextBlock Text="{Binding CustomerID}"
Margin="5,0,0,0"
Foreground="Yellow"
FontSize="12"/>
<TextBlock Text="{Binding CustomerName}"
Margin="5,0,0,0"
Foreground="Yellow"
FontSize="12"/>
<TextBlock Text="{Binding Address}"
Margin="5,0,0,0"
Foreground="Yellow"
FontSize="12"/>
</StackPanel>
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</StackPanel>
</StackPanel>
</Grid>
</UserControl>





15) Now let write a code inside “MainPage.xaml.cs” file on button click event which will fetch the data from database for a given city as shown bellow-




public partial class MainPage : UserControl
{
FindCustomerClient proxy = new FindCustomerClient();

public MainPage()
{
InitializeComponent();
proxy.GetCustomersByCityCompleted +=
new EventHandler<GetCustomersByCityCompletedEventArgs>
(proxy_GetCustomersByCityCompleted);
}

void proxy_GetCustomersByCityCompleted(object sender,
GetCustomersByCityCompletedEventArgs e)
{
listCustomers.DataContext = e.Result.ToList();
}



private void btnSearch_Click(object sender, RoutedEventArgs e)
{
proxy.GetCustomersByCityAsync(txtSearchCustomerByCity.Text);
}
}











16) So, you are almost done!! Hit F5 and test your Silverlight application. It should show you the result as bellow -(in my case)



output



And also see the Binary data which is coming from WCF service as bellow. To show this binary data, I am using “Nikhil Kothari’s Web Development Helper Tool”. You may use different tool as per your convenience.



BinaryResponse



17) Now as you have seen, SOAP Binary Message transportation over http, I am just making few changes. Which will show you difference between Silverlight 2.0 and Silverlight 3.0 Beta-



18) Just to demonstrate here, I am doing direct changes in WCF Service’s config file and client side config file.



i) Open Web.Config file from Web application under which out WCF Service is hosted and do following change as shown bellow-




<bindings>
<customBinding>
<binding name="customBinding0">
<!--<binaryMessageEncoding/>-->
<textMessageEncoding/>
<httpTransport/>
</binding>
</customBinding>
</bindings>





ii) Now Open, ServiceReferences.ClientConfig file from Silverlight project and do the following changes as shown bellow-




<bindings>
<customBinding>
<binding name="CustomBinding_FindCustomer">
<!--<binaryMessageEncoding />-->
<textMessageEncoding/>
<httpTransport maxReceivedMessageSize="2147483647"
maxBufferSize="2147483647" />
</binding>
</customBinding>
</bindings>







19) So, Now we are using <textMessageEncoding/> at both the end Server as well as Client, let’s see how the message is transferred to client-



ServiceResponseinText



20) So, That’s All !! Enjoy !!