Sony Arouje

a programmer's log

Archive for the ‘WPF’ Category

Asynchronous Messaging in iTraveller

with 2 comments

Download iTraveller

I decided to use Lucene.Net to implement Search functionality in iTraveller. But the main design constrain was how to implement the indexing process without affecting the performance of any other functionality. Below are my use cases

  • Should start indexing asynchronously, no other process like Insert/Update should wait to complete indexing.
  • Other process like Insert/Update send a message to Indexing process and continue without waiting to finish the indexing process.
  • Lucene.Net will apply lock before start indexing. So only one process can access the Lucene.Net indexing API at a time.
  • Should have a single entry point for other process to invoke indexing.
  • Before indexing remove the record (if exist) from Index file.
  • Gather all the data related to photo like Photo Title, Description, Comments, etc. Index the data using Lucene.Net

In the above points, the first  one is the important thing I wanted to achieve to make iTraveller running smoothly. It’s obvious that I have to implement threading, and started my search for a thread safe queuing approach. At last I decided to use ‘Queue’ in System.Collections.Generic namespace. Let’s go through how I implemented message queue in iTraveller.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.IO;
using ITraveller.Domain;
using ITraveller.Utils.Logging;
namespace ITraveller.Indexer
{
    public class IndexQueue
    {
        private static Queue<Photo> _queue;
        private static ManualResetEvent _enqueuedEvent;
        private static Thread _workerThread;
        private static Photo _currentPhoto;
        private static ILogger _logger;
        static IndexQueue()
        {
            _queue = new Queue<Photo>();
            _logger = Logger.DefaultLogger;
            _enqueuedEvent = new ManualResetEvent(false);
            _workerThread = new Thread(new ThreadStart(PerformIndex));
            _workerThread.Start();
        }
        public static void RestartThread()
        {
            if (_workerThread.ThreadState == ThreadState.Stopped)
            {
                _workerThread.Abort();
                _workerThread = new Thread(new ThreadStart(PerformIndex));
                _workerThread.Start();
            }
        }
        public static void Add(Photo photo)
        {
            try
            {
                if (_queue == null)
                    _queue = new Queue<Photo>();
                lock (_queue)
                {
                    _queue.Enqueue(photo);
                    _enqueuedEvent.Set();
                }
                RestartThread();
            }
            catch (Exception ex)
            {
                _logger.LogInfo("Error while Adding to index Queue");
                _logger.LogError(ex);
            }
        }
        public static void Add(List<Photo> photos)
        {
            if (_queue == null)
                _queue = new Queue<Photo>();
            for (int i = 0; i < photos.Count; i++)
            {
                try
                {
                    lock (_queue)
                    {
                        _queue.Enqueue(photos[i]);
                        _enqueuedEvent.Set();
                    }
                }
                catch (Exception ex)
                {
                    _logger.LogInfo("Error while Adding to index Queue in loop");
                    _logger.LogError(ex);
                }
            }
            RestartThread();
        }
        private static bool Dequeue()
        {
            lock (_queue)
            {
                if (_queue.Count > 0)
                {
                    _enqueuedEvent.Reset();
                    _currentPhoto = _queue.Dequeue();
                }
                else
                {
                    return false;
                }

                return true;
            }
        }

        private static void PerformIndex()
        {
            IndexWriter writer=null;
            try
            {
                writer = new IndexWriter("./SearchIndex");
                while (Dequeue())
                {
                    IndexData indexData = new IndexData();
                    writer.DeleteFromIndex("ImageId:" + _currentPhoto.ImageID.ToString());
                    writer.WriteToIndex(indexData.GetIndexingData(_currentPhoto));
                }
            }
            catch (Exception ex)
            {
                _logger.LogInfo("Error while indexing data in worker thread");
                _logger.LogError(ex);
            }
            finally
            {
                if(writer!=null)
                    writer.Dispose();
            }
        }
    }
}

Other process can add Photo entity for indexing just by calling the static Add function and pass the required Photo( s ) object as parameter. Once the photo got added to queue, the Add function will call RestartThread function. The RestartThread function will check whether the worker thread Stopped, if Stopped then Recreate and Start the thread.

The function PerformIndex will get called when the worker thread starts. The PerformIndex function will dequeue the photo one by one from the Queue. Once the photo is dequeued successfully then one helper class will create and format the data for indexing and then  pass it to Lucene.Net class for further processing. The dequeue process will remove the photo object from the queue as well.

With the above approach I achieved a complete asynchronous messaging system. Any suggestion or better approach is always welcome.

Written by Sony Arouje

February 21, 2011 at 6:30 pm

Introduction to Caliburn Micro – Part 2

with 5 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 9 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

%d bloggers like this: