Tool – ProjectEuler Solution

After reading some reviews of interviews at Microsoft and Google, I am inspired to train myself for solving mathematical problems and writing algorithms. http://projecteuler.net/ is my first “mountain peak” to conquer. This website has until now more than 350 problems of many fields in mathematics. It’s suitable for training to write efficient algorithms to solve complicated computing tasks. I’m just at starter level and don’t have much time for it but when I have free time I’ll solve some of them. To manage all solved problems, I have written a GUI Tool which loads all problems as plugins, allow me to enter argument with its value and invoke the calculate method to get result back.
The tool will scan folder “Extensions” at its startup directory and load all plugins written for him. Therefore you can write your own plugin, copy to “Extensions” folder and use the tool as GUI to run your solution.
I also created a Web-version of this tool but the website version is very limited. It doesn’t permit to upload your solutions (I know you’re good hackers) and customize value of argument (I’ll improve the website version in next version so that you can customize the input).

  • Version: 1.0.0.0
  • Supported OS: All Windows

NOTE: If this tool doesn’t work with your system, post here your errors.

LINK DOWN: http://hintdesk.com/Web/Tool/ProjectEulerSolution.zip

WEBSITE: http://projecteulersolutionweb.apphb.com/ (the website is pretty slow at first load. Sorry for that, I don’t have any Windows host to host my application)

HISTORY:

  • [1.0.0.0] : Beta Version

SCREENSHOT

ProjectEuler Solution

PLUGIN INSTRUCTION
– To write your own plugin which works with this GUI tool, you should create a library and add reference to libraries

  • RPESPlugIn.dll (which can be found in “Extensions” folder)
  • System.ComponentModel.Composition.dll
  • – Your solution class must implement the IProblemSolution interface and define some attributes as example below

    [ProblemSolutionAttribute("Problem 1", @"If we list all the natural numbers below 10 that are multiples of 3 or 5, we get 3, 5, 6 and 9. The sum of these multiples is 23.
    
    Find the sum of all the multiples of 3 or 5 below 1000.
    ")]
    public class Problem1Solution : IProblemSolution
    {
    	public string GetResult(List<ProblemArg> probArgs)
    	{
    		Stopwatch stopWatch = new Stopwatch();
    		stopWatch.Start();
    
    		double result = Calculate(probArgs);
    
    		stopWatch.Stop();
    		return string.Format("Result: {0}\nTime elapsed: {1} ms", result, stopWatch.ElapsedMilliseconds);
    	}
    
    	public double Calculate(List<ProblemArg> probArgs)
    	{
    		int n = Convert.ToInt32(probArgs.First().Value) - 1;
    		return SumDivisibleBy(n, 3) + SumDivisibleBy(n, 5) - SumDivisibleBy(n, 15);
    	}
    
    	public double ProjectEulerCalculate(List<ProblemArg> probArgs)
    	{
    		throw new NotImplementedException();
    	}
    
    	private int SumDivisibleBy(int n, int factor)
    	{
    		int i = (n / factor);
    		return factor * i * (i + 1) / 2;
    	}
    
    	public List<ProblemArg> RequiredInputArgs
    	{
    		get
    		{
    			return new List<ProblemArg>() { new ProblemArg { DefaultValue = "1000", Name = "Integer n", RegularExpression = "^[0-9.]+$", MaxLength = Int32.MaxValue.ToString().Length } };
    		}
    	}
    }
    

    – There are 2 required attributes for your class solution. One is the name of problem which should be shown in combo box and the other is the description of problem which should be displayed in text box.

    – If you want to allow user enter value of argument, you should define the RequiredInputArgs property to give a list of argument back. The list can contain more arguments which will be show in list box under problem description.

    – The GetResult(List probArgs) gives you a signal that the user want to invoke your solution with his defined value (if any). In this function you can make your calculation (which can be in Calculate(List probArgs) function but it must not) and give the result back with type of string.

    So it’s pretty easy to write extension for this GUI tool. Try yourself to write your own solution and let this tool manages all solution for you.

    C# – Excel, Image, PDF Report with RDLC in Master/Details and MultiColumn

    There is maybe a complicated definition of the word “report” in IT application but for me it’s pretty simple. A report is just an interface between what the user gives and what he wants to see. He may have many data sources which build up a same designed form of report or he has one data source and would like to display it in different ways. Because of this loosing relation there are a lot of Report components for .NET framework to fulfill programmer’s entire requirement. Some popular commercial ones are Crystal Report, List & Label, ComponentOne Reports, etc. … which provide flexible ways so that a user (without having any programming skills) can customize his report as he desires. Of course, a commercial one is always expensive because of his numerous abilities. However in some cases we don’t need such complicated reporting tool but only a simple one to illustrate data as predefined template. In this case we can use the Report Viewer (accompanied with .NET Framework) to create many kinds of basic reports. I know there are a lot of tutorials about RDLC (Report Viewer) in Internet, for examples at this site http://gotreportviewer.com/ but I would like to write another one. First it’s for myself to look up when I need (because I don’t regularly use Report Viewer component, I use List & Label at work) and second it maybe will help some newbies who need very basic tutorial about Report Viewer. If you are professional, you can just skip this post.

    This blog post will discuss 3 supported types of Report Viewer (.RDLC): PDF, Excel and Image. For each type of report, I will insert some custom modifications to keep it not so boring and to illustrate how we can customize the reports. Of course I can’t cover all kinds of customizing but I think these customizations will be most asked for. All reports are embedded report (that means you don’t see .rdlc file at output folder). Now let’s create a console project to play around with Report Viewer. A report contains always 2 parts: data and template. So I need some data sources to feed Report Viewer. I have prepared some classes as VOs (ValueObject) containing our data and I will display values of these objects on report file. PDF and Image report use same data source (Example 1 and 3), Excel uses another ones (Example 2). These classes can be found in attachment at the end of post.

    I. PDF Report
    1. Right click on project and choose “Add New Item” –> Report –> Give “ReportMetaDataMember.rdlc” as new item’s name.

    Add new report item

    2. A new report design window will be opened. In this window, I can define how my report looks like when printing but let’s choose a data source for it first. In “Report Data” window click on New -> DataSet.

    New DataSet

    Enter MetaDataMember as Name, click on button new at Data source. On the new opened window, choose Object –> MetaDataDoc –> Click Finish. Go back to DataSet property choose MetaDataDoc (Members) in available datasets –> Click OK. At the end I have “Dataset Properties” as image below

    Dataset Properties

    3. Now I can feed my report with data. It’s the first part of what a report needs. The second part is the template. From Toolbox window, drag and drop a table on .rdlc designer then drag each property of VO to a column of table but Icon property. The icon property is an image property. However if I use Image type and I drag and drop this property whose type is Image on designer, I can’t show it on the report. The report will only show the name of property type. Therefore to show image on report, I need to convert it to byte array, and in the report template, I use Image control to parse this byte array.

    public byte[] Icon 
    {
    	get 
    	{
    		Bitmap result = null;
    		if (Name.StartsWith("T:"))
    			result = Properties.Resources.Auto_icon;
    		else if (Name.StartsWith("M:"))
    			result = Properties.Resources.EVE_icon;
    		else if (Name.StartsWith("F:"))
    			result = Properties.Resources.M_O_icon;
    		else if (Name.StartsWith("P:"))
    			result = Properties.Resources.Wall_E_icon;
    		else
    			result = Properties.Resources.Wall_E_icon;
    
    		MemoryStream ms = new MemoryStream();
    		result.Save(ms, ImageFormat.Png);
    		ms.Flush();
    		return ms.ToArray();
    	}
    }
    

    Image Properties

    4. If I don’t use Image in data source but would like to link it from external source like file on disk. I can add a parameter to “Report Data” and pass the link of image to this parameter. In Windows “Report Data”, right click on “Parameters” folder –> Add Parameter

    Report Data Add Parameter

    On “Report Parameter Properties”, set name as “LogoPath” and data type as “Text”

    Report Parameter Properties

    Go back to design window, insert an image control and set its properties like image below

    Image Properties

    As you can see, the image source is set as External and its expression is linked to the parameter added before “= “file:\\\” & Parameters!LogoPath.Value“. Now I have a simple template to display my data. I can customize my report more likely
    – Add Page Footer and Page number (from Built-in Fields at Report Data)

    Page Footer

    – Add Sorting, for example according to Name and Summary

    Row Groups Details

    Group Properties Sorting

    – Repeat table header on new page

    Advanced Mode

    Repeat on new page

    Play around with report designer as long as you want until the template satisfies you. After finishing with template, I need to write code to use this template for printing to pdf file.

    internal class PDFReportGenerator
    {
    	private IEnumerable<MetaDataMember> members;
    
    	public PDFReportGenerator(IEnumerable<MetaDataMember> members)
    	{
    		this.members = members;
    	}
    
    	public byte[] CreateReport()
    	{
    		byte[] result = null;
    
    		using (LocalReport localReport = new LocalReport())
    		{
    			localReport.ReportEmbeddedResource = "RDLC_as_embedded_resource.ReportMetaDataMember.rdlc";
    			localReport.DataSources.Add(new ReportDataSource("MetaDataMember", members));
    
    			localReport.EnableExternalImages = true;
    			ReportParameter logoParam = new ReportParameter("LogoPath");
    			logoParam.Values.Add(Path.Combine(Application.StartupPath, "Logo.png"));
    			localReport.SetParameters(new ReportParameter[] { logoParam });
    
    			string mimeType, encoding, fileNameExtension, deviceInfo;
    			string[] streams;
    			Warning[] warnings;
    			deviceInfo =
    				"<DeviceInfo>" +
    				"	<SimplePageHeaders>True</SimplePageHeaders>" +
    				"</DeviceInfo>";
    
    			result = localReport.Render(
    				"PDF",
    				deviceInfo,
    				out mimeType,
    				out encoding,
    				out fileNameExtension,
    				out streams,
    				out warnings);
    
    			if (warnings.Length > 0)
    				foreach (Warning warning in warnings)
    					Console.WriteLine(warning.Message);
    		}
    		return result;
    	}
    }
    

    The code is pretty simple. It’s just a bridge between data and template. I just have to initialize a LocalReport, set its ReportEmbeddedResource to report template and add data to data source. The value of parameter must be added before calling printing function (I have inserted a parameter LogoPath in template before). I intend to use external image as logo therefore the EnableExternalImages must be set to true. Call the generator with data and I will have a PDF report as output

    string fileName = "Read Metadata from Assembly.XML";
    XDocument doc = XDocument.Load(fileName);
    MetaDataDoc metadataDoc = (from d in doc.Descendants("doc")
    						   select new MetaDataDoc(d)).FirstOrDefault();
    
    IEnumerable<MetaDataMember> members = metadataDoc.Members;
    PDFReportGenerator reportGenerator = new PDFReportGenerator(members);
    byte[] pdf = reportGenerator.CreateReport();
    File.WriteAllBytes("test.pdf", pdf);
    Process.Start("test.pdf");
    

    PDF Report Output

    II. Excel report
    In this second part, I will discuss about Excel report with Master/Details relationship. It’s pretty simple to create this kind of report. The simply implemented master/details need at least 2 (or more) report templates. One is for master and the other is for details. The detail template will be referenced in master template through inserting a Subreport component in master and set its properties to detail one

    Subreport properties

    Master report

    The most important thing at master/details view is the relationship of parameters. Which property of master object will be used to categorize the children? In this example, the property “EmployeeID” of detailed part will be linked with ID of parent object

    Subreport Properties Parameters

    The code will be fast as same as the one for PDF report. However I must handle the Event SubreportProcessing to give the correct sub data for each parent object

    internal class ExcelReportGenerator
    {
    	private IEnumerable<Employee> members;
    
    	public ExcelReportGenerator(IEnumerable<Employee> members)
    	{
    		this.members = members;
    	}
    
    	public byte[] CreateReport()
    	{
    		byte[] result = null;
    
    		using (LocalReport localReport = new LocalReport())
    		{
    			localReport.ReportEmbeddedResource = "RDLC_as_embedded_resource.ReportMetaDataMemberMaster.rdlc";
    			localReport.DataSources.Add(new ReportDataSource("Employee", members));
    
    			localReport.SubreportProcessing += new SubreportProcessingEventHandler(localReport_SubreportProcessing);
    
    			string mimeType, encoding, fileNameExtension, deviceInfo;
    			string[] streams;
    			Warning[] warnings;
    			deviceInfo =
    				"<DeviceInfo>" +
    				"	<SimplePageHeaders>True</SimplePageHeaders>" +
    				"</DeviceInfo>";
    
    			result = localReport.Render(
    				"Excel",
    				deviceInfo,
    				out mimeType,
    				out encoding,
    				out fileNameExtension,
    				out streams,
    				out warnings);
    
    			if (warnings.Length > 0)
    				foreach (Warning warning in warnings)
    					Console.WriteLine(warning.Message);
    		}
    		return result;
    	}
    
    	private void localReport_SubreportProcessing(object sender, SubreportProcessingEventArgs e)
    	{
    		string employeeId = e.Parameters["EmployeeID"].Values[0];
    		string dataSourceName = e.DataSourceNames[0];
    		IEnumerable<Phone> phones = members.Where(x => x.ID.ToString() == employeeId).Select(x => x.Phone).FirstOrDefault();
    		e.DataSources.Add(new ReportDataSource(dataSourceName, phones));
    	}
    }
    

    The master/details in Excel report displays the data like image below

    Excel Report

    III. Image report with multi-column
    Now we reach the last supported type of Report Viewer. There’s nothing much to say with this kind of report. Instead of PDF exporting, I’ll export data in .tiff format. Of course I still need a template to define how the data looks like at the end. The report page of image example will be split into 2 columns. To do this, just right click out of the body template, choose “Report Properties” and Column property tells how many columns will be used in each report page. The code for image report is exactly same as in PDF report. I just replace the export type from “PDF” to “Image”.

    Report Properties

    Column Property

    I have discussed all of 3 kinds of Report Viewer. It plays no role which kind of report, it’s just output format. What is more important is the customizing which you can only learn through more practicing and complete source code can be downloaded as “RDLC as embedded resource

    C# – MemoryCache for Object, File and SQL Server – Part 1/2

    Caching is always a must-to-have feature in all applications, especially in database application. For example, I have to load a nested set of about 10.000 items from database, build up their path then load them to control (combo box, list box, etc…). The query to get 10.000 entries from SQL Server takes not so long to finish but let’s think about the case that we have many users working at the same time, server will be almost overloaded for processing this query parallel. The CPU and RAM usage go quickly up and SQL Server will react slower than normal. Of course, if you own a good server, there are maybe small problem but for a small server it’ll be a big problem and there is no benefit that the program make a same query for many times without any changes from database. In addition to server performance, the program performance should be also discussed. The result of this query will be mapped into objects. This mapping process takes even longer than executing query to finish. At the end, we have such long time action which we can avoid to call frequently through cache.

    In this blog post, I would like to make some basic examples for introducing new kind of cache which is available from .Net Framework 4 : MemoryCache. The MemoryCache implements the abstract ObjectCache class and represents the type that implements an in-memory cache. For more details you can read at MSDN http://msdn.microsoft.com/en-us/library/system.runtime.caching.memorycache.aspx . I wouldn’t discuss deeply how this class works but rather make concrete examples with it.

    1. Object cache
    The typical use of cache is storing an object in “clipboard” and gives the object back when required with its all information. In this example, I’ll create an object with a long time running method. This method takes time at the first call, the object will be then stored in cache. I call this method again in second time and now it gives the result back immediately. The object looks like this

    internal class LongTimeRunningObject
    {
    	public string Name { get; set; }
    
    	public int Seconds { get; set; }
    
    	public void LongTimeRunningMethod()
    	{
    		Seconds = new Random().Next(1, 2);
    		Thread.Sleep(new TimeSpan(0, 0, Seconds));
    	}
    }
    

    The long time running method will takes randomly one or two seconds to finish (yeah, the duration is not really long but it’s ok for an example). Now I create an object of this class and store it in MemoryCache.

    private static long CacheSimpleObject()
    {
    	string keyName = "LongTimeRunningObject";
    	LongTimeRunningObject longTimeRunningObject = new LongTimeRunningObject();
    	Stopwatch stopWatch = Stopwatch.StartNew();
    
    	MemoryCache cache = MemoryCache.Default;
    
    	if (cache.Contains(keyName))
    	{
    		longTimeRunningObject = (LongTimeRunningObject)cache.Get(keyName);
    	}
    	else
    	{
    		longTimeRunningObject = new LongTimeRunningObject();
    		longTimeRunningObject.Name = "CacheSimpleObject";
    		longTimeRunningObject.LongTimeRunningMethod();
    		CacheItemPolicy cacheItemPolicy = new CacheItemPolicy();
    		cacheItemPolicy.AbsoluteExpiration = new DateTimeOffset(DateTime.Now.AddSeconds(2));
    		cache.Add(keyName, longTimeRunningObject, cacheItemPolicy);
    	}
    
    	Console.WriteLine(string.Format("Example: {0} - Long time running methods took {1} to finish", longTimeRunningObject.Name, longTimeRunningObject.Seconds));
    	stopWatch.Stop();
    	return stopWatch.ElapsedMilliseconds;
    }
    

    With the CacheItemPolicy I can define how long the object should be still located in MemoryCache. In this case, MemoryCache will delete the object after 2 seconds. If the object was deleted from MemoryCache or not loaded into MemoryCache, I need to initialize it again. If it was there, then hold it back. Let’s test to see how the cache works.

    Console.WriteLine("Cache simple object");
    Console.WriteLine(string.Format("First time running took {0} miliseconds to finish ", CacheSimpleObject()));
    Console.WriteLine(string.Format("Second time running took {0} miliseconds to finish ", CacheSimpleObject()));
    Thread.Sleep(new TimeSpan(0, 0, new Random().Next(2, 4)));
    Console.WriteLine(string.Format("Third time running took {0} miliseconds to finish ", CacheSimpleObject()));
    

    At the first and third time, the object was first created or just deleted from memory cache. Therefore it takes time for the method to finish his job. At the second time, object was “cached” and therefore the method doesn’t have to run again. The cache gives his result simply back.

    2. List of object cache
    The object cache works perfectly. However, in real case, we often need to cache a list of object and create a missing one when it’s not in the list anymore. That mean we provide a cache of a list, when this cache is required with an available item, he returns this item back. If not, he should call the Callback function to create this item. This feature can be accomplished with help of a MemoryCacheWrapper

    internal class MemoryCacheWrapper<T> where T : class
    {
    	private readonly Func<string, T> callBack;
    	private readonly MemoryCache memoryCache;
    
    	public MemoryCacheWrapper(Func<string, T> factory, TimeSpan timeout, string name)
    	{
    		memoryCache = MemoryCache.Default;
    		callBack = factory;
    		this.TimeOut = timeout;
    		this.Name = name;
    	}
    
    	public virtual T this[string key]
    	{
    		get
    		{
    			T value = default(T);
    
    			if (memoryCache.Contains(key))
    				value = (T)memoryCache[key];
    			else
    			{
    				value = callBack(key);
    				CacheItemPolicy policy = new CacheItemPolicy();
    				policy.AbsoluteExpiration = new DateTimeOffset(DateTime.Now.Add(this.TimeOut));
    				memoryCache.Set(key, value, policy);
    			}
    			return value;
    		}
    	}
    
    	public TimeSpan TimeOut { get; set; }
    
    	public string Name { get; set; }
    
    	public void Add(object objectToCache, string key)
    	{
    		memoryCache.Add(key, objectToCache, DateTime.Now.AddMilliseconds(TimeOut.Ticks));
    	}
    
    	public T Get(string key)
    	{
    		return this[key];
    	}
    
    	public void Clear(string key)
    	{
    		memoryCache.Remove(key);
    	}
    
    	public bool Exists(string key)
    	{
    		return memoryCache.Get(key) != null;
    	}
    
    	public List<string> GetAll()
    	{
    		return memoryCache.Select(keyValuePair => keyValuePair.Key).ToList();
    	}
    }
    

    This wrapper contains as his member variable one callback function, one MemoryCache object and for example TimeOut property to clean cache after an interval. Moreover, he provides some basic functions to access MemoryCache as List-way to make the access easier. The code below demonstrates how this wrapper works

    private static void RunCustomCacheWrapper()
    {
    	Func<string, LongTimeRunningObject> cacheMissCreateCallback = CacheMissCreateCallback;
    	MemoryCacheWrapper<LongTimeRunningObject> wrapper = new MemoryCacheWrapper<LongTimeRunningObject>(cacheMissCreateCallback, new TimeSpan(0, 0, 10), "CacheListOfLongTimeRunningObject");
    	wrapper.Add(new LongTimeRunningObject() { Name = "One", Seconds = rnd.Next(2, 4) }, "One");
    	wrapper.Add(new LongTimeRunningObject() { Name = "Two", Seconds = rnd.Next(2, 4) }, "Two");
    	Console.WriteLine(string.Format("Name: {0}, Seconds: {1}", wrapper["Two"].Name, wrapper["Two"].Seconds));
    	Console.WriteLine(string.Format("Name: {0}, Seconds: {1}", wrapper["Three"].Name, wrapper["Three"].Seconds));
    	Console.WriteLine(string.Format("Name: {0}, Seconds: {1}", wrapper["Four"].Name, wrapper["Four"].Seconds));
    }
    
    private static LongTimeRunningObject CacheMissCreateCallback(string key)
    {
    	return new LongTimeRunningObject() { Name = "Name" + DateTime.Now.Ticks.ToString(), Seconds = rnd.Next(5, 10) };
    }
    

    The object with key “One” and “Two” were intentionally added to the list. It’s clearly accessible, but the object with key “Three” and “Four” was not in the cache. I have never added them before I access them from the cache. In this missing case, the Callback function will be called to add these missing one. If you access the key “Three” again, you’ll see that you got the same object created before

    MemoryCacheWrapper

    So now we reach the end of this part 1. The complete source code will be given at the end of Part 2. In part 2 we’ll discuss how we handle specific cases such as file cache and SQL Server cache.

    C#, AForge.Net – Examples for average color and motion detection

    As I was student at chair in Data and Signal processing of TUM (http://tum.de), I had a course of Computer Vision which discusses about the image processing and his uses in real application. Matlab is often used for calculating, evaluating the algorithms and displaying data on chart. However in .NET I would like to introduce another library which is also powerful for image processing. That’s AForge.NET (http://aforgenet.com).

    AForge.NET is a C# framework designed for developers and researchers in the fields of Computer Vision and Artificial Intelligence – image processing, neural networks, genetic algorithms, machine learning, robotics, etc.

    The reason that I come to AForge.NET, is my laziness. I often see films/video on my computer from my bed. And I am so lazy that when I go to sleep, I must crawl from the bed to the computer to turn it off. Therefore I have an idea to write a small program using my webcam to monitor the brightness in the room when I turn off the light, room turns black and my program will turn off the computer. That means I can turn off my computer just by turning off the light. Is it great isn’t it? ^_^. So let’s go to the homepage of AForge.Net and download its installer (http://aforge.googlecode.com/files/AForge.NET%20Framework-2.2.2.exe) to have full of examples, documentation, etc…

    1. Create new MVVM Light WPF 4 Project (you can use any type of project you want. This is just the GUI).
    2. Insert an image control, a combo box and a TextBlock as below

    <Grid x:Name="LayoutRoot">
    	<Grid.RowDefinitions>
    		<RowDefinition Height="8*"></RowDefinition>
    		<RowDefinition Height="1*"></RowDefinition>
    		<RowDefinition Height="1*"></RowDefinition>
    	</Grid.RowDefinitions>
    	<Image x:Name="imgCamera" Grid.Row="0" Source="{Binding CameraFrame}"></Image>
    	<ComboBox Grid.Row="1" Margin="5" ItemsSource="{Binding Cameras}" SelectedIndex="{Binding CameraIndex, Mode=TwoWay}">
    		<i:Interaction.Triggers>
    			<i:EventTrigger EventName="SelectionChanged">
    				<cmd:EventToCommand Command="{Binding SelectionChangedCommand, Mode=OneWay}" PassEventArgsToCommand="True" />
    			</i:EventTrigger>                
    		</i:Interaction.Triggers>
    	</ComboBox>
    	<TextBlock x:Name="tbAverageColor" Text="{Binding AverageColor, StringFormat='Average Color: \{0\}'}" Grid.Row="2" HorizontalAlignment="Center" VerticalAlignment="Center">            
    		<TextBlock.Background>
    			<SolidColorBrush Color="{Binding AverageColor}"></SolidColorBrush>
    		</TextBlock.Background>
    	</TextBlock>
    </Grid>
    

    3. It looks maybe a little involved for someone who doesn’t work with WPF MVVM. But just skipping it if you can’t understand, the code does nothing special than showing the control, binding them to data context and handling event SelectionChanged of combo box. So that’s all preparations for the GUI. Now go to MainViewModel() to build our logics When the program is started, I will load all available webcams into combo box so that I can select later which one I would like to use. This action can take long time so it should run asynchronously and I won’t block the GUI during its executing.

    public MainViewModel()
    {
    	if (IsInDesignMode)
    	{
    		// Code runs in Blend --> create design time data.
    	}
    	else
    	{
    		// Code runs "for real"
    		Task.Factory.StartNew(() => Initialize());		
    	}
    }
    
    AForgeUtil aforgeUtil = null;
    public List<string> Cameras {...}
    
    private void Initialize()
    {
    	aforgeUtil = new AForgeUtil();
    	Cameras = aforgeUtil.GetCameras();
    }
    

    In this initialization step, I create a Task asynchronously to initialize my custom AForgeUtil class and call GetCameras() function to get list of camera connected to the computer

    private FilterInfoCollection filterInfoCollection = new FilterInfoCollection(FilterCategory.VideoInputDevice);
    public  List<string> GetCameras()
    {            
    	return filterInfoCollection.Cast<FilterInfo>().ToList().Select(x=>x.Name).ToList();
    }
    

    As you can see, with the help of FilterInfoCollection in AForge.NET, I can easily get list of cameras. When I start the program, the combo box will be filled with all webcams connected to my computer. To make code above work, of course, we need to add references to AForge.Video and AForge.Video.DirectShow.

    AForge Get Cameras

    4. In next step, I would like to handle the SelectionChanged event of combo box to start the selected webcam and streaming what it records on image control

    private RelayCommand<SelectionChangedEventArgs> selectionChangedCommand;
    public ICommand SelectionChangedCommand
    {
    	get
    	{
    		if (selectionChangedCommand == null)
    			selectionChangedCommand = new RelayCommand<SelectionChangedEventArgs>(e => HandleSelectionChangedCommand(e));
    		return selectionChangedCommand;
    	}
    }
    
    private void HandleSelectionChangedCommand(SelectionChangedEventArgs e)
    {
    	Task.Factory.StartNew(() => aforgeUtil.StartCamera(CameraIndex));
    }
    
    private  VideoCaptureDevice videoCaptureDevice = null;
    public  void StartCamera(int CameraIndex)
    {
    	videoCaptureDevice = new VideoCaptureDevice(filterInfoCollection[CameraIndex].MonikerString);
    	videoCaptureDevice.NewFrame += new AForge.Video.NewFrameEventHandler(videoCaptureDevice_NewFrame);
    	videoCaptureDevice.Start();
    }
    
    void videoCaptureDevice_NewFrame(object sender, AForge.Video.NewFrameEventArgs eventArgs)
    {
    	Messenger.Default.Send(new NotificationMessage<Bitmap>((Bitmap)eventArgs.Frame.Clone(), MessengerMessages.NewFrame));
    }
    
    public MainViewModel()
    {
    	...
    		Task.Factory.StartNew(() => Initialize());
    		Messenger.Default.Register<NotificationMessage<Bitmap>>(this, (message) => UpdateCameraFrame(message));
    }
    
    private void UpdateCameraFrame(NotificationMessage<Bitmap> message)
    {
    	if (message.Notification == MessengerMessages.NewFrame)
    	{
    		CameraFrame = message.Content.ToWpfBitmap();		          
    	}   
    }
    
    public static class ExtensionMethod
    {
    	public static BitmapSource ToWpfBitmap(this Bitmap bitmap)
    	{
    		using (MemoryStream memorystream = new MemoryStream())
    		{
    			bitmap.Save(memorystream, ImageFormat.Bmp);
    			memorystream.Position = 0;
    			BitmapImage result = new BitmapImage();
    			result.BeginInit();
    			// According to MSDN, "The default OnDemand cache option retains access to the stream until the image is needed."
    			// Force the bitmap to load right now so we can dispose the stream.
    			result.CacheOption = BitmapCacheOption.OnLoad;
    			result.StreamSource = memorystream;
    			result.EndInit();
    			result.Freeze();
    			return result;
    		}
    	}
    
    }
    

    It’s really long, long code for a simply action. The SelectionChanged event will be handled by a new Task calling to StartCamera() function of AForgeUtil class with index of selected camera in the list. In StartCamera(), I create then an instance of VideoCaptureDevice of given camera, subscribe to its NewFrame event and turn the camera on. That means anytime when a new frame comes, function videoCaptureDevice_NewFrame(…) will be called and I send the current frame back to MainViewModel() to show it on image control. MainViewModel receives this message, converts current frame from Bitmap to WPFBitmap and “streams” it on image control by setting CurrentFrame property. ToWpfBitmap() is an extension method for converting Bitmap to WPFBitmap without causing memory leaking.

    The code look maybe a little complicated but most of them relate to communicate within program. The part of AForge.Net is just some line of codes. But before starting the program, we must be sure that VideoCaptureDevice must be disposed correctly when program is closed to avoid memory leak.

    public static void ClearMain()
    {
    	_main.CloseCamera();
    	_main.Cleanup();
    	_main = null;
    }
    
    public void CloseCamera()
    {
    	aforgeUtil.CloseCamera();
    }
    
    public void CloseCamera()
    {
    	if (videoCaptureDevice != null && videoCaptureDevice.IsRunning)
    	{
    		videoCaptureDevice.SignalToStop();
    		videoCaptureDevice.WaitForStop();
    		videoCaptureDevice = null;
    	}
    }
    

    You can override the CleanUp in MainViewModel and dispose object too. It’s better than changing code in ViewModelLocator like me. Then now start program to see if it works

    AForge Webcam to Image Control

    5. The capturing must look smoothly and RAM should be about 40MB. If not, then check your code again to see if there is any position causing memory leak with any profiler. I have now current frame on my image control and what I still have to do now is calculating its average color to decide if the light in room is turned off.

    private void UpdateCameraFrame(NotificationMessage<Bitmap> message)
    {
    	if (message.Notification == MessengerMessages.NewFrame)
    	{
    		CameraFrame = message.Content.ToWpfBitmap();
    		aforgeUtil.GetAverageColor(message.Content);                
    	}   
    }
    
    public void GetAverageColor(Bitmap bitmap)
    {
    	Color tempColor;
    	long sumA = 0, sumR = 0, sumG = 0, sumB = 0;
    	for (int i = 0; i < bitmap.Height; i++)
    	{
    		for (int j = 0; j < bitmap.Width; j++)
    		{
    			tempColor = bitmap.GetPixel(j, i);
    			sumA += Convert.ToInt32(tempColor.A);
    			sumR += Convert.ToInt32(tempColor.R);
    			sumG += Convert.ToInt32(tempColor.G);
    			sumB +=Convert.ToInt32(tempColor.B);
    		}
    	}
    
    	System.Windows.Media.Color result = new System.Windows.Media.Color();
    	result.A = (byte)(sumA / (bitmap.Height * bitmap.Width));
    	result.R = (byte)(sumR / (bitmap.Height * bitmap.Width));
    	result.G = (byte)(sumG / (bitmap.Height * bitmap.Width));
    	result.B = (byte)(sumB / (bitmap.Height * bitmap.Width));
    	Messenger.Default.Send(new NotificationMessage<System.Windows.Media.Color>(result, MessengerMessages.NewAverageColor));
    }
    
    bool alreadyStart = false;
    const int BlackThreshhold = 47;
    public MainViewModel()
    {
    	...
    		Messenger.Default.Register<NotificationMessage<Bitmap>>(this, (message) => UpdateCameraFrame(message));
    		Messenger.Default.Register<NotificationMessage<System.Windows.Media.Color>>(this, (message) =>
    			{
    				AverageColor = message.Content;
    				if (AverageColor.R < BlackThreshhold && AverageColor.G < BlackThreshhold && AverageColor.B < BlackThreshhold && alreadyStart)
    				{
    					alreadyStart = false;
    					Messenger.Default.Send(MessengerMessages.RunYourActionNow);
    				}
    				else if (AverageColor.R > BlackThreshhold && AverageColor.G > BlackThreshhold && AverageColor.B > BlackThreshhold)
    				{
    					alreadyStart = true;
    				}
    			});
    	}
    }
    
    public MainWindow()
    {
    	InitializeComponent();
    	Closing += (s, e) =>
    		{                    
    			ViewModelLocator.Cleanup();
    		};
    
    	Messenger.Default.Register<string>(this, (message) => HandleStringMessage(message));
    }
    
    private void HandleStringMessage(string message)
    {
    	if (message == MessengerMessages.RunYourActionNow)
    	{
    		MessageBox.Show("Run your action now");
    	}
    }
    

    Again the code looks a little confusing but it is really simple. When current frame changed, we’ll calculate its average color through summing color values and dividing through its area. After that, send color back to MainViewModel to show it on TextBlock and check if color is nearly black. If yes, then show message box. Of course, you should replace the message box with your defined action, for example turn off computer and make it stand by.

    6. We can extend the example with motion detection to decide if there is any motion in the room. If not, turn off the light or something like that or raise an alarm for instrusion.

    IMotionDetector motionDetector = new TwoFramesDifferenceDetector();
    BlobCountingObjectsProcessing motionProcessing = new BlobCountingObjectsProcessing();
    MotionDetector detector = null;
    const int MinObjectsSize = 30;
    public AForgeUtil()
    {
    	motionProcessing.HighlightColor = System.Drawing.Color.Green;
    	motionProcessing.MinObjectsHeight = MinObjectsSize;
    	motionProcessing.MinObjectsWidth = MinObjectsSize;            
    	detector = new MotionDetector(motionDetector, motionProcessing);
    	
    }
    
    void videoCaptureDevice_NewFrame(object sender, AForge.Video.NewFrameEventArgs eventArgs)
    {
    	MotionDetection((Bitmap)eventArgs.Frame.Clone());
    }
    
    public void MotionDetection(Bitmap bitmap)
    {
    	if (detector.ProcessFrame(bitmap) > 0.02)
    	{
    		if (motionProcessing.ObjectsCount > 1)
    		{
    			Messenger.Default.Send(MessengerMessages.IntrusionAlarm);
    		}                
    	}           
    
    	Messenger.Default.Send(new NotificationMessage<Bitmap>(bitmap, MessengerMessages.NewFrame));
    }
    

    AForge Motion Detection

    There are still lot of interesting functionalities of AForge.Net which can be not all discussed at this small blog. I’ll write more about this library when I have time to make research with it. As usual, at the end, you’ll find the source code “AForge Webcam Average Color

    C# – MVVMLight Toolkit Messages

    MVVM pattern is the most popular pattern to developers in WPF environment and there are already many platforms/frameworks supporting this pattern out there in internet. For example, I use Caliburn Micro Framework at work and use MVVM Light Toolkit at home for my private studying. Each framework has its own advantages and disadvantages so just choose one which you like or it satisfies you at most. Today I would like to make a small post to describe how the Messenger of MVVM Light Toolkit (MLT) works so that we can make the communication within application without violating the MVVM pattern.

    Continue reading C# – MVVMLight Toolkit Messages

    C# – Microsoft Sync Framework for file and database

    Data synchronization is always a top feature for any product in IT zone, especially if your product is a database-based product. It provides the customers more flexibilities and “freedom” when using the products. For example, the customer is on construction area, enter data through a concise mini mobile client, then sync them with server and when they are back to office, they have all data in the main software and finish the rest of work. That means at anytime and anywhere they can access their updated data. However it’s not easy at all to implement this dreaming feature in any application because of the complexity. However if you’re using Microsoft products, you can easily build this feature in your apps thanks to Microsoft Sync Framework (MSF) http://msdn.microsoft.com/en-us/sync/bb736753. Maybe you’ll say that there is already the replication feature in MS SQL Server, why do you need to use MSF? Yes, it’s correct that MS SQL has already this feature but obviously we can only sync between MS SQL Servers. How about if we want to sync between MS SQL Express? The answer can be MSF.

    In this small blog, I would like to make a small introduction about MSF through an example showing how we can simply sync 2 databases in MS SQL Express. It’s very simple example so that you have a good start with MSF, don’t expect for something advanced here. If you are already professional with MSF, you can skip this blog. First you need to download Microsoft Sync Framework Software Development Kit with latest version of 2.1 at http://www.microsoft.com/download/en/details.aspx?displaylang=en&id=23217 and install it. In MS SQL Express, create a new database called “MainDb” with 2 tables “Orders” and “OrdersDetails”. The scripts for creating tables are below

    CREATE TABLE [dbo].[Orders](
    	[Id] [int] IDENTITY(1,1) NOT NULL,
    	[OrderDate] [datetime] NULL,
     CONSTRAINT [PK__Orders__3214EC077F60ED59] PRIMARY KEY CLUSTERED 
    (
    	[Id] ASC
    )WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
    ) ON [PRIMARY]
    
    
    CREATE TABLE [dbo].[OrderDetails](
    	[Id] [int] IDENTITY(1,1) NOT NULL,
    	[OrderId] [int] NOT NULL,
    	[Product] [nvarchar](100) NULL,
    	[Quantity] [int] NULL,
     CONSTRAINT [PK__OrderDet__3214EC0703317E3D] PRIMARY KEY CLUSTERED 
    (
    	[Id] ASC
    )WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
    ) ON [PRIMARY]
    GO
    /****** Object:  ForeignKey [FK_OrderDetails_Orders]    Script Date: 10/17/2011 16:32:36 ******/
    ALTER TABLE [dbo].[OrderDetails]  WITH CHECK ADD  CONSTRAINT [FK_OrderDetails_Orders] FOREIGN KEY([OrderId])
    REFERENCES [dbo].[Orders] ([Id])
    GO
    ALTER TABLE [dbo].[OrderDetails] CHECK CONSTRAINT [FK_OrderDetails_Orders]
    GO
    

    MainDb and its tables

    Execute this SQL statement several times to insert some data records into tables

    INSERT INTO [MainDb].[dbo].[Orders]
               ([OrderDate])
         VALUES
               (DATEADD(DAY,RAND()*365,GETDATE()))
    GO
    

    Muster Data

    Now create another new database call “ClientDb01” and let it clear, we’ll sync it with the master database.

    Database structure

    Now start Visual Studio, create a new Console Application and add references to .dll of MSF. The .dll can be found in .NET reference tab.

    Microsoft Sync Framework References

    Microsoft Sync Framework References

    Then write the listing below to make synchronization between them.

    SyncOrchestrator agent = new SyncOrchestrator();
    string scopeName = "test";
    SqlConnection sqlConnLocal = new SqlConnection(@"Data Source=localhost\sqlexpress;Initial Catalog=MainDb;Integrated Security=True;");
    SqlConnection sqlConnRemote = new SqlConnection(@"Data Source=localhost\sqlexpress;Initial Catalog=ClientDb01;Integrated Security=True;");
    
    SqlSyncProvider sqlProviderLocal = new SqlSyncProvider(scopeName, sqlConnLocal);
    SqlSyncProvider sqlProviderRemote = new SqlSyncProvider(scopeName, sqlConnRemote);
    
    SqlSyncScopeProvisioning scopeProvisionLocal = new SqlSyncScopeProvisioning(sqlConnLocal);
    if (!scopeProvisionLocal.ScopeExists(scopeName))
    {
    	DbSyncScopeDescription scopeDesc = new DbSyncScopeDescription(scopeName);
    	scopeDesc.Tables.Add(SqlSyncDescriptionBuilder.GetDescriptionForTable("Orders", sqlConnLocal));
    	scopeDesc.Tables.Add(SqlSyncDescriptionBuilder.GetDescriptionForTable("OrderDetails", sqlConnLocal));
    	scopeProvisionLocal.PopulateFromScopeDescription(scopeDesc);
    	scopeProvisionLocal.SetCreateTableDefault(DbSyncCreationOption.Skip);
    	scopeProvisionLocal.Apply();
    }
    
    SqlSyncScopeProvisioning scopeProvisionRemote = new SqlSyncScopeProvisioning(sqlConnRemote);
    if (!scopeProvisionRemote.ScopeExists(scopeName))
    {
    	DbSyncScopeDescription scopeDesc = SqlSyncDescriptionBuilder.GetDescriptionForScope(scopeName, sqlConnLocal);
    	scopeProvisionRemote.PopulateFromScopeDescription(scopeDesc);
    	scopeProvisionRemote.Apply();
    }
    
    agent.LocalProvider = sqlProviderLocal;
    agent.RemoteProvider = sqlProviderRemote;
    SyncOperationStatistics stats = agent.Synchronize();
    Console.WriteLine("Download Applied:\t {0}", stats.DownloadChangesApplied);
    Console.WriteLine("Download Failed:\t {0}", stats.DownloadChangesFailed);
    Console.WriteLine("Download Total:\t\t {0}", stats.DownloadChangesTotal);
    Console.WriteLine("Upload Total:\t\t {0}", stats.UploadChangesApplied);
    Console.WriteLine("Upload Total:\t\t {0}", stats.UploadChangesFailed);
    Console.WriteLine("Upload Total:\t\t {0}", stats.UploadChangesTotal);
    Console.ReadLine();
    

    As you can see that the main object which is responsible for synchronizing between databases is SyncOrchestrator which needs two providers: LocalProvider and RemoteProvider. These providers can be FileSyncProvider, SqlSyncProvider or any custom provider depending on which object we would like to synchronize. In case of SqlSyncProvider, we can declare SyncProvider with a scope name and its connection. In case of FileSyncProvider, we need path to folders we would like to synchronize like this

    FileSyncProvider providerLocal = new FileSyncProvider(@"C:\Temp\Source Sync");
    FileSyncProvider providerRemote = new FileSyncProvider(@"C:\Temp\Dest Sync");
    

    We can apply more settings to the SyncProvider through SqlSyncScopeProvisioning to customize the synchronization. In the example, I define which tables should be synchronized between databases. The result of synchronizing process will be stored in SyncOperationStatistics telling how many data record was sent to remote server or download from it and if any record can’t be synchronized. So now if I execute the code, I’ll receive the statistic at frontend and at backend the contents of both databases are same.

    SyncOperationStatistics

    Metatables

    As you can see, MSF create some metadata tables for controlling the synchronization too. It makes the databases a little complicated and messy but I think for an administrator it’s no problem. Now I would like to make a small test to see what will happen when changes occur at both of sides: local and remote. Therefore I open the OrderDetails table of MainDb, insert one data record and open OrderDetails of ClientDb01, insert one other data record. The content of these records are different.

    Changes in MainDb

    Changes in ClientDb01

    Then I let the synchronization sync again, that result really satisfies me. Both of tables has exactly same structure of data (please notify the Id of each data record of table OrderDetails).

    Result for data integrity

    Database with immediate changes

    Ok, MSF passed first test with data integrity. Now I would like to make a second test for duplication, what would happen if changes from local and remote are same? I open OrderDetails table of MainDb and ClientDb01 again and insert another data record to them, but these records are same. I let the synchronization again, the statistic shows that there are some data to be uploaded and downloaded. But when opening the table at back end, we’ll see that there are no changes in database. MSF recognizes that they are duplicated and don’t insert them again into database.

    Duplication test

    SyncOperationStatistics duplication test

    MSF is a powerful framework. We can use it to sync any object with our custom sync provider. It allows us to define how the synchronization should run and how it should behave for any conflict. I hope that you have a good start with MSF and maybe I’ll write some more articles about this wonderful framework. At usual is source code for anyone who is interested in “Sync Framework Basic Example

    C#, Tools – PC Time to track on/off time of computer

    One boring task at my company is that each employee should report how he allocates time for each project he was following. Of course it is a must-do-work for project managers or supporters because they have to monitor how much time they have worked for each project so that the accounting department can send billings to customers later. But it doesn’t mean to me because I am a programmer and I have only 2 or 3 projects to take care of. I am just swinging between 2 phases: developing and bug fixing. The Test-phase will be made by Testers. Sometimes I write some Unit-Tests too but it’s not my fulltime field. As you see, my tasks are pretty “simple” however I must make myself an hour booking report at the end of each month too.
    So I try to keep this task as simple as it is. Each day I make a notice on my calendar about with which project I am on. For a small, short-time project, I notice its name and its duration. It works great. But for a long-time project then I really don’t know how long I was on because it takes weeks, months to accomplish. The problem is that I always forget to book hours after working day. Then I have an idea to approximate my PC on time as project time (Of course I have to subtract lunch pause and some minutes for short break) It won’t be exact as project time but I believe it will be nearly exact. With this solution I don’t need to remember to book hour after each day anymore.
    To monitor PC on/off time there is also half-free software on Internet, you can easily find him with search engine. In free version, I can only see 3 weeks before today. If I want to see more, I must buy a PRO-version. I am a poor man so I don’t have money to buy one therefore I must write myself to help me making my hour booking report.
    The tool is not very complicated because any action of computer was logged by operating system. The On/Off events are not exceptions. I just have to read them out from log files and show them in easy-read way. Every time when I turn the computer on/off, the actions will be logged in Windows Logs –> System which can be viewed through Event Viewer

    Windows Logs System

    As you can see in image above (in case that you can read German ^_^), Event-ID 12 is ID of ON-Event which was sent by Kernel when I turn the computer on. The OFF-Event has ID 13. So basing on this log, I can trace back when I switch my computer on/off, calculate the ON time, make some magical calculations and then I have my project time at last. I will show you how to read on/off time from this log with C#.

    Dictionary<DateTime, List<TimeBlock>> PCOnOffTime = new Dictionary<DateTime, List<TimeBlock>>();
    private void IntializeData()
    {
    	EventLog log = new EventLog();
    	log.Log = "System";
    	log.MachineName = ".";
    
    	var entries = log.Entries.Cast<EventLogEntry>();
    	var itemMin = from e in entries
    				  group e by e.TimeGenerated.Date into g
    				  select new CustomEntry { EntryDate = g.Key, TimeGenerated = g.Min(e => e.TimeGenerated), ActionType = "On" };
    	var itemMax = from e in entries
    				  group e by e.TimeGenerated.Date into g
    				  select new CustomEntry { EntryDate = g.Key, TimeGenerated = g.Max(e => e.TimeGenerated), ActionType = "Off" };
    	var itemOn = from e in entries
    				 where e.InstanceId == 12 && e.Source.Contains("Kernel-General") && e.EntryType == EventLogEntryType.Information
    				 select new CustomEntry { EntryDate = e.TimeGenerated.Date, TimeGenerated = e.TimeGenerated, ActionType = "On" };
    	var itemOff = from e in entries
    				  where e.InstanceId == 13 && e.Source.Contains("Kernel-General") && e.EntryType == EventLogEntryType.Information
    				  select new CustomEntry { EntryDate = e.TimeGenerated.Date, TimeGenerated = e.TimeGenerated, ActionType = "Off" };
    
    
    	List<CustomEntry> temp = new List<CustomEntry>();
    	itemMin.ToList().ForEach(x => temp.Add(x));
    	itemMax.ToList().ForEach(x =>
    	{
    		if (temp.FirstOrDefault(y => y.TimeGenerated == x.TimeGenerated) == null)
    			temp.Add(x);
    	});
    	itemOn.ToList().ForEach(x =>
    	{
    		if (temp.FirstOrDefault(y => y.TimeGenerated == x.TimeGenerated) == null)
    			temp.Add(x);
    	});
    	itemOff.ToList().ForEach(x =>
    	{
    		if (temp.FirstOrDefault(y => y.TimeGenerated == x.TimeGenerated) == null)
    			temp.Add(x);
    	});
    
    	List<CustomEntry> result = new List<CustomEntry>();
    	string actionType = "";
    	CustomEntry itemBefore = null;
    	foreach (CustomEntry item in temp.Distinct().OrderBy(x => x.TimeGenerated))
    	{
    		if (actionType == item.ActionType)
    			result.Remove(itemBefore);
    		result.Add(item);
    		actionType = item.ActionType;
    		itemBefore = item;
    	}
    
    	for (int index = 0; index < result.Count; index++)
    	{
    		if (!PCOnOffTime.ContainsKey(result[index].EntryDate))
    		{
    			List<TimeBlock> listTimeBlocks = new List<TimeBlock>();
    			PCOnOffTime.Add(result[index].EntryDate, listTimeBlocks);
    		}
    
    		PCOnOffTime[result[index].EntryDate].Add(new TimeBlock() { EntryStartTime = result[index].TimeGenerated, EntryEndTime = result[++index].TimeGenerated });
    	}
    }
    

    The code is pretty simple. I just instantiate a variable whose type is EventLog, indicate it to work with the System-Log at my local machine (MachineName = “.”). Then I read the first entry of each day and set it as ON action and last entry of each day and set it as OFF action. Now I have a likely ON duration but it will be wrong if I turn on the computer in the morning at 8:00, turn it off at 8:15, go out, come back to company at 17:00, turn computer on again and turn it off at 17:15. Then the first entry is 8:00 and the last is 17:15 but the truth is I am not in company during this time. So I have to catch the ON/OFF events within day as in variables itemOn/itemOff.
    After having all ON/OFF events, I just add them together, order ascending according to time, remove duplicated ones and then construct them in a Dictionary whose Key is date and Value is a list of time block marked with On and Off time. That means in one date, computer can be turned on/off many times. These on/off time will be parsed as EntryStartTime/EntryOffTime and saved in list.

    class CustomEntry
    {
    	public DateTime EntryDate { get; set; }
    	public DateTime TimeGenerated { get; set; }
    	public string ActionType { get; set; }
    }
    class TimeBlock
    {
    	public DateTime EntryStartTime { get; set; }
    	public DateTime EntryEndTime { get; set; }
    }
    

    At the end is the GUI. With some mock-up from WPF, I have beautiful PC Time software to show me when I turned on/off my computer.

    PC Time On Loading

    PC Time Load Finished

    Maybe you’ll tell me that you can let the computer on and go out. My tool cannot detect that. Yes, it’s true but this tool is to help you to control yourself, not to cheat someone else. 😀
    Binary: http://hintdesk.com/Web/Tool/PC%20Time.zip
    Source code: https://bitbucket.org/hintdesk/dotnet-tools-pc-time-to-track-onoff-time-of-computer