Showing posts with label Silverlight. Show all posts
Showing posts with label Silverlight. Show all posts

Tuesday, November 26, 2013

Optimize the size of xap file an easy way.

Your silverlight projects .xap file is getting bigger, this happens because of some assembly issues. And ofcourse there are some ways to optimize it.

http://blogs.telerik.com/miromiroslavov/posts/10-09-15/5-ways-to-reduce-your-xap-size.aspx

The above article shows few popular ways to reduce the size of xap file.

I had a xap file what was almost 4 mb in size. so I decided to do some optimization.

First thing i did is to remove all unused references and control references. fortunately resharper has some good feature on this. I right clicked on the project and selected “Optimize Reference” and removed all unnecessary references.

Now my xap file is reduce to 1.6 mb. that is almost 200% reduced. awesome.

image

Next there are some option for assembly caching, if you go you the silverlight tab of the project you would see that there is a checkbox for “Reduce XAP size by using…….” Just check it and recompile it. 

image

Next what happen is all the other assemblies that is been used are zipped and added in client bin folder. and reduce the xap file size to negligible.

image

But that does not help that much I guess as the total is still about 1.6 mb. any its a feature and we can used it.

Until next time cheers!.

Update: Checkout this kick ass article to get crazy on size reduction

http://blogs.telerik.com/xamlteam/posts/08-05-13/increasing-the-compression-ratio-of-the-xap-files.aspx

Thursday, December 6, 2012

Silverlight key event modifier key

Just wanted to share a quick tips, in WPF , and WINForms many times we needed to use the modifier key, and so does it needed in silverlight for taking special input and tab navigation, reverse tab navigation etc.

well no more talk just a code snippet

//modifier key in silverlight
bool isShift = (Keyboard.Modifiers & ModifierKeys.Shift) == (ModifierKeys.Shift);


Cheers!

Friday, August 3, 2012

WPF Tree view binding how to stuff.

Introduction

Treeview is a very useful control, yet not that much used in real life scenario, however; it has a very good potential and the control is very customizable. Even though it has some disadvantages over some special category of data but none the less this control is a great addition to WPF default control set. In this particular article we will look at some basic functionality that WPF Tree view can provides, in particular we will take a look at the binding options. 

Basic Uses

Bellow I have given a simple code, that shows how to add a treeview in XAML. The Treeview Items are also defined as as a child nodes.

<Window x:Class="WPFTreeView.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<TreeView Height="287"
HorizontalAlignment="Left"
Margin="12,12,0,0"
Name="treeView1"
VerticalAlignment="Top"
Width="479">
<TreeViewItem Header="Bing">
<TreeViewItem Header="A" />
<TreeViewItem Header="B" />
<TreeViewItem Header="C" />
</TreeViewItem>
<TreeViewItem Header="Google" >
<TreeViewItem Header="D" />
<TreeViewItem Header="E" />
</TreeViewItem>
<TreeViewItem Header="Yahoo" >
<TreeViewItem Header="F" />
</TreeViewItem>
</TreeView>
</Grid>
</Window>


 

If you want to Populate the tree view and its node from c# code bellow I have listed few line of code to demonstrate how to do that.


using System.Windows;
using System.Windows.Controls;

namespace WPFTreeView
{
public partial class WindowTreeViewFromCodexaml
{
private TreeView _treeView;

public WindowTreeViewFromCodexaml()
{
InitializeComponent();
BuildTreeView();
BuildTreeViewNodes(0,_treeView.Items);
}

private void BuildTreeViewNodes(int level, ItemCollection itemCollection)
{
if(level==3)
return;

for (int i = 0; i < 3; i++)
{
var item = new TreeViewItem();
item.Header = string.Format("Item {0}", i + 1);
BuildTreeViewNodes(level+1,item.Items);
itemCollection.Add(item);
}
}

private void BuildTreeView()
{
TreeViewContainer.Children.Clear();
_treeView = new TreeView();
_treeView.HorizontalAlignment = HorizontalAlignment.Left;
_treeView.Margin = new Thickness(12, 12, 0, 0);
_treeView.Name = "treeView1";
_treeView.VerticalAlignment = VerticalAlignment.Top;
TreeViewContainer.Children.Add(_treeView);
}
}
}


Binding to a source


In this section we would see how we can bind a Treeview to a data source which has a hierarchical structure. For this scenario let’s Consider the following example. “ We want to display employee information as hierarchical data. The corresponding xaml and c# code is given bellow. 


XAML code


<Window x:Class="WPFTreeView.WindowTreeViewWithItemSource"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="WindowTreeViewWithItemSource" Height="300" Width="300">
<Window.Resources>
<HierarchicalDataTemplate x:Key="ItemTemplate" ItemsSource="{Binding Employees}" >
<CheckBox Content="{Binding Name}" IsChecked="{Binding IsChecked}"></CheckBox>
</HierarchicalDataTemplate>
</Window.Resources>
<Grid>
<DockPanel LastChildFill="True">
<TreeView
Name="treeView1"
ItemTemplate="{StaticResource ItemTemplate}"
ItemsSource="{Binding Employees}">
</TreeView>
</DockPanel>
</Grid>
</Window>


Above  Xaml code shows declaration of WPF treeview where ItemSource is Employee Dependency Property. But we would assign the item source from code. And this would work perfectly as we override the binding with hard code source. We have also defined a item template for each tree view item node. Bellow the corresponding c# code is given.


C# code


public partial class WindowTreeViewWithItemSource
{
public WindowTreeViewWithItemSource()
{
InitializeComponent();
LoadData();
}

private void LoadData()
{
var employees = new List();
for (int i =1; i <= 100; i++)
{
var manager = new Employee {Name = string.Format("Manager {0}", i.ToString())};
for (int j = 1; j <= 100; j++)
{
var lead = new Employee { Name = string.Format("Team Lead {0}", i.ToString()) };
for (int k = 0; k < 100; k++)
{
var junior = new Employee { Name = string.Format("Developer {0}", i.ToString())};
lead.Employees.Add(junior);
}
manager.Employees.Add(lead);
}
employees.Add(manager);
}
treeView1.ItemsSource = employees;
}
}

public class Employee
{
public Employee()
{
Employees = new List();
}
public string Name { get; set; }
public string Department { get; set; }
public int Age { get; set; }
public string Designation { get; set; }
public string Email { get; set; }
public DateTime DateOfJoin { get; set; }
public double Salary { get; set; }
public List Employees { get; private set; }
}


In above code we have defined a custom user type named “Employee” and constructed a demo hierarchy data, and finally assigned to the item source of the treeview. Note that here we did assigned itemsouce directly. If we want to use binding in that case we have to use mvp (model view presenter) or MVVM ( Model View ViewModel) pattern.


public partial class WindowTreeViewWithItemSourceBinding
{
public WindowTreeViewWithItemSourceBinding()
{
InitializeComponent();
this.DataContext = new TreeViewPresenter();
}
}

public class TreeViewPresenter:DependencyObject
{
public TreeViewPresenter()
{
LoadData();
}
private void LoadData()
{
var employees = new List<Employee>();
for (int i = 1; i <= 100; i++)
{
var manager = new Employee { Name = string.Format("Manager {0}", i.ToString()) };
for (int j = 1; j <= 100; j++)
{
var lead = new Employee { Name = string.Format("Team Lead {0}", i.ToString()) };
for (int k = 0; k < 100; k++)
{
var junior = new Employee { Name =
                    string.Format("Developer {0}", i.ToString()) };
lead.Employees.Add(junior);
}
manager.Employees.Add(lead);
}
employees.Add(manager);
}
Employees = employees;
}
public List<Employee> Employees
{
get { return (List<Employee>)GetValue(EmployeesProperty); }
set { SetValue(EmployeesProperty, value); }
}

public static readonly DependencyProperty EmployeesProperty =
DependencyProperty.Register("Employees", typeof(List<Employee>),
typeof(TreeViewPresenter), new UIPropertyMetadata(null));
}


Summery


In this short article we have seen how to use WPF tree view and some usages of WPF tree view as far as the binding and populating tree view is concern.


References


MSDN Help


Monday, October 10, 2011

Keyboard selection on Silverlight ListBox and ComboBox

By default Silverlight combo box and list box does not support keyboard selection, so we need custom solution, “Mr Fons Sonnemans”  has done a fantastic job of achieving the behavior with adding behavior  to the controls.

Here is the original post “Keyboard selection on Silverlight ListBox and ComboBox

There is a sample project added with the post. its totally reusable and fantastic. We have used it in our project and also recommend that people should use it.

Thumbs Up  “Mr Fons Sonnemans” .

Sunday, October 2, 2011

“Silverlight SPY” for firebug or snoop like tool for Silverlight

In this blog I am going to share one yet another interesting tool developed by “firstfloorsoftware”, and the tool is “Silverlight SPY” It’s a simple wonderful tool for UI debug, in fact you can see the dom and highlight particular section.

image

One demoralizing thing is that this is not a free tool, its available only in commercial tool. Its available for only evaluation.

But if we don’t need for debug the UI rather need to watch the inner anatomy of controls and customize it, I would say Expression blend is also handy.  But again expression blend is also not free Open-mouthed smile. In fact to be frank Visual Studio is also not free Open-mouthed smile.

Tell Next time. Me “Munna” Signing out.

Display XPS document In Silverlight

Today I am going to share a very useful tool named “DocumentViewer”, it’s a Silverlight control which allow users to display documents as XPS document. There are lots of supporting control associated with “DocumentViewer”, for instance view mode which deals with document’s zoom factor, navigation and off course thumb nail view, etc.

image

One key thing is that this control is commercial, so we need to pay for using it. But its free to try. We have developed a application with shows different types of document via this control, and so far the impression is very satisfactory.

I wonder whey some thing would be available with built in Silverlight control set.

Saturday, October 1, 2011

Using WCF Service with Silverlight

Introduction

In one of our products, we had to use WCF service with Silverlight. While working on Silverlight and WCF, I found out some very interesting things and I feel that those are worth sharing. Whenever we want to work with Silverlight and need some kind of service communication, we would encounter those common problems. In this article, we are going to discuss a few interesting findings about WCF and Silverlight Bridge.

For the purpose of demonstration, we are going to use a demo application with some simple class. Let's say we have an expense management application and we have a client build with Silverlight. And the client communicated to server via WCF. Let's take this example to fit our explanation process.

Using WCF with Silverlight

In this section, we will see how we can use WCF service with Silverlight. I am sure every reader has a nice grip on what is WCF and how we can use it in web applications. Some of the stuff is repeated and discussed again and may sound familiar. But as we need some parts as a subset, I am discussing it again. First, we would look at the basics and then we would see some other relevant tricks and information.

The WCF Basics

WCF has three basic building blocks. Those are called A,B,C of WCF. A stands for Address, B stands for Binding and C stands for contract. In a later section, we would see the most common knowledge that is necessary to work with WCF, of course communication with Silverlight context. WCF can be hosted in several ways. Most common ones are given below:

  • Hosting in Internet Information Services
  • Hosting in Windows Process Activation Service
  • Hosting in a Windows Service Application
  • Hosting in a Managed Application

We are not going to discuss about the above hosting options in this article as those need further study, and assumes to not be the focused area of the article. I would recommend that you spend some time on MSDN or Google to learn more about WCF hosting process.

The Service Contract and Operation Contract

I am sure we all know what a service contract is, but I am still discussing it as it is a beginner article. We make any class a service contract by adding one simple class attribute "[ServiceContract]" but it's better to declare an interface first and then apply class attribute to that interface and then implement class in a derived class. Now the methods that we would want to expose as part of the service need to be decorated with a method attribute named "[OperationContract]".

Below we have a code block with an interface that has been declared as a service contract and then we have implemented a derived class from the interface to define the methods that would be invoked via clients.

Service Contract

[ServiceContract]
public interface IMoneyService
{
[OperationContract]
ServiceResponse AddExpense(Expense expense);
[OperationContract]
ServiceResponse UpdateExpense(Expense expense);
[OperationContract]
ServiceResponse DeleteExpense(Expense expense);
[OperationContract]
ServiceResponse GetExpenseByID(int expenseId);
[OperationContract]
ServiceResponse AddCategory(Category category);
[OperationContract]
ServiceResponse UpdateCategory(Category category);
[OperationContract]
ServiceResponse DeleteCategory(Category category);
[OperationContract]
ServiceResponse GetCategoryByID(int categoryId);
}

Implementation of the Contract

[AspNetCompatibilityRequirements
(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class MoneyService : IMoneyService
{
public ServiceResponse AddExpense(Expense expense)
{
var response = new ServiceResponse();
using (var manager = new ExpenseManager())
{
try
{
response.Result = manager.AddExpense(expense);
response.IsSuccess = true;
}
catch (Exception exception)
{
response.ServiceException = exception;
response.IsSuccess = false;
response.ErrorMessage = "Unable to add Expense";
}
}
return response;
}

///Other method's implementation.... goes bellow
///....
}

In the above example, we didn't put down all the implementation in one method to demonstrate the idea.


The Data Contract


If we want to transfer custom data via WCF from server to client, we have to apply "[DataContract]" class attribute on the custom data type. Besides, all primitive datatypes can be used as a transferable data. Below we have added a simple class that we have used as our custom type to transfer data from service to client.


You might need to use KnownType attribute in case you have nested custom type in your data contract.

[KnownType(<span style="COLOR: blue">typeof</span>(your-custom-type))]

Below, a sample Data contract implementation is given.

[DataContract]
public class ServiceResponse
{
private string _errorMessage;
[DataMember]
public string ErrorMessage
{
get { return _errorMessage; }
set { _errorMessage = value; }
}
private object _result;
[DataMember]
public object Result
{
get { return _result; }
set { _result = value; }
}
private bool _isSuccess;
[DataMember]
public bool IsSuccess
{
get { return _isSuccess; }
set { _isSuccess = value; }
}
private Exception _serviceException;
[DataMember]
public Exception ServiceException
{
get { return _serviceException; }
set { _serviceException = value; }
}
}

ASP.NET Compatibility


This particular scenario is very useful if we host the WCF service in the IIS environment. The idea is to share the same HttpContext in service methods and inner methods so that we can access session and application data of the web application where the WCF service is being exposed.

var context = HttpContext.Current;
var path = context.Server.MapPath("~/MyPics");

if (!Directory.Exists(path))
{
Directory.CreateDirectory(path);
}

var userFolder = string.Format("{0}\\{1}", path, userId);

if (!Directory.Exists(userFolder))
{
Directory.CreateDirectory(userFolder);
}

In the above example, we want to find a folder name "MyPics" where the pictures of a particular user will be saved. So we need the httpContext where the service is running.


Below, the service configuration is given. The key stuff is the tag "serviceHostingEnvironment" we have to set the attribute aspNetCompatibilityEnabled="true".

    <system.serviceModel>
<behaviors>
<endpointBehaviors>
<behavior name="PEM.MoneyTrackingServiceAspNetAjaxBehavior">
<enableWebScript />

</behavior>
</endpointBehaviors>
</behaviors>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true"
multipleSiteBindingsEnabled="true" />

<services>
<service name="PEM.MoneyTrackingService">
<endpoint address=""
behaviorConfiguration="PEM.MoneyTrackingServiceAspNetAjaxBehavior"
binding="webHttpBinding" contract="PEM.MoneyTrackingService" />

</service>
</services>
</system.serviceModel>

After that, we have to put the AspNetCompatibilityRequirements class attribute with value RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed to the desired service contract implementation. Note that this attribute cannot be added before the interface which is the contract. We have to add it before the service contract implementation.

[ServiceContract(Namespace = "")]
[AspNetCompatibilityRequirements
(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class MoneyTrackingService
{
[OperationContract]
public void DoWork()
{
return;
}
}

Adding Service Reference to Silverlight


Alright. We have the basics on our finger tip, now it's time to make the service workable. Here are the steps we have to do.



  • Step 1: Define Data Contract that we want to transmit via service. Add "[DataContract]" class attribute to class and "[DataMember]" property attribute to properties. If we have any enum in the DataContract we have to apply EnumMember attribute.
  • Step 2: Define interface for ServiceContract with methods, add service contract attribute. mark each method that we want to expose to OperationContract.
  • Step 3: Define a derived class for ServiceContract implementation. Add the necessary class attribute if we need ASP.NET compatibility.
    In our case, we have defined those classes and interface in a separate project named MoneyTracking.Service.
  • Step 4: Add a reference to the project where we defined the classes. If we defined all the classes and interfaces in the web project, then no worries.
  • Step 5: Add a svc file. Get rid of the "cs" file. Modify the XML for the .svc file. put down the proper service name.
     <%@ ServiceHost Language="C#" Debug="true" 
    Service="full Qualified name goes here" %>

  • Step 6: Define proper service definition in service model tag of web.config. We have defined the XML in the previous section, we can also copy from there. Note that we should at mex binding as well.
  • Step 7: Browser the service to see if everything is working fine or not.
  • Step 8: Go to the Silverlight project where we want to consume the service, right click on the project's reference node and select add Service Reference, which will bring the configure add service reference wizard. Rest of the work is self explanatory in the wizard.

When you finished adding the service, you will have a service reference node where the service will be added. Visual Studio also adds lots of code behind the scenes, an also a ServiceReferences.ClientConfig file. We will see the uses in later sections.


ServiceReferences.ClientConfig

<configuration>
<system.serviceModel>
<bindings>
<basicHttpBinding>

<binding name="BasicHttpBinding_IMoneyService" maxBufferSize="2147483647"
maxReceivedMessageSize="2147483647">
<security mode="None" />

</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="http://localhost/MoneyTrackingService.svc"
binding="basicHttpBinding"
bindingConfiguration="BasicHttpBinding_IMoneyService"

contract="MoneyTrackingServiceReference.IMoneyService"
name="BasicHttpBinding_IMoneyService" />
</client>
</system.serviceModel>
</configuration>

Using the Channel Factory


So far, we have three ways to use a WCF service in Silverlight:



  • Using a service reference
  • Using chanel Factory
  • Using Client base

Below, we have explained how the chanel factory can be used to define a WCF service in Silverlight side. Note that in this case, we don't have to use any sort of reference for the service. But how? Silverlight only allows asynchronous model of service method call, so we cannot use the same OperationContract. We can copy all the classes that are DataContract as a link and use in the Silverlight project, for the service contract we have to define a new class with ServiceContract attribute. Note that the methods need to have [OperationContract(AsyncPattern = true)] method attribute. For each method in the ServiceContract in server, we have to define two methods with pre-fix "Begin" and "End" so if we have a method named "AddExpense" in server, in the client class we have to define two methods named "BeginAddExpense" and "EndAddExpense". Below, a complete code has been given for the class IMoneyService of client.


Example of AnyncPattern Contract

namespace MoneyTracking.Service
{
[ServiceContract]
public interface IMoneyService
{
[OperationContract(AsyncPattern = true)]
IAsyncResult BeginAddExpense
(Expense expense, AsyncCallback callback, object state);

[OperationContract(AsyncPattern = true)]
IAsyncResult BeginUpdateExpense
(Expense expense, AsyncCallback callback, object state);

[OperationContract(AsyncPattern = true)]
IAsyncResult BeginDeleteExpense
(Expense expense, AsyncCallback callback, object state);

[OperationContract(AsyncPattern = true)]
IAsyncResult BeginGetExpenseByID
(int expenseId, AsyncCallback callback, object state);

[OperationContract(AsyncPattern = true)]
IAsyncResult BeginAddCategory
(Category category, AsyncCallback callback, object state);

[OperationContract(AsyncPattern = true)]
IAsyncResult BeginUpdateCategory
(Category category, AsyncCallback callback, object state);

[OperationContract(AsyncPattern = true)]
IAsyncResult BeginDeleteCategory
(Category category, AsyncCallback callback, object state);

[OperationContract(AsyncPattern = true)]
IAsyncResult BeginGetCategoryByID
(int categoryId, AsyncCallback callback, object state);

ServiceResponse EndAddExpense(IAsyncResult result);

ServiceResponse EndUpdateExpense(IAsyncResult result);

ServiceResponse EndDeleteExpense(IAsyncResult result);

ServiceResponse EndGetExpenseByID(IAsyncResult result);

ServiceResponse EndAddCategory(IAsyncResult result);

ServiceResponse EndUpdateCategory(IAsyncResult result);

ServiceResponse EndDeleteCategory(IAsyncResult result);

ServiceResponse EndGetCategoryByID(IAsyncResult result);
}
}

Example of chanelFactory


Now we have defined the interface. It's time to build the service using ChanelFactory. Below a simple code is given to demonstrate how we can create a service client and invoke a method.

private void UsingChanelFactory(object sender, RoutedEventArgs e)
{
var basicHttpBinding = new BasicHttpBinding();
var endpointAddress = new EndpointAddress
("http://localhost/MoneyTrackingWeb/MoneyTrackingService.svc");
var moneyService = new ChannelFactory
<moneytracking.service.imoneyservice>

(basicHttpBinding, endpointAddress).CreateChannel();
moneyService.BeginAddCategory
(new MoneyTracking.Common.Category(), ASyncronousCallBack, moneyService);
}

private void ASyncronousCallBack(IAsyncResult ar)
{
if(ar.IsCompleted)
{
MoneyTracking.Common.ServiceResponse serviceResponse =
((MoneyTracking.Service.IMoneyService)ar.AsyncState).EndAddCategory(ar);
if(serviceResponse.IsSuccess)
{
//do your work here
}
}
}

Making Synchronous Call


By default, the methods that we have in service client in Silverlight are asynchronous method calls. A simple code is given below to demonstrate the idea. A Client has been initiated and then a completed event has been subscribed to and then call the asynchronous method.


Example of Asynchronous call

public void AddExpense()
{
var client = new MoneyServiceClient();
var category = new Category();
//fill category attributes here
client.AddCategoryCompleted += ClientAddCategoryCompleted;
client.AddCategoryAsync(category);
}

void ClientAddCategoryCompleted(object sender, AddCategoryCompletedEventArgs e)
{
ServiceResponse serviceResponse = e.Result;
if(serviceResponse.IsSuccess)
Categories.Add((Category) serviceResponse.Result);
}

Example of Synchronous Call


In some scenarios, we need to have a synchronous call, since Silverlight does not allow the synchronous call we can always bypass and use the same system in such a way so that we have a synchronous call, the idea is to stop the current code execution until the completed event is been fired.


We have defined a custom class AsyncCallStatus<T> a custom status which will be passed via Async Method. But the magic class which make all this possible is "AutoResetEvent", we have the current execution freeze using _autoResetEvent.WaitOne(). When in completed event, we get the result back we simply set the  _autoResetEvent.Set(); which again resumes the process.


Note that in Silverlight 4, we have to use ThreadPool.QueueUserWorkItem(MethodNameGoesHere); to start the process otherwise AutoResetEvent.WaitOne() will stop the current tread execution, and completed event won't fire at all, in fact call the server will never be invoked. Below, we have put down the complete listing of a method called synchronously.

private void SyncronousCall(object sender, RoutedEventArgs e)
{
ThreadPool.QueueUserWorkItem(AddExpenseInServer);

}

private void AddExpenseInServer(object state)
{
Expense addedExpense = AddExpense();
Dispatcher.BeginInvoke(() =>
{
StatusMessage.Content = "Expense is been Added";
Expenses.Add(addedExpense);
});
}

private Expense AddExpense()
{
var asyncCallStatus = new AsyncCallStatus<AddExpenseCompletedEventArgs>();
var client = new MoneyServiceClient();
client.AddExpenseCompleted += ClientAddExpenseCompleted;
client.AddExpenseAsync(new Expense(),asyncCallStatus);
_autoResetEvent.WaitOne();
if (asyncCallStatus.CompletedEventArgs.Error != null)
{
throw asyncCallStatus.CompletedEventArgs.Error;
}
var serviceResponse = asyncCallStatus.CompletedEventArgs.Result;
if (serviceResponse.IsSuccess)
{
return serviceResponse.Result as Expense;
}
else
return null;
}

void ClientAddExpenseCompleted(object sender, AddExpenseCompletedEventArgs e)
{
var status = e.UserState as AsyncCallStatus<AddExpenseCompletedEventArgs>;
if (status != null) status.CompletedEventArgs = e;
_autoResetEvent.Set();
}

private readonly AutoResetEvent _autoResetEvent = new AutoResetEvent(false);

public class AsyncCallStatus<T>

{
public T CompletedEventArgs { get; set; }
}

Cross Domain Service Call


By default, Silverlight can invoke any method from the originator site. So if the Silverlight component is invoked from "http://mytestside.com/silverlightTestPage.aspx", the component can call any WCF service hosted in "http://mytestside.com/testservice.svc". But let's say we want to call a WCF service which is hosted on "http://myotherside.com/otherservice.svc", we would encounter an error something like this:


The way to archive cross domain service call in Silverlight is pretty simple in fact. We have to put two XML files named "clientaccesspolicy.xml" and "crossdomain.xml" file in root folder of the service. So if we have a service named "http://mytestserver.com/myservice.svc", we need to put down those two files in "http://mytestserver.com/clientaccesspolicy.xml". Both the file and its content are given below.


clientaccesspolicy.xml

<?xml version="1.0" encoding="utf-8" ?>
<access-policy>
<cross-domain-access>

<policy>
<allow-from http-request-headers="SOAPAction">
<domain uri="*"/>
</allow-from>
<grant-to>

<resource path="/" include-subpaths="true"/>
</grant-to>
</policy>
</cross-domain-access>

</access-policy>

crossdomain.xml

<?xml version="1.0" ?>
<!DOCTYPE cross-domain-policy SYSTEM
"http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd">
<cross-domain-policy>
<allow-http-request-headers-from domain="*" headers="SOAPAction,Content-Type"/>

</cross-domain-policy>

You can simulate the crossdomain class in the local environment also. For this, modify the host file:

127.0.0.1 testserver.com 
127.0.0.1 testclient.com

Now you can run your project from testclient and service will be consumed from testserver.


Transfer Large Data


In this section, we would see how we can customize the WCF service so that we can transfer large amount of data. We often encounter an error while communicating that max limit of array size has been crossed or perhaps an exception that endpoint not found, it's simply because there could be a size issue. Note that the endpoint not found exception can occur for many reasons.


To overcome the limitation, we need to customize the basicHttpBinding. We have to define a bindings section under <system.servicemodel> and under that we would customize the basicHttpBinding. For this, we have to create another sub section under binding named "<basicHttpBinding>". Here we can put multiple bindings and of course we can set all the advanced attributes.


Below, we have put down both client and server configuration.


Service Configuration on Server

<system.serviceModel>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true"
aspNetCompatibilityEnabled="true"/>

<bindings>
<basicHttpBinding>
<binding name="MoneyTrackingServiceBinding" maxBufferPoolSize="2147483647"
maxBufferSize="2147483647" maxReceivedMessageSize="2147483647">

<readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647"
maxArrayLength="2147483647" maxBytesPerRead="2147483647"
maxNameTableCharCount="2147483647">
</readerQuotas>

</binding>
</basicHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior name="MoneyTrackingServiceBehavior">

<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="false" />
</behavior>
</serviceBehaviors>

</behaviors>
<services>
<service name="MoneyTracking.Service.MoneyService"
behaviorConfiguration="MoneyTrackingServiceBehavior">
<endpoint address="" binding="basicHttpBinding"

bindingConfiguration="MoneyTrackingServiceBinding"
contract="MoneyTracking.Service.IMoneyService" />
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>

</service>
</services>
</system.serviceModel>

Here under service, we have added behaviorConfiguration to "" in service and under that in endpoint section we have also set "bindingConfiguration" to our desired configuration name.


Client Side Configuration

<configuration>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="MoneyTrackingServiceBinding" maxBufferSize="2147483647"

maxBufferPoolSize="2147483647" maxReceivedMessageSize="2147483647" />
</basicHttpBinding>
</bindings>
<client>

<endpoint address="http://localhost/MoneyTrackingWeb/MoneyTrackingService.svc"
binding="basicHttpBinding"
bindingConfiguration="MoneyTrackingServiceBinding"
contract="MoneyTrackingServiceReference.IMoneyService"
name="BasicHttpBinding_IMoneyService" />

</client>
</system.serviceModel>
</configuration>

The above service configuration section is for the client, note that both server and client binding configuration name should match and the value should also match. In client service configuration fine we don't have to define the "readerQuotas", infact that would give you an exception. And we don't need behaviour configuration. You guys can also copy and paste the above configurations in your context, while doing so you have to fix the contract names and service names.


Summary


In this short article, we have seen the basics of WCF service. We have discussed only those parts that are necessary to build a simple WCF service that can be consumed by a Silverlight client. Then we have seen two ways of creating a client proxy for Silverlight. We can add service reference and also can use chanel factory to build client. Chanel factory gives more control over client proxy.


After that, we have seen how we can use some small policy XML files to extend the service so that it can be consumed via Silverlight components running in a different domain. Lastly, we have seen how we can customize the binding to support large amount of data transfer. There are lots of challenges in real life development regarding WCF and Silverlight. I hope to put together more content in a future article.


References



History



  • 29th September, 2011: Initial version

Sunday, September 18, 2011

Finding a child element in silverlight

Today I am going to share a simple code that will help us to find a child element from a silverlight control. In one of our control we had a requirement to find out the internal scrollviewer, by default we didn't had support to find the internal element right way.

So the only way is to try finding it with VisualTreeHelper. And do a recursive call to find out if the Element With the name exists or not. we can use couple of modification depending ton Name or Type, bellow I have shared a Extension method which demonstrate the idea.

public static class FrameworkElementExtensions
    {
        public static FrameworkElement FindChild(this FrameworkElement element, string targetName)
        {
            if (element == null || string.IsNullOrEmpty(targetName))
                return null;
            if (element.Name == targetName)
                return element;
            for (int index = 0; index < VisualTreeHelper.GetChildrenCount(element); index++)
            {
                var child = (FrameworkElement)VisualTreeHelper.GetChild(element, index);
                if (child.Name == targetName)
                    return child;
                child = FindChild(child, targetName);
                if (child != null)
                    return child;
            }
            return null;
        }

        public static object TryFindResource(this FrameworkElement element, object resourceKey)
        {
            var currentElement = element;

            while (currentElement != null)
            {
                var resource = currentElement.Resources[resourceKey];
                if (resource != null)
                {
                    return resource;
                }

                currentElement = currentElement.Parent as FrameworkElement;
            }

            return Application.Current.Resources[resourceKey];
        }