.Net ramblings
# Tuesday, 09 October 2007
MultiThreading In CF2 with Delegates
what a frustrating problem this was.  delegates weren't support in CF1, but now we have CF2 and according to microsoft:

The .NET Compact Framework 2.0 now supports asynchronous execution of a delegate on a user interface thread. Unlike the .NET Compact Framework 1.0 that supports only the Control.Invoke method (which synchronously executes a delegate on a control's owning thread), the .NET Compact Framework 2.0 provides Control.BeginInvoke that asynchronously executes a delegate on the control's owning thread. The Control.EndInvoke method is also provided. When called, the EndInvoke method returns the results of an asynchronous operation.

This is great but it's easily assumed that delegates are fully supported now in CF2, but no such luck.  they don't say that calling BeginInvoke on a delegate will cause your application to crash (with a NotSupportedException) even though it will compile in visual studio without warning or error.  there is an excellent (if lengthy) discussion on the matter on this newsgroup post.  the long and short of it is that you should use the ThreadPool class instead of using delegates to fire off worker threads.  You can still use delegates to send a function back to the UI thread just like in winforms.  Notice in the code below that the method signature of the function you are starting the thread on, requires a single 'object' parameter.
using System.Threading;

private void Button_Click(etc)
{
ThreadPool.QueueUserWorkItem(new WaitCallback(this.DoSomeWork));
}

private void DoSomeWork(object o)
{
...
}

Tuesday, 09 October 2007 15:00:03 (GMT Daylight Time, UTC+01:00)  #    Comments [0]  .Net Compact

# Monday, 08 October 2007
Look After Your Eyes!
i went to the optician yesterday for an annual check up, i'm always a bit worried because i write code for most of the day and that's not very healthy for eyes etc etc.  i know you're supposed to take breaks every 15 mins or so but that's difficult to do in practice.
the test showed one of my eyes with a very slight deterioration which makes no difference really but still i found it quite alarming that i'm doing damage to my eyes, specially since you only get 2 for your whole life.  i dug out a program i wrote a few years ago to go 'ding' in the background every 10 minutes to remind you to take an eye break.  apparently relaxing your eyes on a distant object for a minute or two is a good idea etc.  i was going to post up my little exe file but then i went looking and found "TakeYourBreak" on download.com, it is a much better program!


Monday, 08 October 2007 15:44:00 (GMT Daylight Time, UTC+01:00)  #    Comments [0]  General

# Tuesday, 02 October 2007
Bug in ComboBox SelectedIndex
big bug in ComboBox control here: http://support.microsoft.com/default.aspx?scid=kb;en-us;327244
you have to set the SelectedIndex to -1 twice in a row if you want it to take effect!
i came across this in a compact framework app, but it looks like it applies to win-forms as well.


Tuesday, 02 October 2007 17:17:18 (GMT Daylight Time, UTC+01:00)  #    Comments [0]  .Net Compact | .Net Windows Forms

# Tuesday, 18 September 2007
Profiler For SQL 2005 Express
wow, i never knew this existed: http://sqlprofiler.googlepages.com/
thanks to nikolay.zhebrun
it works great.


Tuesday, 18 September 2007 13:43:58 (GMT Daylight Time, UTC+01:00)  #    Comments [0]  .Net General | Database

LINQ Sql Using Skip And Take
Here is the sql that is generated by a DataContext when you use Skip() and Take() to efficiently select records for the grid:
SELECT TOP 10 [t1].[Name], [t1].[Address], [t1].[Tel1], [t1].[Tel2], [t1].[Email], [t1].[DateCommenced], [t1].[Comments], [t1].[Active], [t1].[Fax]
FROM (
SELECT ROW_NUMBER() OVER (ORDER BY [t0].[Name], [t0].[Address], [t0].[Tel1], [t0].[Tel2], [t0].[Email], [t0].[DateCommenced], [t0].[Comments], [t0].[Active], [t0].[Fax]) AS [ROW_NUMBER], [t0].[Name], [t0].[Address], [t0].[Tel1], [t0].[Tel2], [t0].[Email], [t0].[DateCommenced], [t0].[Comments], [t0].[Active], [t0].[Fax]
FROM [dbo].[Table1] AS [t0]
) AS [t1]
WHERE [t1].[ROW_NUMBER] > @p0
-- @p0: Input Int32 (Size = 0; Prec = 0; Scale = 0) [50]
-- Context: SqlProvider(Sql2005) Model: AttributedMetaModel Build: 3.5.20706.1

it's not immediately obvious why they use the subquery like this, but i'm sure they have been very thorough in optimising LINQ. 


Tuesday, 18 September 2007 13:22:32 (GMT Daylight Time, UTC+01:00)  #    Comments [1]  .Net General | Asp.Net | Database

# Monday, 17 September 2007
LINQ with strings
Today was the first time i used LINQ with non-database data.  I always knew you could do it but didn't realise how satisfying it would actually be to use LINQ to crunch out some results that i would otherwise have to code up in some gnarly routine involving on-the-fly DataTables and DataView filters etc.  Also, I'm mainly posting this because i can never remember the LINQ group by syntax...

i have a plain list of reference numbers, e.g. 1.a, 2.b, 3.c, 4.a, 10.d, 11.c etc.  they contain duplicates and i was asked to figure out the top 10 most popular references.  A simple regex separates out the numbers, i could also have used string.split() but regex is better in my case.  Copy each one into an array and then a simple LINQ query on the array gives me the top 10 references:
List<string> lst = new List<string>();
foreach(Match m in Regex.Matches(this.txtInput.Text, @"\w+\.\w+", RegexOptions.IgnoreCase))
lst.Add(m.Groups[0].Captures[0].Value);
var results = (from l in lst group l by l into g select new {Ref = g.Key, Total = g.Count()}).OrderByDescending(z => z.Total).Take(10);
foreach(var v in results)
this.txtOutput.Text += v.Ref + "\t" + v.Total + "\r\n";


Monday, 17 September 2007 15:01:26 (GMT Daylight Time, UTC+01:00)  #    Comments [0]  .Net General

# Friday, 31 August 2007
SQL: order by with parameters of different datatype
It's fair enough that SQL won't accept a parameterised query like below, because it cannot verify that the parameter is referring to a valid column.
select * from table order by @OrderBy
the work around then is to use a case statement like so:
select * from table order by case 
when @OrderBy = 'Column1' then Column1
when @OrderBy = 'Column2' then Column2
end
but i ran into a problem with this approach, where sql raises an error if the datatypes of the columns are not all the same, e.g. you may want to sort by an Int or NVarChar column.  the datatype precedence rules applied to the case statement are well explained in this post on google groups.  the solution posted by Erland Sommarskog is to have a separate case statement for each clause.  so the more robust approach is like so:
select * from table order by 
case when @OrderBy = 'Column1' then Column1 end,
case when @OrderBy = 'Column2' then Column2 end




Friday, 31 August 2007 12:36:35 (GMT Daylight Time, UTC+01:00)  #    Comments [0]  .Net General | Database

# Wednesday, 29 August 2007
IE problems with javascript window.open()
i couldn't figure out why IE was giving me an 'invalid argument' for using code like:
window.open("http://whatever", "1234321-ABCDE-1234231");
the problem is that IE only accepts alphanumeric and underscore characters for the second parameter (window name), so the hyphens were causing problems.  just trim them out and it will work fine.


Wednesday, 29 August 2007 13:34:31 (GMT Daylight Time, UTC+01:00)  #    Comments [1]  Asp.Net

# Friday, 27 July 2007
VS 2008: First impressions
Just got up and running with VS 2008 Beta 2 and converted my Orcas Beta 1 projects over to VS 2008.  have a read of Scott Gu's post on downloading and installing.  whaddya know? VS 2008 hasn't crashed yet :)  seriously though, this is a major relief to see good stability.  as a developer it did my head in to have to keep nuking devenv.exe and losing a few minutes work, driving me quietly insane.  hopefully those days are over now.  Beta 1 was a thousand times better than VS 2005, but Beta 2 looks even better. 

in terms of breaking changes with upgrading projects etc., here are some tidbits i came across
  • the namespace System.Data.Linq.Expressions no longer exists.  i just deleted this namespace and it worked fine, they must have moved various classes back into the root Linq namespace or something.
  • if you use SqlMetal, you will have to use the new version of this tool, which i found at C:\Program Files\Microsoft SDKs\Windows\V6.0A\Bin\SqlMetal.exe. The generated code from the new tool is very different to before so you will need to regenerate in order to use the new LINQ libraries.
  • web.config changes are also introduced.  the best way to figure out the changes is to open up a blank web application and compare the standard web.config in the empty project to your own web.config.
  • Crystal Reports assembly version numbers are the same with this release of VS, 10.5.3700.0, so no changes here since Beta1.
i'll post more next week when i have some real experience using VS 2008.  so far so good.  great job Scott & Co.

Update 30 July 2007 - Deployment Issues
  • To deploy a VS 2008 beta 2 web application to a Server 2003 with .net runtime 2.0, you need to install 3.5 of the runtime.  i got all sorts of web.config errors due to the new syntax with beta 2.  A web app compiled against v3.5 in Beta 1 had no trouble running on top of the 2.0 runtime with the various v3.5 DLLs deployed to the /bin directory, however this doesn't seem to be possible anymore.  it took me a while to find the correct download for the 3.5 beta 2 redistributable, it installed in about 10 mins and required a reboot, and did not affect any of the v1.1 and v2 web sites running on the server. 


Friday, 27 July 2007 17:49:16 (GMT Daylight Time, UTC+01:00)  #    Comments [0]  .Net General | .Net Windows Forms | Asp.Net

# Wednesday, 18 July 2007
JPEG Resizing Quality Problems .Net
public static ImageCodecInfo GetEncoderInfo(String mimeType)
{
int j;
ImageCodecInfo[] encoders;
encoders = ImageCodecInfo.GetImageEncoders();
for(j = 0; j < encoders.Length; ++j)
if(encoders[j].MimeType == mimeType)
return encoders[j];
return null;
}

public static Bitmap resizeImage(Bitmap originalImage, int max)
{
// never increase the size of an image from this method because it loses resolution
if(originalImage.Height <= max && originalImage.Width <= max)
return originalImage;

int height, width;
if(originalImage.Width > originalImage.Height)
{
width = max;
height = (int)(max/((double)originalImage.Width / (double)originalImage.Height));
}
else
{
height = max;
width = (int)(max/((double)originalImage.Height / (double)originalImage.Width));
}

Bitmap thumb = new Bitmap(originalImage as Image, width, height);
Graphics resizer = Graphics.FromImage(thumb);
resizer.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
resizer.DrawImage(originalImage, 0, 0, width, height);

resizer.Dispose();
return thumb;
}

public static bool ThumbnailCallback()
{
return false;
}

this lovely code highlighted in red solved problems i was having with resizing JPEGs using .net.   without the code in red, some images would appear very grainy when reduced in size.  i got this tip from http://forums.asp.net/p/532033/532033.aspx.



Wednesday, 18 July 2007 17:41:41 (GMT Daylight Time, UTC+01:00)  #    Comments [0]  .Net General | .Net Windows Forms