Archive for the ‘.NET’ Category
Introduction to Caliburn Micro – Part 2
If you haven’t used Caliburn Micro please go through Caliburn Micro Introduction 1
Introduction
Most of the us know what is MVVM model but most of us hesitant to use it in their development. Reason they say is, implementing MVVM in a small project is an overkill. Might be true if they use some complicated MVVM frameworks. In my opinion using Caliburn Micro as a MVVM framework wont overkill or complicate your development rather It will ease our development. Caliburn Micro uses Convention over Configurations, so zero configuration. Last couple of months I did so many tracers and some large projects in Silverlight and WPF using Caliburn Micro, some tracers are just one page projects still I used Caliburn Micro because it’s very easy to develop compare to the normal code behind approach. Some of us are not using Caliburn Micro, the reason is they are doubtful whether it can used in big production level projects as it’s a micro. My answer is yes, I used Caliburn Micro in very complex applications that have more than thirty pages and very complicated functionalities. Don’t underestimate Caliburn Micro by its name, it’s very powerful and easy to learn. I am sure once you start using Caliburn Micro you will never go back to normal codebehind approach in Silverlight or WPF or WP7 neither a different MVVM framework.
iTraveller Development Days
In the development phase of iTraveller I come across lot of blockers related to MVVM model development using Caliburn Micro. In this post I am going to give a brief description about some of my blockers and how I overcome those.
Capturing PreviewDrop/KeyUp or any kind of event in Viewmodel
If you had a chance to look at iTraveller then you can see most of the functionality is based on drag and drop features. My first concern was how to capture drop event or Mouse Down Even or KeyUp Event using Caliburn Micro. What we should do to capture the event is as follows.
<ListBox Name="MyPhotoSets" VerticalAlignment="Stretch"
Visibility="{Binding IsListVisible}" AllowDrop="True" MinHeight="100" MinWidth="100" Style="{DynamicResource PhotoListStyle}" ItemTemplate="{DynamicResource SetTemplate}" ItemContainerStyle="{DynamicResource PhotoListItem}" > <i:Interaction.Triggers> <i:EventTrigger EventName="PreviewDrop"> <cal:ActionMessage MethodName="NewPhotosDropped"> <cal:Parameter Value="$eventArgs"></cal:Parameter> </cal:ActionMessage> </i:EventTrigger> <i:EventTrigger EventName="SelectionChanged"> <cal:ActionMessage MethodName="CategorySelectionChanged"> <cal:Parameter Value="{Binding ElementName=MyPhotoSets,
Path=SelectedItem}"></cal:Parameter> </cal:ActionMessage> </i:EventTrigger> <i:EventTrigger EventName="KeyUp"> <cal:ActionMessage MethodName="KeyUpHappened"> <cal:Parameter Value="$eventArgs"></cal:Parameter> </cal:ActionMessage> </i:EventTrigger> </i:Interaction.Triggers> </ListBox>
You should add a xmlns reference to System.Windows.Interactivity and Caliburn Micro in your xaml page as shown below
xmlns:cal="clr-namespace:Caliburn.Micro;assembly=Caliburn.Micro" xmlns:i="clr-namespace:System.Windows.Interactivity;
assembly=System.Windows.Interactivity"
As you can see in the ListBox I added an event trigger for PreviewDrop and KeyUp. Obviously in you Viewmodel you need to get the DragEventArgs or KeyEventArgs to perform the desired action. We can instruct Caliburn Micro to send these eventargs to the viewmodel function by adding a parameter with value ‘$eventArgs’. Just examine the xaml code.
<i:EventTrigger EventName="PreviewDrop"> <cal:ActionMessage MethodName="NewPhotosDropped"> <cal:Parameter Value="$eventArgs"></cal:Parameter> </cal:ActionMessage> </i:EventTrigger>
In the above code will work like this. If a PreviewDrop event happened in Listbox then call NewPhotosDropped function in my Viewmodel with parameter DragEventArgs. Have a look at my Viewmodel’s NewPhotosDropped function
public void NewPhotosDropped(DragEventArgs e) { //perform your task with parameter e.
}
That’s it now you will get the DragEventArgs in your Viewmodel and do what ever you wanted to do with it.
How to get a View in ViewModel
Most of the case you don’t need a reference to the View. But if in any case you need the reference of your View in your Viewmodel, no issues. You can override OnViewLoaded function of Caliburn micro in Viewmodel and get your view as follows.
protected override void OnViewLoaded(object view) { base.OnViewLoaded(view); MyView myView = view as MyView; if (myView != null) _webBrowserControl = myView.WebBrowserControl; }
How to Bind a ViewModels to a ListBox/ItemsControls that has Custom Template
In some scenarios you may need to bind a list of Viewmodels to a Listbox. If there is no custom templates then no issues. But if the Listbox has some custom templates and the view should show in a contentcontrol placed in the template. Then we should add one dependency property to the content control. Let’s take an e.g
<ListBox x:Name="IndividualComments" BorderThickness="0"> <ListBox.ItemsPanel> <ItemsPanelTemplate> <StackPanel Orientation="Vertical" Background="Gray"/> </ItemsPanelTemplate> </ListBox.ItemsPanel> <ListBox.ItemTemplate> <DataTemplate> <Border BorderBrush="Black" BorderThickness="1" CornerRadius="0" Background="Transparent" Margin="1"> <ContentControl ca:View.Model="{Binding}" Margin="0" Background="Transparent"/> </Border> </DataTemplate> </ListBox.ItemTemplate> </ListBox>
View model code
private ObservableCollection<IndividualCommentViewModel> _individualComments; public ObservableCollection<IndividualCommentViewModel> IndividualComments { get { return _individualComments; } set { _individualComments = value; } }
In the viewmodel I will have a list of IndividualCommentViewModel. The Listbox in xaml page has some custom template to add a border around the comments. The viewmodel should be binded to a ContentControl inside the border. I tried lot of ways to show my view in the content control but failed. After some search in Caliburn Micro code and googling I came across View.Model dependency property.
As you can see the contentcontrol
<ContentControl ca:View.Model=”{Binding}” Margin=”0″ Background=”Transparent”/>
If we set ca:View.Model=”{Binding}” then Caliburn Micro is intelligent enough to set the View to the content control. ‘ca’ is my xmlns name reference in the page, it can be any name.
Showing Views in Tabcontrols just like in Visual Studio
In iTraveller views like Preview, Search Result, Upload basket, etc are in tabbed view. In one of Rob’s post he explained in detail how we can achieve tabbed view. I just used the same approach he mentioned. I don’t think I need to explain it again.
How to Give a Title to Popup window
After the release, when I recheck iTraveller, I could see that the popup window is showing without the Title I had given in the xaml page. The title is coming with fully functional name of the popup’s viewmodel. So how to solve it. What we need to do is inherit the viewmodel from screen. See the below code to set the title
FlickrAuthorizeViewModel flickrAuthorizeViewModel = new FlickrAuthorizeViewModel(flickrService); flickrAuthorizeViewModel.DisplayName = "Flickr Authorization"; WindowManager winManager = new WindowManager(); winManager.ShowDialog(flickrAuthorizeViewModel, null);
Screen class has a property called Display Name, just set the title to Display Name property as shown above. We are done, the WindowManager will now show the popup with the Title I given in DisplayName property
Event Aggregator
Event Aggregator in Caliburn Micro is a powerful implementation of Observer/Subscriber pattern. The usage of Event aggregator is not limited to ViewModel communication. It can be used in any layer, if there is a need of Observer/Subscriber communication. In iTraveller the messaging (Event Aggregation) is a separate Layer. One main reason I separated it from UI layer is, I may need to raise messages from other layers other than UI. In iTraveller’s User Comment service uses Event Aggregator to publish the result once it’s processed all the comments fetched from Flickr or Facebook. I used Event Aggregator here because once the comments are saved the application does two things, 1: it’s start indexing those comments for searching, 2: a tab need to open to display the comments fetched from Flickr/Facebook. Rather than calling those functionalities the Comment service just publish the processed comments. Who ever listening those messages will get notified, here in iTraveller Indexing service and UserCommentUpdateViewModel is listening to UserComment message. They know what they should do when they got UserComment update notification.
As the day passes… more and more in love with Caliburn Micro
. Thanks for reading. Any questions or comments pls update it in the comment section.
Populate Listbox Asynchronously using Await and Reactive Extension (Rx)
Recently I completed rewriting one of my WPF application called iTraveller, one important area of interest was User interface. I did lot of things to make the UI responsive even in, time consuming operations. My first hurdle was populating the thumbnail images in a list box without halting the UI. If we populate Listbox in normal approach then the UI will be unresponsive till it completes. I searched a lot to find a better approach to populate ListBox asynchronously without halting my UI. Most of the approaches were too complex or not suited for my requirement. So I combined Async CTP’s await and Reactive Extension (Rx) to satisfy my requirement. The result was far far better than I thought, with my approach I could populate Listbox asynchronously with a very responsive UI.
Let’s see how I solved the issue.
First have a look at my Photo entity
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Windows.Media.Imaging; using System.Threading.Tasks; using System.Threading; using System.IO; using Db4objects.Db4o; namespace ITraveller.Domain { public class Photo:IDisposable { public Photo() { this.ImageID = Guid.NewGuid(); } private Guid _imageID; public Guid ImageID { get { return _imageID; } set { _imageID = value; } } private String _imageName; public String ImageName { get { return _imageName; } set { _imageName = value; } } private string _title; public string Title { get { return _title; } set { _title = value; } } private string _description; public string Description { get { return _description; } set { _description = value; } } private Uri _uri; public Uri Uri { get { return _uri; } set { _uri = value; } } private string _imagePath; public string ImagePath { get { return _imagePath; } set { _imagePath = value; } } private LocalCategory _category; public LocalCategory Category { get { return _category; } set { _category = value; } } private int _commentCount; public int CommentCount { get { return _commentCount; } set { _commentCount = value; } } private BitmapImage _thumbnailImage; public BitmapImage ThumbnailImage { get { return _thumbnailImage; } set { _thumbnailImage = value; } } private BitmapImage _previewImage; public BitmapImage PreviewImage { get { return _previewImage; } set { _previewImage = value; } } public void EmptyImage() { this.PreviewImage = null; this.ThumbnailImage = null; } public delegate void LoadImage(); public Photo GetPhotoWithThumbnail() { this.ThumbnailImage = new BitmapImage(); this.ThumbnailImage.BeginInit();
this.ThumbnailImage.UriSource = new Uri(this.ImagePath);
this.ThumbnailImage.DecodePixelHeight = 50;
this.ThumbnailImage.EndInit();
return this; } public Photo GetPhotoWithPreviewImage() { try { this.PreviewImage = new BitmapImage(); this.PreviewImage.BeginInit(); this.PreviewImage.UriSource = new Uri(this.ImagePath); this.PreviewImage.EndInit(); return this; } catch (Exception ex) { this.PreviewImage = null; return this; } } public void Dispose() { this.PreviewImage = null; this.ThumbnailImage = null; } } }
It’s a normal Entity. GetPhotoWithThumbnail function creates the BitmapImage in the photo entity. Before adding to Listbox I make a call to this function to get the thumbnail image and bind it to ListBox.
I used db4o for persisting my data, I covered how I used db4o in one of my previous post. Let’s start the code walk through from Application layer. In my app layer I have a function to fetch all the photos belongs to a category.
public async Task<List<Photo>> GetPhotosByCategory(LocalCategory category) { return await TaskEx.Run(() => { IRepository repository = GenericRepository.GetRepositoryInstance(); return repository.Find<Photo>(p => p.Category.ID == category.ID).ToList<Photo>(); }, CancellationToken.None); }
I used await here to perform the data fetching task asynchronously.
Now let’s go to the Viewmodel and see how I am calling this function and populating the listbox. iTraveller implements MVVM model and as usual I used Caliburn Micro as my MVVM framework.
public async void LoadPhotosInCategory(LocalCategory category) { PhotoService photoService = new PhotoService();
//data retrieving call using await
List<Photo> photos=await photoService.GetPhotosByCategory(category);
//loading of List using Reactive extension
IObservable<Photo> photosToLoad = photos.ToObservable<Photo>();
photoToLoad.Subscribe<Photo>(p =>
{
Dispatcher.CurrentDispatcher.Invoke(DispatcherPriority.Background, new Action<Photo>(AddThumbnailToCollection), p);
}, () =>
{
//this block will execute once the iteration is over.
}
);
}
private void AddThumbnailToCollection(Photo photo) { photo = photo.GetPhotoWithThumbnail(); this.Thumbnails.Add(photo); }
public ObservableCollection<Photo> Thumbnails { get; private set; }
Dispatcher can be find in System.Windows.Threading namespace.
The observablecollection Thumbnails is binded to the Listbox in the View. That all happens behind the scene and done by Caliburn Micro.
I used Dispatcher here because the creation of BitmapImage should be in the same thread of the UI otherwise while binding it will throw error.
Try it out yourself and see how responsive your UI even if the Listbox is getting loaded with hundreds of thumbnails.
iTraveller–A photo uploader for Flickr and Facebook
Today I released my new version of iTraveller. I was working on this version for last 2 weeks, it’s a complete rewrite of old iTraveller, with several added usability features. Now iTraveller can upload photos to Facebook as well.
What is iTraveller
iTraveller is a desktop application to organize your photos and upload them to Flickr and Facebook. iTraveller ease the organizing of photos. We can mark which photos should go to Flickr or Facebook and add to appropriate set/album in offline. Once you decide to upload, click the Synchronize button leave the rest to iTraveller. While iTraveller synching with Flickr/Facebook, you go for a walk or grab a cup of coffee or you can continue creating your local category or adding more photos to Flickr Set/Facebook Album. Another useful feature of iTraveller is, you can see the photo comments posted by other users in offline mode.
I used Calburn micro to separate my View and View Model. Also I extensively used Async CTP to make a very responsive UI. I will give more details of my architecture in a different post.
Technologies used
Let’s see some screen shots of iTraveller
Home Screen
First step in using iTraveller is creating a Local set. You can create a local set by dragging and dropping your photos from Windows explorer to the Local Set box at the left top pane. When you drag and drop photos to Local Set pane, it will ask whether you need to create a new set or add to an existing category. You can see the photos inside a category by clicking on category and all the photos inside the category will show in the bottom pane of the application.
Humans are prone to errors, if you accidentally create any Local Set, don’t worry select the Local Category and just press delete key in your keyboard, you are done. The local set is deleted (only from iTraveller). In some scenarios you may need to delete only couple of photos from a local set. You can do that as well, select the photo from the thumbnail view and press delete key in your keyboard.
Mark for Flickr Uploading
You need to authorize iTraveller to connect to Flickr. Clicking on the synchronize button for the first time will popup a dialog box and follow the step to authorize it. After the authorization iTraveller will download the Flickr sets from Flickr.
Now let’s see how we can upload photo(s) to Flickr. Select a Flickr set in the right hand side of the application. Click on the Flickr set you want to upload your photo. It will open a tab as shown below.
Drag the required photo from the thumbnail to the Queue box and drop it. You also can give the Title and Description for the photo. By default visible to public is unchecked, if you want your photo to be visible to public then check the ‘Is Visible to Public’. You can put as many photo to queue. Once you are connected to internet, click the synchronize button just below the Flickr set to upload it to Flickr.
Mark for Facebook Uploading
You can upload the photo to Facebook just like the way we did for Flickr, instead of Flickr set you should select a Facebook Album on the right hand side. First time synching with Facebook needs your authorization. After you allow iTraveller to communicate with Facebook account, it will download all your Facebook Albums. iTraveller will take some time to get the photo albums from Facebook.
Once the synchronization is over and iTraveller got any new comments from Facebook or Flickr then it will open an Updates tab for you, so that you wont miss any updates.
You can provide different title and description for Facebook and Flickr Photos. These text is also searchable.
Create Flickr Set Through iTraveller
You can also create Flickr Set through iTraveller. Click on the ‘+’ icon, just above the Flickr Set Thumbnails. iTraveller will popup a window to enter new Flickr Set and Set description, click save once you done. While synchronizing with Flickr, the set will get created in Flickr. To create a Flickr Set successfully, at least one photo should be their in the upload queue of the newly created Set. The thumbnail of the newly created Set will be displayed only after the synchronization.
Search
iTraveller have built in searching feature. It enables the user to search for photos that satisfy the search text. The search will only look for photos added to iTraveller. User can search for the photo name, Title, Description, Flickr Title, Flickr Description, Facebook Description and Photo Comments. Enter the Search Text at the text box located at the top right corner of the application.
As a photographer you will have a lot of photos in your hardisk. Always our big problem is how to find a photo with some attributes. iTraveller can help you out, you can add a title and description and just save it. When ever you want to find it just enter the search text and click search. Another reason for search is, you may wanted to find the photos that got comments from your friends (either from Facebook or Flickr), let’s say Kevin or Sony. Go ahead and enter Kevin;Sony in the search text and hit Search button. iTraveller will give you the list of photos commented by Kevin or Sony.
You can see the preview of the Searched photo by double clicking on the thumbnail.
Comments
In the preview if any photo have any comments then a View comments button will shown in the preview tab as shown below.
Clicking on the comments button will open a new comment tab as shown below. You can leave this tab open and the comments will get changed when you navigate from one photo to another through the thumbnail.
Preview Tab
Preview tab will display the image in preview mode. Below the preview image, you can see below buttons
More feature will get added in next release, but needs motivation. Use my iTraveller and Motivate me
.
Upgrade to New Versions
In coming days I will release iTraveller with bug fixes and new enhancements.
If you have already installed iTraveller 2.0, then you can upgrade to latest version. Please take a backup of the following files and folders before you update to new version, it will help you keep your data safe. In case of any issue after the update like not showing your Local set or any thing, you always can put the backuped up files back to the iTraveller folder.
You can find the the below files/folders here ‘Program Files\iTraveller\iTraveller’
Files/Folders to Backup
- ITravellerData.data (File)
- FacebookThumbnails (Folder)
- FlickrThumbnails (Folder)
- SearchIndex (Folder)
Download
I uploaded the application here. Install it and let me know your feed back.
.NET Reflection–Helpful Functions
In this post I will explain few functions I created to solve some of the scenarios in one of my project.
Property Defaulter
In one of my project I had to deal with a table that have hundreds of fields but we are dealing with very few field in the table. The several fields of the table needs default values either zero or empty. I know if I am not finding a generic solution I will be in trouble as I had to fill all the fields my self and I don’t want to do that. So I created a small function that will do the job of setting my entities to default values if the properties doesn’t have any values. Here is my function
public static void SetDefaultValue<TEntity>(TEntity entity) where TEntity : class { try { PropertyInfo[] properties = typeof(TEntity).GetProperties(); bool isSetDefaultVal = false; foreach (PropertyInfo property in properties) { object propertyValue; if (property.CanRead) { isSetDefaultVal = false; if (property.PropertyType.Name != "String" &&
property.PropertyType.Name != "Single" &&
property.PropertyType.Name != "Int32") continue; try { propertyValue = property.GetValue(entity, null); } catch (Exception ex) { //log error continue; } if (propertyValue==null) { if (property.PropertyType.Name == "String") propertyValue = ""; else propertyValue = 0; isSetDefaultVal = true; } //set the value if property value is null and set to 0 in above if block. if (property.CanWrite && isSetDefaultVal == true) { if (property.PropertyType.Name == "Single") property.SetValue(entity, Convert.ToSingle(propertyValue), null); else if (property.PropertyType.Name == "Int32") property.SetValue(entity, Convert.ToInt32(propertyValue), null); else if (property.PropertyType.Name == "String") property.SetValue(entity, "", null); } } } } catch (Exception ex) { throw; } }
So how we use it, lets see with a e.g
PropertyDefaulter.SetDefaultValue<ItemMaster>(itemMaster);
The above function will inspect the properties in the itemMaster object, if any property doesn’t has value then based on the type the function will set the value. Int or float property will set to 0 and string property will set to empty.
Copy DataReader to Entities
When I was dealing with ADO.NET I used to fetch data from database table using SqlCommand’s execute reader and get the data in DataReader. I have DTO’s (Data Transfer Object) to transfer data between layers. So I have to copy all the data in DataReader to my DTO’s. I need to find an easy way rather than manually assigning values from datareader to properties. Here is my method to do the copy of data from DataReader to my DTO’s
public static List<TEntity> CopyDataReaderToEntity<TEntity>(IDataReader dataReader)
where TEntity : class { List<TEntity> entities = new List<TEntity>(); PropertyInfo[] properties = typeof(TEntity).GetProperties(); while (dataReader.Read()) { TEntity tempEntity = Activator.CreateInstance<TEntity>(); foreach (PropertyInfo property in properties) { SetValue<TEntity>(property, tempEntity, dataReader[property.Name]); } entities.Add(tempEntity); } return entities; } public static TEntity SetValue<TEntity>(PropertyInfo property, TEntity entity, object propertyValue)
where TEntity : class { if (property.CanRead) { if (property.PropertyType.Name != "String" &&
property.PropertyType.Name != "Single" &&
property.PropertyType.Name != "Int32") return entity; if (propertyValue == null) { if (property.PropertyType.Name == "String") propertyValue = ""; else propertyValue = 0; } if (property.CanWrite) { if (property.PropertyType.Name == "Single") property.SetValue(entity, Convert.ToSingle(propertyValue), null); else if (property.PropertyType.Name == "Int32") property.SetValue(entity, Convert.ToInt32(propertyValue), null); else if (property.PropertyType.Name == "String") property.SetValue(entity, propertyValue, null); } } return entity; }
Here we need to follow a convention to get it working. The convention I follow here is, the Property name in the DTO and the table field should be same.
Let’s see how we can use it.
SqlCommand cmd = new SqlCommand(qryToExecute, connection); SqlDataReader reader = cmd.ExecuteReader(); List<ItemDetails> itemDetails = SQLHelper.CopyDataReaderToEntity<ItemDetails>(reader);
Create Select and Insert SQL statement Dynamically
When I was dealing with some table that have a lot of fields, I always have trouble in creating select or insert statement. So I created a small function that creates the Select and Insert statement dynamically. Here also I follow the same convention I explained earlier, that is the field name and the property name should be same.
private static List<FiledAndValueHolder> CreateFieldValueMapper<TEntity>(TEntity entity)
where TEntity : class { List<FiledAndValueHolder> filedAndValues = new List<FiledAndValueHolder>(); PropertyInfo[] properties = typeof(TEntity).GetProperties(); foreach (PropertyInfo property in properties) { object propertyValue; string propertyName; if (property.CanRead) { if (property.PropertyType.Name != "String" &&
property.PropertyType.Name != "Single" &&
property.PropertyType.Name != "Int32") continue; propertyValue = property.GetValue(entity, null); propertyName = property.Name; if (propertyName.StartsWith("Native")) continue; FiledAndValueHolder fieldAndValue = new FiledAndValueHolder(); fieldAndValue.FieldValue = propertyValue; fieldAndValue.FiledName = propertyName; fieldAndValue.FieldType = property.PropertyType.Name; filedAndValues.Add(fieldAndValue); } } return filedAndValues; } public static string CreateInsertStatement<TEntity>(TEntity entity, string tableName)
where TEntity : class { List<FiledAndValueHolder> filedAndValues = CreateFieldValueMapper<TEntity>(entity); string sql = "insert into [dbo]." + tableName + "({0}) values ({1})"; StringBuilder fieldBuilder = new StringBuilder(); StringBuilder valueBuilder = new StringBuilder(); string seprator = string.Empty; foreach (FiledAndValueHolder filedAndValue in filedAndValues) { fieldBuilder.Append(seprator); fieldBuilder.Append(filedAndValue.FiledName); valueBuilder.Append(seprator); if (filedAndValue.FieldType == "String") { valueBuilder.Append(string.Format("'{0}'", filedAndValue.FieldValue as string)); } else { valueBuilder.Append(filedAndValue.FieldValue); } if (string.IsNullOrEmpty(seprator)) seprator = ","; } string sqlStatement = string.Format(sql, fieldBuilder.ToString(), valueBuilder.ToString()); return sqlStatement; }
public static string CreateSelectStatement<TEntity>(TEntity entity, string tableName, string selectCondition) where TEntity : class { List<FiledAndValueHolder> filedAndValues = CreateFieldValueMapper<TEntity>(entity); string sql = "select {0} from dbo.{1} where ({2})"; StringBuilder fieldBuilder = new StringBuilder(); string seprator = string.Empty; foreach (FiledAndValueHolder filedAndValue in filedAndValues) { fieldBuilder.Append(seprator); fieldBuilder.Append(filedAndValue.FiledName); if (string.IsNullOrEmpty(seprator)) seprator = ","; } return string.Format(sql, fieldBuilder.ToString(), tableName, selectCondition); }
Let’s see how we can use it.
insertItemMaster = SQLHelper.CreateInsertStatement<ItemMaster>(itemMaster, "ItemMaster");
Most of the functions I explained above doesn’t required much explanations. If any one need any more details then leme know.
db4o A light weight Object Oriented Database
Now a days I am spending my free time in rewriting one of my freeware for Flickr users called iTraveller. One of the design goals was the application should be scalable. My major concern was, I cannot freeze my db design before my first release because I am planning to have multiple version with added functionalities, so the db structure may change in the future. If I use conventional db’s then I have to write functionality to add or remove columns. iTraveller is not very data centric application, so managing db change scripts and writing a functionality to apply these changes when user upgrade to new version will be a big pain for me.
First I thought of using MongoDB, because I used Mongo db in a Silverlight application. But then finally dropped that idea. I want some thing more lighter than Mongo and NoSql sort of database. I evaluated several db’s but nothing suites what I am looking for. Finally my search ends at db4o. The usage of db4o is very straight forward and very easy to learn, db4o installer comes with a very good documentation to start off with the development.
db4o is a light weight Object Oriented database. Using db4o I can persist my entities very easily without any configuration. I can add or remove new properties to my entities without affecting the existing persisted entities.
I created a generic repository sort of class around db4o, the same way I did one for Entity Framework. This generic repository reduced lot of my work and act as the entry point to persist my entities to db4o data file. Below is the Generic repository I created for db4o.
using Db4objects.Db4o;
public class GenericRepository:IRepository,IDisposable { private static IRepository _singleRepoInstance; public const string DBNAME = "Data.dat"; public static IRepository GetRepositoryInstance() { if (_singleRepoInstance == null) _singleRepoInstance = new GenericRepository(); return _singleRepoInstance; } IObjectContainer _context = null; private IObjectContainer Context { get { if(_context==null) _context = Db4oFactory.OpenFile(DBNAME); return _context; } } private IList<TEntity> Query<TEntity>() where TEntity : class { return this.Context.Query<TEntity>(); } public IList<TEntity> GetAll<TEntity>() where TEntity : class { return this.Query<TEntity>().ToList(); } public IList<TEntity> GetAll<TEntity>(TEntity entity) where TEntity : class { return this.Context.QueryByExample(entity).Cast<TEntity>().ToList(); } public IList<TEntity> Find<TEntity>(Func<TEntity, bool> criteria) where TEntity : class { return this.Query<TEntity>().Where<TEntity>(criteria).ToList<TEntity>(); } public TEntity Single<TEntity>(Func<TEntity, bool> criteria) where TEntity : class { return this.Query<TEntity>().Single<TEntity>(criteria); } public TEntity First<TEntity>(Func<TEntity, bool> criteria) where TEntity : class { return this.Query<TEntity>().FirstOrDefault<TEntity>(criteria); } public TEntity First<TEntity>(TEntity criteria) where TEntity : class { return this.Context.QueryByExample(criteria).Cast<TEntity>().First<TEntity>(); } public void Add<TEntity>(TEntity entity) where TEntity : class { this.Context.Store(entity); } public void Add<TEntity>(List<TEntity> entities) where TEntity : class { foreach (TEntity entity in entities) { this.Add<TEntity>(entity); } } public void Delete<TEntity>(TEntity entity) where TEntity : class { this.Context.Delete(entity); } public void Update<TEntity>(TEntity entity) where TEntity : class { this.Context.Store(entity); } public void Dispose() { this._context.Close(); this._context.Dispose(); this._context = null; } }
The above repository is created in singletone mode. I did that way because I noticed that opening the database file is taking some delay and wanted to avoid that delay. So I wont close the data file until iTraveller get closed.
Let’s see how we can call the above repository to save an entity
GenericRepository repository = GenericRepository.GetRepositoryInstance(); repository.Add<Photo>(photos);
Below is the way we can retrieve some entities from the data file
IRepository repository = GenericRepository.GetRepositoryInstance(); List<LocalCategory> categories = repository.GetAll<LocalCategory>().ToList<LocalCategory>();
You can also retrieve data based on any condition as well. The below code will return a list of Photo object whose categoryId is 10.
IRepository repository = GenericRepository.GetRepositoryInstance(); return repository.Find<Photo>(p => p.Category.ID == 10).ToList<Photo>();
As you can see the db4o is very easy to use light weight database without the hurdles of mapping to tables and all sort of stuffs.
Approach to count dominant colors in a image
This will be a small post that give some brief idea about how to calculate dominant colors in a image. Before going in further details I wanted to explain some background of my problem. The project I currently working on needs to count colors in a image. The count should not take all the different colors in the image, that means it should merge similar colors and count it as one. For e.g if there is a Red and light red then the count should be one, i.e Red. Just like human eye counts colors.
To solve the issue I tried different approach including Histogram quantization and several other approach. But nothing worked well. Then thought of applying some algorithm I come across when I was doing some research in collective intelligence, Euclidean distance algorithm and KMeans clustering algorithm.
This is how I solved the issue.
Step 1: Scan through the image and get all the pixels. Group similar pixels and also increase the count. I use a hash table for grouping. After the scanning I will get a hash table with all the colors and the count of each colors.
Step 2: Find out the dominant colors using the pixel count and remove the nearest pixels. To find the nearest color in the same domain I use Euclidean distance algorithm. I meant by dominant color is the color that has more pixel count. While removing the color, we should not remove the dominant color.
Step 3: The above step still will not give accurate results, this step 2 result will just a give a starting point for color count. I use the result from Step 2 as the cluster for applying KMeans clustering algorithm. For clusters take only the top n higher pixel counted colors from Step 2. Apply the clustering on the pixel data we got from Step 1.
Step 4: Apply the Euclidean distance on the result we got from Step 3. The result will be closer to the count of colors in the image. You can tweak to get closer result by increasing or decreasing the distance cutoff value.
I tested this method with images with less size, it may have worst performance in big images. There may be different more accurate method might be their. I cant do much with my limited knowledge on Image processing.
I will be more happy if any one can provide me a better approach. You can add it to the comment section.
Using await in real world asynchronous programming–Part 2
This is the continuation to my previous post related to new async ctp. In the previous post I explained the use of await using a webclient. This post I am going to explain how can we use await in real life scenario. In real life you may not only deal with webclient, you may wanted to do a time consuming database call or you wanted to do some time consuming process or whatever in asynchronous manner, at the same time our UI should be responsive.
I did a lot of search to find a scenario to deal expensive process other than calling a webclient but no use. So I thought it will be good to post some real life scenario as most of the blogs explain the async ctp with webclient or in some complex way that person like me cant understand.
Async CTP simplify the way we write asynchronous methods, with async ctp no BeginXXX and no EndXXX. So let’s go through the scenario with a small intro.
Currently am in the process of rewriting one of my app called iTraveller. My prime focus is a very responsive UI with less app loading time. The app requires to load categories and lot of thumbnails at startup. I am doing lot of these process at startup and if we do it synchronously it will affect the application startup speed. When async CTP launched, I jumped into to it, because I know that it’s very useful for me.
Below is a piece of code we normally write to load some data from a database.
public List<LocalCategory> GetAllCategories() { IRepository repository = GenericRepository.GetRepositoryInstance(); return repository.GetAll<LocalCategory>().ToList<LocalCategory>(); }
Here I used the Generic repository model I explained earlier in my blog. The above method is a synchronous call and the caller should wait till the db calls complete. Am going to rewrite the above method in async mode.
public async Task<List<LocalCategory>> GetAllCategoriesAsync() { IRepository repository = GenericRepository.GetRepositoryInstance(); return await TaskEx.Run(() => { //write the time consuming process here return repository.GetAll<LocalCategory>().ToList<LocalCategory>(); }, System.Threading.CancellationToken.None); }
Here I converted a synchronous method to an asynchronous one, It’s as simple as that. Let’s see how can we call the above method.
private async void LoadExistingCategory() { CategoryService categoryService = new CategoryService(); var categoriesTask=await categoryService.GetAllCategoriesAsync(); this.ExistingCategories = categoriesTask.ToList<LocalCategory>(); }
You can call the async method in button event handler or where ever you want to call. But the caller should marked as async, the above method I added async just after the private.
LocalCategory is one of my entity class in the application.
I wrote a very expensive Euclidean distance algorithm using async mode and it worked very well. The same without async will keep the UI busy for two seconds and the user will be blocked from doing any action.
Using await in asynchronous programming
In the recent release of VS Async CTP introduced a new way of placing async calls using await. I did a small analysis with the Async CTP. Based on my limited analysis I felt like the new CTP wont make much difference in making WCF calls from silverlight, only workarounds. In other hand the new feature is good to develop asynchronous API’s much clean and easier.
First lets see how we normally make async calls, for the demo I choose webclient as it is easy.
WebClient wc = new WebClient(); wc.DownloadStringCompleted += (o, e) => { if (e.Error == null) { //do our work } }; wc.DownloadStringAsync(new Uri(“http://api.twitter.com/1/statuses/public_timeline.xml”), null);
In the above approach the call will be done in single method. Then what’s the use of await, leme explain. Think about a scenario were, you wanted to call the twitter api and the function should return the result. The current scenario it’s not possible. The function will return back to the caller before the async calls completed. Here is were the await will come into picture.
I am going to rewrite the code using await. To use new CTP, I need to refer AsyncCtpLibrary.dll located in C:\Users\<UserName>\Documents\Microsoft Visual Studio Async CTP\Samples. Add namespace system.threading.tasks
private static async Task<string> DownloadGoogleHomePageAsync() { WebClient wc = new WebClient(); var byteArr = await wc.DownloadDataTaskAsync(new Uri("http://api.twitter.com/1/statuses/public_timeline.xml")); return System.Text.Encoding.ASCII.GetString(byteArr); }
as you can see above my new function will return the result of the async call. This approach eradicate the anonymous or lambda way of calling the async function. With this approach we can do an if condition check or what ever we need just like a normal function call.
I can call the above function as shown below.
string content = DownloadGoogleHomePageAsync().Result;
I am not going to explain the more technical details here. MSDN has a white paper giving an in depth knowledge of await and Task based programming.
Await In Silverlight
Await functionality is also available in Silverlight. I will be more happy if I could able to call a WCF service using await from Silverlight. Currently WCF wont serialize Task/Task<T>, so there is no direct way of calling await with a WCF service method. One workaround is mentioned in the msdn forum, I haven’t tried yet. I use Reactive extension to call async methods.
In one of Amadeo Casas blog mentioned that WCF team is working to adopt async model. I am awaiting for the WCF vNext release :).
Await in Real Life scenario
See my other post to see how to use await in real life scenario like doing a time consuming database call or doing a time consuming algorithm.
An Introduction to Caliburn Micro
Introduction
This post gives some brief introduction to develop Silverlight applications using Caliburn Micro which gives the basic features are:
- BootStrapping
- Conventions to write ViewModels
- Event Aggregation
- Action Message
Once you got the above basic ideas, it’s very easy to develop scalable applications in Silverlight. You can download the latest Caliburn Micro source from CodePlex.
When MVVM pattern introduced into my Silverlight development, initially it’s not digesting for me. But after I got the clear picture of MVVM pattern, I felt It’s very easy to develop Silverlight application that can adaptable to changes very easily. We choose Caliburn Micro as our MVVM framework, one reason it’s very light weight, another reason is the code base is very less. As the code base is very less we can go through it understand it better.
I hope every one who reads this post has some idea of MVVM pattern. In short MVVM separates View (presentation) and the code manipulates the view separately, and called it as View Model. One of the main advantage of MVVM is we can modify View or ViewModel without affecting each other. There is no event handlers for any control in the code behind, so it’s easy to replace one control with another. We can even reuse the same view model for different platform, let say we are developing an app for both Silverlight and WP7, here only difference in view is it’s base classes but UI is same. So we can share the same View Model thus by increase the maintainability and decrease the effort.
How the View and View Model’s will communicate? here the MVVM framework like Caliburn Micro will comes into picture. The MVVM Framework will bind the View and View Model’s. There are several MVVM frameworks in the market like Prism, MVVM Light, etc. but am not going to cover those.
Caliburn Micro uses conventions to bind View and View Model’s, I feel the conventions are better than wiring through code or attributes. You will get the conventions of Caliburn Micro as we progress through this post.
There are two approach in MVVM model, Code first and View first. Which one is better? I am not the person to comment on, their is an age old debate is going on. Personally I prefer Code First approach. But here to simplify things I will do it in View First approach.
Caliburn Micro In Action
Let’s do some small application in Silverlight using Caliburn Micro. The functionality of this app is pretty simple, display a list of customer and allow the user to edit it.
I am going to create a user control to display the details of individual customer. In the listing page we will bind this User control to a List. Let’s create the control.
IndividualResultView.xaml
<Grid x:Name="LayoutRoot" Background="White"> <Border BorderThickness="3" BorderBrush="Black" Margin="3"> <Grid Margin="5"> <Grid.RowDefinitions> <RowDefinition Height="30"></RowDefinition> <RowDefinition Height="60"></RowDefinition> <RowDefinition Height="30"></RowDefinition> <RowDefinition></RowDefinition> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition Width="120"></ColumnDefinition> <ColumnDefinition></ColumnDefinition> </Grid.ColumnDefinitions> <TextBlock x:Name="lblName" Text="Name" Grid.Row="0" Grid.Column="0"></TextBlock> <TextBlock x:Name="Name" Grid.Row="0" Grid.Column="1"></TextBlock> <TextBlock x:Name="lblAddress" Text="Address" Grid.Row="1" Grid.Column="0" ></TextBlock> <TextBlock x:Name="Address" Grid.Row="1" Grid.Column="1"></TextBlock> <TextBlock x:Name="lblPhoneNumber" Text="Phone#" Grid.Row="2" Grid.Column="0"></TextBlock> <TextBlock x:Name="PhoneNumber" Grid.Row="2" Grid.Column="1"></TextBlock> <HyperlinkButton x:Name="EditCustomer" Grid.Row="3" Content="Edit"></HyperlinkButton> </Grid> </Border> </Grid>
IndividualResultView.xaml.cs
Let’s see the IndividualResultView.xaml.cs, as per the MVVM pattern it should not contain any View related code, other than initializing the UI controls. You can see that our code behind is clean.
using System.Windows.Controls; namespace WCFEnabledSilverlightApp.Views { public partial class IndividualResultView : UserControl { public IndividualResultView() { InitializeComponent(); } } }
We need to create a ViewModel for the above view, let’s do it. I named my ViewModel as IndividualResultViewModel.cs. Below is the code
using DataModel; using Caliburn.Micro; namespace WCFEnabledSilverlightApp.ViewModels { public class IndividualResultViewModel:PropertyChangedBase { string _name; public string Name { get { return _name; } private set { _name = value; NotifyOfPropertyChange(() => Name); } } string _address; public string Address { get { return _address; } private set { _address = value; NotifyOfPropertyChange(() => Address); } } public string PhoneNumber { get; private set; } private Customer _customer = null; public IndividualResultViewModel(Customer customer) { this._customer = customer; this.Name = customer.CustomerName; this.Address = customer.Address; this.PhoneNumber = customer.PhoneNumber; } public void EditCustomer() { EditCustomerViewModel editCustomer = new EditCustomerViewModel(_customer); Screen scrn = new Screen(); WindowManager winMngr = new WindowManager(); winMngr.ShowDialog(editCustomer); } } }
Convention 1
We learned our first convention of Caliburn Micro. The UI should suffix with “View”. The View Model should suffix with “ViewModel” and prefix with ViewName
<ViewName>View.xaml
<ViewName>ViewModel.cs
Eg.
IndividualResultView.xaml
IndividualResultViewModel.cs
Convention 2
You might have noticed that in the view and viewmodel we used some convention. The name of TextBlock that display the customer details have a corresponding property in ViewModel. For E.g. the TextBlock name for displaying Customer Name is “Name” and in ViewModel you can see a property “Name”. The Caliburn Micro will bind the Property in the ViewModel to the View. That means what ever value we set for property “Name” will be displayed in the View. Pretty simple.
You might have one question now how to handle click event or those kind of events raised by your view in our View model. It’s pretty easy create a function with same name as your button. Just go back to the View and check the name of the hyperlink button, also check whether their is method with same name in View model. Hyperlink button name is EditCustomer and I have one method in View model EditCustomer. The method will create an instance of another view model.
Later in this post you can see how we can pass parameters from your view to view model.
NotifyOfPropertyChange
In our properties the setter calls a function called NotifyOfPropertyChange, what is the use of this function call? We call this function to notify the UI that the value has changed in the view model. We can notify UI without calling NotifyOfPropertyChange by implementing INotifyPropertyChanged interface and pass the property name. Caliburn Micro wraps the implementation of INotifyPropertyChanged in PropertyChangedBase and our view model is inherited from it. NotifyOfPropertyChange we are not passing any string value instead we pass the Property itself. The advantage of this method is we can use VS refactoring feature on properties. If we pass it as string then refactoring will not take into consideration.
Event Handling
When I implemented MVVM using Caliburn Micro I implemented the communication between View Models using normal event driven mechanism. That means If I want to handle an event occurred in a child view model in the parent. Then child view model raise an event and the parent will handle it. I didn’t like this approach as it creates a dependency between View models. So I start exploring Caliburn Micro to figure out the event handling features and my search ends in EventAggregator.
Caliburn Micro’s Event Aggregator functionality is a very powerful implementation of Observer pattern. We can write View Models with less coupling using EventAggregators. Let’s see how can we establish communication between View Models using Event Aggregator.
In the sample code I created a static property to give access to EventAggregator as shown below
public class EventAggregationProvider { static EventAggregator _eventAggregator = null; public static EventAggregator EventAggregator { get { if (_eventAggregator == null) _eventAggregator = new EventAggregator(); return _eventAggregator; } } }
In the sample app I have a popup window to edit the Customer Details, when the user clicks Save/Ok I need to notify the Parent View Model to initiate the Save process. Let’s see how to implement it.
In my CustomerEditViewModel.cs there is a method called SaveCustomer which will get called when the user clicks Ok from the View. You can see that in SaveCustomer I am publishing the Customer object. See how I am publishing it.
EventAggregationProvider.EventAggregator.Publish<Customer>(customer);
This ViewModel done his job, it’s job of the parent view model who can subscribe to this message and get the notification. Now let’s see how the parent view model is subscribing to this event.
public class CustomerListingViewModel : PropertyChangedBase, IHandle<Customer> {
public CustomerListingViewModel()
{
Messages.EventAggregationProvider.EventAggregator.Subscribe(this);
}
public void Handle(Customer message) { //do the save process }
}
To Subscribe to Customer message the CustomerListingViewModel is implemented by IHandle<Customer>. That means this CustomerListingViewModel is capable of handling any message with type Customer. One more line of code need to added to get notification. You can see in the constructor of CustomerListingViewModel to subscribe to EventAggregator.
Your View Model can subscribe to any number of messages by implementing IHandle with the respective type. For e.g
public class CustomerListingViewModel : PropertyChangedBase, IHandle<Customer>,IHandle<Order> {
public CustomerListingViewModel()
{
Messages.EventAggregationProvider.EventAggregator.Subscribe(this);
}
public void Handle(Customer message) { //do the save process }
public void Handle(Order message)
{
//do the save process
}
}
In the above e.g this View Model will get notified if any view model publish Customer or Order message.
Action Message
The Action Message is one of the functionality of Caliburn Micro to call parameterized function from View. Let’s see how we can do it. To do this we need to refer system.windows.interactivity assembly.
In the below e.g. a message box will show when a LostFocus happened in View EditCustomerView. Let’s go through the View
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity" xmlns:ca="clr-namespace:Caliburn.Micro;assembly=Caliburn.Micro"
<TextBox x:Name="Name" Grid.Row="0" Grid.Column="1"> <i:Interaction.Triggers> <i:EventTrigger EventName="LostFocus"> <ca:ActionMessage MethodName="NameLostFocus"> <ca:Parameter Value="{Binding ElementName=Name,Path=Text}"></ca:Parameter> </ca:ActionMessage> </i:EventTrigger> </i:Interaction.Triggers> </TextBox>
I referenced System.Windows.Interactivity and Caliburn Micro in the View. As you can see in the above view I mentioned “LostFocus” to the EventName. The ActionMessage takes the MethodName that we created in the ViewModel. Parameter’s Value take the parameter to the method. So what’s this means, it’s very simple, whenever the lost focus happened in Name text box then the view should call NameLostFocus method with TextBox’s Text as the parameter. Below is the NameLostFocus method in the ViewModel
public void NameLostFocus(string text) { MessageBox.Show(text); }
You can see more about Action Message in Rob’s blog
Bootstrapping
Bootstrapping is the method of booting our application and allow Caliburn Micro to take the control. So how to create a bootsrapper. It’s very simple as shown below
namespace WCFEnabledSilverlightApp { public class BootStrapper:Bootstrapper<ViewModels.CustomerListingViewModel> { } }
It’s tells caliburn that CustomerListingViewModel is the first page to load. It’s same as setting RootVisual to the some page say MainPage in non MVVM model. We need to provide this BootStrapper in App.xaml as shown below
<Application xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Class="WCFEnabledSilverlightApp.App" xmlns:bs="clr-namespace:WCFEnabledSilverlightApp" > <Application.Resources> <bs:BootStrapper x:Name="bootStrapper"></bs:BootStrapper> </Application.Resources> </Application>
Below is code behind of App.xaml. No code just clean.
using System.Windows; namespace WCFEnabledSilverlightApp { public partial class App : Application { public App() { InitializeComponent(); } } }
This post is just an introduction to Calibun Micro, just use it and get more comfortable with it. Thanks for reading this long post.
Introduction to Caliburn Micro Part 2
Download the source code.
Making Async calls in Silverlight using Reactive Extension (Rx)
In this blog I am going to explain briefly about how to make async calls using Reactive Extension (Rx). Every one knows that Silverlight is one of the best platform to create RIA’s. One of the architecture constrain of Silverlight is, it wont directly interact with backend DB. So we need to have a webservice to perform the db operations. Silverlight can consume WCF or asmx service, but their is a catch silverlight can only communicate to webservices asynchronously. We all know that async calls have several advantages. One key feature of async call is, it wont block the UI while performing the call. But one downside in async programming is the coding pattern involved in placing async calls. When I place an async calls, I use an anonymous delegate approach or use lambda expression. But some how I am not satisfied with any of these approaches, I feel my code is not clean. So we always look for a better approach and our long waiting is over with the introduction of Reactive Extension (Rx) from MS labs.
You can visit Rx web site to get more details. I am not a person to explain the architecture or indepth details of Rx instead I am going to show how it benefit me in my async programing. I am going to rewrite one of my application I wrote to upload images using Silverlight and WCF, you can get more details of that app from my blog. I will rewrite only the part where I make async calls to server to get images from WCF service. Before get into refactoring, We need to download and install the Rx libraries from Rx web site.
Let’s refactor the code to make our async calls using Rx. We need to add couple of assembly references to add Rx to Silverlight, below are those assemblies.
- System.Observables
- System.CoreEx
- System.Reactive
I demonstrated two ways of interacting with WCF service in the source code I uploaded. A proxy and proxy less approach. We all know the proxy approach, the communication to the service using the class generated by VS. In one of my post I provided some insight of Proxy less approach, you can check it out here.
If you have my source code in hand, have a look at the ImageListViewModel.cs in Silverlight app. You can see how I am making the async call.
In proxy less approach I use lambda expression to make the call.
IImageServiceAsync imgService = ServiceChannelProvider.CreateChannel<IImageServiceAsync>(); imgService.BeginGetAllImage(save => { try { imgs = imgService.EndGetAllImage(save); this.AddToUserLogoList(imgs); } catch (Exception ex) { throw; } }, imgService);
In proxy approach I used a event driven approach as shown below.
ImageServiceClient imgClient = new ImageServiceClient(); imgClient.GetAllImageCompleted += new EventHandler<GetAllImageCompletedEventArgs>(imgClient_GetAllImageCompleted); imgClient.GetAllImageAsync();
void imgClient_GetAllImageCompleted(object sender, GetAllImageCompletedEventArgs e) { for (int i = 0; i < e.Result.Length; i++) { this.UserLogos.Add(e.Result[i]); } NotifyOfPropertyChange(() => UserLogos); }
I am not going to explain the downside of these approaches mentioned above, Just like me you all might have experienced it. Lets rewrite the code using Reactive Extension (Rx).
Proxy less approach
private void ReadAllImages() { IImageServiceAsync imgService = ServiceChannelProvider.CreateChannel<IImageServiceAsync>(); var func = Observable.FromAsyncPattern<IList<UserImage>>(imgService.BeginGetAllImage, imgService.EndGetAllImage) .Invoke() .SubscribeOnDispatcher() .Subscribe(s => this.UserLogos = s.ToList<UserImage>()); }
Rx have one method called FromAsyncPattern, there we can provide our Beginxxx and Endxxx functions. I provided BeginGetAllImages and EndGetAllImages to FromAsyncPattern function. I also provided the return type of EndGetAllImages() to FromAsyncPattern function. Return type of EndGetAllImages is IList<UserImage>, so I called FromAsyncPattern as FromAsyncPattern<IList<UserImage>>. Rx uses Observer pattern to publish the result. So here I added UserLogos properties as my observer, once the execution is done the result will be pushed to the observer. Here the observer is a property in my view model. Below is the UserLogos property
List<UserImage> _logos = new List<UserImage>(); public List<UserImage> UserLogos { get { return _logos; } private set { lock (this) { _logos = value; NotifyOfPropertyChange(() => UserLogos); } } }
Let’s see how we can make an async call in proxy generated approach.
private void ReadAllImages() { ImageServiceClient imgClient = new ImageServiceClient(); var o = Observable.FromEvent<GetAllImageCompletedEventArgs>(imgClient, "GetAllImageCompleted") .ObserveOn(Scheduler.ThreadPool) .Select(result => result.EventArgs.Result) .Subscribe(s => this.UserLogos = s.ToList<UserImage>()); imgClient.GetAllImageAsync(); }
Here I used FromEvent function provided by Rx instead of FromAsyncPattern. FromEvent accepts the event type, here it is GetAllImageCompletedEventArgs. It also accepts the service client object and which event it should handle. I passed the GetAllImageCompleted to the FromEvent function. Then we need to attach UserLogos as observer. After that we called GetAllImageAsync of service proxy.
You can see our code is pretty clean, we don’t have any messy code that we normally write to handle the async calls. Once you start using Rx I think you will never go back to the old approach of placing async calls.
