Sony Arouje Blog

a programmer's log

Archive for the ‘Silverlight’ Category

Introduction to Caliburn Micro – Part 2

with 4 comments

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 Smile. Thanks for reading. Any questions or comments pls update it in the comment section.

Written by Sony Arouje

February 16, 2011 at 2:51 pm

Populate Listbox Asynchronously using Await and Reactive Extension (Rx)

with 8 comments

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.

Written by Sony Arouje

February 15, 2011 at 6:24 pm

iTraveller–A photo uploader for Flickr and Facebook

with 5 comments

 

Download iTraveller

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

  1. WPF
  2. Caliburn Micro
  3. Async CTP
  4. MEF
  5. Facebook SDK
  6. Flickr SDK
  7. Reactive Extension (Rx)
  8. Lucene .NET
  9. db4o

 

Let’s see some screen shots of iTraveller

Home Screen

home

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.

FlickrUploadBasket

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.

FacebookUploadBasker

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.

SearchResult

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.

CommentButton

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.

CommentView

Preview Tab

Preview tab will display the image in preview mode. Below the preview image, you can see below buttons

image

Fullscreen-64

Clicking on the button will show the photo in Full screen. The background of Full screen mode is 18% gray. 

user-comments-icon

View Comments button, this button will be visible only if the preview photo have any comments.

thumbnail

By default the Local Set thumbnail is randomly picked. Any time you can change the thumbnail image of a Local set. Select the category and select the desired photo from the thumbnail. In the preview tab click on this button. Done… your Local set thumbnail is changed instantly.

notes-edit-icon

Note button opens a small popup and you can add a Title and Description to your photo.

 

More feature will get added in next release, but needs motivation. Use my iTraveller and Motivate me Smile.

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

  1. ITravellerData.data  (File)
  2. FacebookThumbnails  (Folder)
  3. FlickrThumbnails  (Folder)
  4. SearchIndex  (Folder)

 

Download

I uploaded the application here. Install it and let me know your feed back.

Written by Sony Arouje

February 13, 2011 at 10:53 pm

Approach to count dominant colors in a image

with 3 comments

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.

Written by Sony Arouje

December 17, 2010 at 12:04 am

Posted in .NET, Silverlight

Tagged with ,

Using await in asynchronous programming

with one comment

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.

Written by Sony Arouje

November 30, 2010 at 7:20 pm

Posted in .NET, Silverlight

Tagged with ,

Photo Album using Silverlight,Caliburn Micro and MongoDB–Part 2

with one comment

This post is a continuation to my another post about a photostream application in Silverlight 4. You all can read more about the post here. I publish the code to codeplex with some more updates. The functionalities added to application is as below

  • Add/Delete Categories
  • Public commenting for Photos
  • Delete Photo
  • Filter photo’s based on Category

Below are some of the functionality in the app.

Home Page

Home

The home page will display the thumbnails of all your photos. In the right hand pane you can see the list of categories I created. User can see the photos in a particular category by clicking the category. You can add category by clicking on the Add/Edit category in the right hand side.

Photo Preview

PreviewPhoto

Nothing much to say it just show a preview of your photo. As you can see there are some icons at the bottom of the preview window. One for adding/viewing comments and another for deleting the photo. You might wonder how a public user can delete a photo. No they can’t am working on the admin part once it’s added only the admin user can do the delete and other admin related functionalities.

Public Comment(s)

PhotoComments

Clicking on the small icon next to the delete button will show the comments as well as user can add comments.

Upload Photos

UploadPhoto 

You can upload multiple photos at a time. Currently assigning a photo to category can be done at the time of uploading.

Hope this app will be helpful for some one.

Download Source code.

Written by Sony Arouje

November 28, 2010 at 12:56 am

Photo Album using Silverlight, Caliburn Micro and Mongo DB

with 14 comments

In this post I am going to explain a small Photo Album I created using Silverlight. With this app I also joined the band wagon of NoSQL movement. I used MongoDB as my backend for this application. This application is still in the development mode. I will add more functionality to this application like Public comments, admin module, etc. Currently this app shows the functionality of admin module, like upload photo, delete photo, etc. The application uses MVVM pattern and as usual I used Caliburn Micro here. I used several framework in the app as shown below

  • Silverlight
  • Caliburn Micro
  • Reactive Extension
  • MongoDB
  • WCF

In this application I used Reactive Extension (Rx) to perform Async service calls. I felt the Rx is a very powerful tool to perform Async calls. The one good advantage of Rx is you can place Async calls in Thread Pool and push it to dispatcher once the call completed. All these can be done in one or two lines of code. This way the UI will always responsive.

This is my first experiment with Mongo db, I can say it’s very easy to use and fast. There are several Mongo drivers for .NET available in the market and is free. I used the one from here. The advantage of Mongodb is, I don’t want to write code to map my POCO to tables. You can directly persist your entity to Mongodb. You can find a lot of article about Mongo db in internet

I don’t think I need to explain Caliburn Micro in detail here. I wrote a post that gives a brief introduction to Caliburn Micro.

Running MongoDB

Below are the steps to run MongoDB

  1. Download the latest version of Mongo db from Mongodb.org
  2. Extract the zip file to C:\Mongodb
  3. Create a Folder called data in C drive
  4. Create a subfolder called db inside data
  5. Goto command prompt and change directory to C:\Mongodb
  6. Type Mongod in the command prompt and hit enter

Now the Mongodb will listen to the default port and our app can make request. There are different ways of hosting Mongodb, you can get more details from Mongodb site.

The App

Below is the screen shot of my application.

image

This page will display the thumbnails of uploaded images. We can see the bigger image by clicking on the thumbnail as show below.

image 

The preview will display in a Windowless popup. We can delete the photo by clicking the Trash icon bottom right side of the image. We can upload images by clicking on the upload icon at the top right of the window. The upload page will get displayed as shown below.

image

When the user upload the image, the application will create a thumbnail version of the image and store along with the original image in the server. This helps to transfer and load the thumbnail page.

Let’s see the entity used in this application.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.IO;
using System.Drawing;
using System.Drawing.Imaging;
namespace PicturePortfolio.Domain
{
    [DataContract]
    public class Photo
    {
        private const int THUMBWIDTH = 100;
        private const int THUMBHEIGHT = 100;
        public Photo()
        {
 
        }
        public Photo(PhotoPersistanceObject persistanceObject)
        {
            this.Name = persistanceObject.Name;
            this.Description = persistanceObject.Description;
            this.ID = persistanceObject.ID;
            this.PublicComments = persistanceObject.PublicComments;
            this.GUID = persistanceObject.GUID;
            
            this.LoadThumbNail();
        }

        [DataMember]
        public int ID { get; set; }

        [DataMember]
        public string GUID { get; set; }

        [DataMember]
        public byte[] ImageFile { get; set; }

        [DataMember]
        public byte[] ImageThumbNail { get; set; }

        [DataMember]
        public string Description { get; set; }

        [DataMember]
        public string Name { get; set; }

        [DataMember]
        public List<PublicComment> PublicComments { get; set; }

        public PhotoPersistanceObject GetDataForPersistance()
        {
            PhotoPersistanceObject photoPersistance = new PhotoPersistanceObject();
            photoPersistance.ID = this.ID;
            photoPersistance.Name = this.Name;
            photoPersistance.ImagePath = "/test/" + this.Name;
            photoPersistance.Description = this.Description;
            photoPersistance.PublicComments = this.PublicComments;
            if (string.IsNullOrEmpty(this.GUID) == true)
                photoPersistance.GUID = Guid.NewGuid().ToString();
            else
                photoPersistance.GUID = this.GUID;
            return photoPersistance;
        }


        public void SaveImage()
        {
            if (this.ImageFile == null)
                throw new ArgumentNullException();
            try
            {
                byte[] buffer = this.ImageFile.ToArray();
                MemoryStream memStream = new MemoryStream();
                memStream.Write(buffer, 0, buffer.Length);

                this.SaveOrginalImage(memStream);
                this.SaveImageThumbNail(memStream);
            }
            catch (Exception ex)
            {
                throw;
            }
        }

        public void LoadImage()
        {
            string fullFileName = this.GetFileFullPath();
            this.ImageFile = this.GetImageAsByteArray(fullFileName);
        }

        public void LoadThumbNail()
        {
            string fullFileName = this.GetFilePath() + this.ThumbNailImageName;
            this.ImageThumbNail = this.GetImageAsByteArray(fullFileName);
        }

        #region Private Methods
        private void SaveOrginalImage(MemoryStream memStream)
        {
            System.Drawing.Image imgToSave = System.Drawing.Image.FromStream(memStream);
            imgToSave.Save(this.GetFileFullPath(), ImageFormat.Jpeg);
        }
        private void SaveImageThumbNail(MemoryStream memStream)
        {
            Image img = Image.FromStream(memStream);
            Image.GetThumbnailImageAbort myCallback = new Image.GetThumbnailImageAbort(ThumbnailCallback);
            Image imageToSave = img.GetThumbnailImage (THUMBWIDTH, THUMBHEIGHT, myCallback, IntPtr.Zero);
            imageToSave.Save(this.GetFilePath() + ThumbNailImageName, System.Drawing.Imaging.ImageFormat.Jpeg);
        }

        private static bool ThumbnailCallback() { return false; }

        private byte[] GetImageAsByteArray(string fullFileName)
        {
            FileInfo fil = new FileInfo(fullFileName);
            if (fil.Exists == true)
            {
                FileStream fileStream = new FileStream(fullFileName, FileMode.Open, FileAccess.Read);
                byte[] buffer = new byte[fileStream.Length];
                fileStream.Read(buffer, 0, (int)fileStream.Length);
                fileStream.Close();
                return buffer;
            }
            else
                return null;
        }

        private string GetFilePath()
        {
            string filePath = AppDomain.CurrentDomain.BaseDirectory + "Images\\";
            return filePath;
        }
        private string GetFileFullPath()
        {
            string fullPath = this.GetFilePath() + this.Name;
            return fullPath;
        }
        private string ThumbNailImageName
        {
            get
            {
                string fileName = this.Name.Substring(0, Name.LastIndexOf("."));
                return fileName + "_thumb.jpg";
            }
        }
        #endregion
    }
}

 

The entity class is very simple. I may need to give a brief explanation about PhotoPersistanceObject used in the entity class. The PhotoPersistanceObject is used for persisting meta data of the image like Name, description etc. You might think that why cant we save Photo object directly, yes I also thought the same way but their is some issue with Mongodb driver I used here. It’s not supporting byte array neither binary, It allows to store binary in Mongodb but throws error while retrieving. So I used a trimmed down version of Photo entity to persist the data.

Async Calls using Thread Pool

As I told before one of the cool feature of Reactive Extension is it’s advantage of making async calls in thread pool. Even if we place async calls in separate thread in Silverlight still it will block the UI to load if we do it in page load. Because the our thread will work in UI. We can achieve the placing calls in thread pool using Rx. See the below code.

private void GetAllThumbnails()
{
    var func=Observable.FromEvent<GetAllPhotosCompletedEventArgs>(_service,"GetAllPhotosCompleted")
        .ObserveOn(Scheduler.ThreadPool);
    _service.GetAllPhotosAsync();
    func.ObserveOn(Scheduler.Dispatcher)
        .Select(result => result.EventArgs.Result)
        .Subscribe(s => this.ParseThumbnails(s.ToList()));
}

As you can see the service calls are doing in ThreadPool. Once the call is done we will change the ObserveOn to Dispatcher, other wise cross thread expection will throw. I call the GetAllThumbnails in the constructor of a ViewModel. As we are doing the call in Threadpool my UI will loaded without any delay, once the call is completed the thumbnails will start display in the listbox.

Mongodb Repository

I wrote a Generic repository similar to the one I wrote for EF. You can find the generic repository for EF in one of my post. Below is the Generic repository class for Mongodb.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MongoDB;
using MongoDB.Linq;
using MongoDB.Connections;
namespace PicturePortfolio.Persistance
{
    public class GenericRepository:IRepository
    {
        public GenericRepository()
        {
 
        }

        Mongo _mongoDb=null;
        public IMongoCollection<TEntity> GetQuery<TEntity>() where TEntity : class
        {
            if (_mongoDb == null)
            {
                _mongoDb = new Mongo();
                _mongoDb.Connect();
            }
            return DataBase.GetCollection<TEntity>(typeof(TEntity).Name + "s");
        }

        IMongoDatabase db = null;
        private IMongoDatabase DataBase
        {
            get
            {
                if (db == null)
                {
                    db = _mongoDb.GetDatabase("Protfolio");
                }
                return db;
            }
        }

        public IList<TEntity> GetAll<TEntity>() where TEntity : class
        {
            try
            {
                return GetQuery<TEntity>().Linq().ToList<TEntity>();
            }
            catch (Exception ex)
            {
                throw;
            }
        }

        public IList<TEntity> Find<TEntity>(System.Linq.Expressions.Expression<Func<TEntity, bool>> criteria) where TEntity : class
        {
            return this.GetQuery<TEntity>().Linq<TEntity>().Where(criteria).ToList<TEntity>();
        }

        public TEntity Single<TEntity>(System.Linq.Expressions.Expression<Func<TEntity, bool>> criteria) where TEntity : class
        {
            return this.GetQuery<TEntity>().Linq<TEntity>().Single(criteria);
        }

        public TEntity First<TEntity>(System.Linq.Expressions.Expression<Func<TEntity, bool>> criteria) where TEntity : class
        {
            return this.GetQuery<TEntity>().Linq<TEntity>().First(criteria);
        }

        public void Add<TEntity>(TEntity entity) where TEntity : class
        {
            this.GetQuery<TEntity>().Save(entity);
        }

        public void Delete<TEntity>(TEntity entity) where TEntity : class
        {
            this.GetQuery<TEntity>().Remove(entity);
            
        }

        public void Delete<TEntity>(IEnumerable<TEntity> entites) where TEntity : class
        {
            throw new NotImplementedException();
        }

        public void Update<TEntity>(TEntity entity, TEntity old) where TEntity : class
        {
            this.GetQuery<TEntity>().Update(entity, old, UpdateFlags.None, true);
        }
    }
}

 

This app is in very primitive stage. you may need to do lot of refactoring to make use in real scenario. I will work on this app and upload it to codeplex some times later.

Download the current source here.

Follow

Get every new post delivered to your Inbox.

Join 161 other followers

%d bloggers like this: