Live Mesh + Visual SourceSafe = Code everywhere!
06 November 09 02:32 PM | jannemattila | 0 Comments   

For long time I have wanted have my code _everywhere_. Just because I have 3 different computers that I use to write my own stuff. Obviously it would be nice to have version control system (such as Team Foundation Server) but for my own use it would be quite heavy solution. And many times when I have had inspiration to start development of my old project I haven’t had network connectivity at that moment :-( So I thought that I try untraditional solution:

  • Use Visual SourceSafe for source control
  • Synchronize VSS database across all my computers with Live Mesh
  • Use local VSS database and “get latest” from that in each computer

I know that this sounds *weird* but it turns out to be good and working solution! Now I can take my source from local VSS database whenever I need and it’s always up to date (since Live Mesh is constantly running on the background and it does all the synchronization stuff).

Future will show if I manage to destroy my VSS database using this this approach :-)

Anyways... Happy hacking!

J

My Chess (another chess application)
22 October 09 05:43 PM | jannemattila | 1 Comments   

I came up with the idea of My Chess when I wanted to play games with my friends and I noticed that I don’t have time to do that :-) So I decided to write an application that allows me to play chess with my friends just by using small amount of time every now and then (approach is pretty different compared to the “normal” chess). Small amount of time means something like 10 seconds per move so and not more... Of course if you WANT to use more time you’re allowed to do that.

Here is list of other features that I wanted from My Chess:

  • Possibility to play offline. In another words I don’t want to think about the transport at all. I would just like to pass the transport related stuff to someone else.
  • Mobile version of the application (HTC Touch Pro since I have one)
  • “Social chess”: I wanted to have possibility to add comment when making move. Just because I want to tell to my opponents how good move I have made and remind them about their bad ones :-)
  • Game should be fast and easy. You should be able to make your move with just few clicks.

I decided to go with C++ since I didn’t want to take start up delay of .NET application on my mobile device. This one was easy decision :-)

Then I thought that I could use email as my transport because it automatically solves issues with the connectivity. On desktop I could rely on Outlook and mobile device I could rely on Pocket Outlook. More about technical details later in this post.

But then I was forced to think proper way to solve how to transmit the game state. I mean that how could I pass the current state of the game to my opponent so that it would be easy for him/her to continue from that state.  Use of attachment at the email was one option. But the story for the end user on mobile device with attachments isn’t that good so I didn’t use effort on this option. I took another approach which was to define URL format that I could use to serialize the game state. Here is one example game state:
my://chess/MczrFh7z?w=player1@contoso.com%26b=player2@contoso.com

Game state uses my protocol which I have mapped to application (Registering an Application to a URL Protocol on MSDN). Of course My Chess is configured according to the article so that it will called when my protocol is launched. Here is example .reg how custom application can be mapped to protocol:

1
2
3
4
5
6
7
8
9
10
11
12
13
Windows Registry Editor Version 5.00

[HKEY_CLASSES_ROOT\my]
@="URL:My Chess Protocol"
"URL Protocol"=""

[HKEY_CLASSES_ROOT\my\shell]

[HKEY_CLASSES_ROOT\my\shell\open]

[HKEY_CLASSES_ROOT\my\shell\open\command]
@="\"C:\\path\\My Chess (x64).exe\" %1"

So it really is that simple. Just define own key under HKEY_CLASSES_ROOT and set path to your application and it will be called automatically by the OS.

If you look the same with regedit it looks like this: Registry

If you now open up links starting with my protocol they will eventually take you to the configured application. But you probably see this kind of security dialogs before your own application starts (at least for the first time):
IE Confirmation dialog 
Just uncheck “Always ask before opening this type of address” and press Allow.

 My Chess Security Warning

Same goes with this dialog. Just check “Do not show me the warning for this program again” and press Allow.

NOTE: Make sure you understand the consequences of allowing protocol to map to application. If you’re application doesn’t validate data correctly it may lead to security issues when someone passes malicious data to your application. Remember you have been warned!

After that you should finally be at your application and you can use the information passed on the command line to execute the required actions.

So basically now I have tools to build the application... But I haven’t yet solved the “creating the email message” part of this solution. Remember I have both desktop application and mobile application to built.

On desktop I’m using Outlook as my mail transport and it has pretty good instructions in here:
How to use an Outlook Object Model from Visual C++ by using a #import statement
How To Send a Message by Outlook Object Model with VC++

Using Outlook on desktop with C++ is almost as easy as using it from .NET. It’s straight forward thing. So far so good right!

On mobile device things aren’t quite that easy since you need to use MAPI for sending the mail message. Here are few examples for that:
Getting Started with MAPI
Practical Use of MAPI
MAPI on Windows Mobile 6: Programmatically retrieve mail BODY (sample code)

But as always things aren’t as easy as they first seem to be. Since even if I did register my protocol at the mobile device it didn’t work as I expected. The problem was that Pocket Outlook always launched the URL to the default browser even if I had registration done to my own protocol. After some digging I found out that there are many security features that prevent that from happening. So in order to do it the right way I should have to edit/configure some files to allow protocol to be launched correctly. But since this is more concept than production kind-of-application I took another route... I chose to *hijack* MMS protocol for my custom application :-) I did that because it’s one of those protocols that are configured properly to the system. It normally launches Windows Media Player but I changed that to launch My Chess instead. This is the reason why you see two links at the emails underneath. The URL structure is exactly the same... Only the protocol part is either my or mms depending on the link. I admit that this one was dirty hack...

Now we have solved pretty much everything. But what about graphics then? Well I used images from Wikipedia at the Chess piece article (example King where you can see the licenses as well). Graphics is another interesting difference between desktop application and mobile application since GDI+ headers and libraries aren’t available for the mobile environment :-( But I wanted to use GDI+ on my desktop application even if I was forced to use GDI at the mobile application. Yeah I know... someone else would have built them using the same codebase but not me.

I used following functionalities from GDI+: Bitmap, Graphics (DrawImage, DrawCachedBitmap, DrawRectangle, FillRectangle), Graphics::FromImage, FontFamily, Font, SolidBrush, Pen, CachedBitmap etc.

I used following functionalities from GDI: DeleteDC, DeleteObject, CreateCompatibleDC, CreateCompatibleBitmap, SelectObject, Rectangle, TransparentBlt, BitBlt etc.

Are you already eager to see the final outcome? Well here it goes:

Desktop version:

My Chess

Mobile version (screenshot from emulator. It looks better on real device):

My Chess (Mobile) 

So how does it work in real life? Here is small example:

First if start My Chess without parameters so it creates automatically new game (in this example I play against myself):
My Chess new game dialog

In order to update the registry correctly for the protocol My Chess needs to be run for the first time in the “Run as administrator” –mode:

Run as administrator in order to register the protocol 

So now you have new game and you can use mouse to make the move (see simple coloring to indicate the move):
Coloring of the move

When you have done that you can press Send menu which then creates email message for you where you can add your own comment to your move (everything else is generated.. you just need to add last line):
My Chess created email message to Outlook
Now the game state is passed to the opponent as just normal email. When opponent receives it and presses the link following security prompt is displayed (Note: on mobile device application is launched directly without any dialogs):
Outlook Security Notice on my protocol link
After that My Chess is opened and it’s opens the current game state directly:
Email3  
And now you’re ready to make your move and then send it to the opponent with some nasty comment of course.

Current status of the My Chess is pretty much experimental / concept state since I haven’t yet implemented all the necessary functions to make it _real_ chess application:

  • Move validation is currently missing and all special moves haven’t been implemented (promotion is only special move that has been implemented)
  • Currently there isn’t way to see previous move or move history (it’s stored behind the covers but it’s not visible). I’m going to implement animations so that when user opens My Chess something like last 3 moves of the game would be animated. And user could browse the move history (with animations of course!) to see what has happened previously on the game.
  • I could CC the email message to email box that could be read by machine. It then could insert the game state to database, create some statistics about the games, history of games etc. This brings more possibilities to extend the game in the future. But I probably leave this to someone else...

By the way... you might have noticed that I used chess as in my URL to define which game should be launched from the my protocol. This indicates that something else might come in the future. That remains to be seen!

How could you use information provided in this blog entry for your own needs? Well here’s one: I have many times heard that customers need to “Send shortcuts” from their existing applications to each other. This could be way to do that. Just add functionality to “copy shortcut” from applications current state and then allow user to send it. Then at the receiving end you could create “proxy application” that interprets received information and opens the application into same state that the other user had. It could be pretty good improvement in many cases.

Anyways... Happy hacking!

J

Filed under: , , ,
My Notes (a small application between notepad and OneNote)
30 April 09 10:20 AM | jannemattila | 1 Comments   

I have been using Windows 7 and  Windows Server 2008 R2 since the first beta. And I mean on my “production” laptops. And I have to say that I haven’t had any major issues with them. In fact I’ve used to them so much that I don’t want to use older versions anymore :-) And there are few improvements in them that I specially enjoy. Of course the biggest one is the new taskbar... But surprisingly I have also found new application that I have “always needed”: Sticky Notes!

Sticky Notes is small application where you can write small notes to yourself. I call it “something between notepad and OneNote”. Reason for that is the fact that notepad is lightweight but it doesn’t contain any features. OneNote is full-blown application with tons of features. Sticky Notes lives between those too... It contains just enough features that make it useful and it also looks nice! The only issue I’m having with the Sticky Notes is the fact that it comes with Windows 7 only :-( So in my main “production” laptop (which is R2) I don’t have sticky notes.

For me it was a bit disappointing but I still understood the logic for that. Of course Sticky Notes isn’t “something that you would expect on the server” but since I really need this kind of application... I was forced to create one :-)

Normally when I create application I’ll just create new .NET project and start writing the application. But now I don’t want to suffer this penalty (screenshot taken from “File –> New Project: Windows Forms Application –> Run”):

.NET Windows Forms application 
Downside of .NET applications is the memory usage. Normally I don’t care about it but since now I’m going to create application that will be “always on” I just have to care about it. I don’t want to waste too much memory (I only have 8 GB of it :-). Therefore I decided to go with the native way (Win32, C/C++ or whatever you like to call it). It gives me possibility to be in control of all the used resources.

And here is the result “My Notes” application:

My Notes - Example

I’ve hidden the menus and tried to make the borders as small as possible. I don’t want to waste space as much the normal Windows application does:
Standard windows application 
“Standard” windows application doesn’t look that good either. So therefore I wanted to give it a bit more “fresh and appealing looks”. I used GDI+ and LinearGradientBrush to make it fancier. In case your wondering how to add GDI+ to your native application then it’s just this simple:

1
2
3
4
5
6
GdiplusStartupInput gdiplusStartupInput;
ULONG_PTR gdiplusToken;

GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
// ...
GdiplusShutdown(gdiplusToken);

See more about GDI+ on MSDN if your interested.

Even if I wanted the application to small borders I didn’t want to completely remove the menus. I used same thing as in IE for example... pressing Alt brings in the menu:

My Notes - Menu visible

I also wanted to give myself possibility to extend the application little bit more and I also added context menu to the edit surface. I don’t know yet what to put there but it’s nice to have if I need it someday :-)
My Notes - Content menu

I had to add “graphical menu” for basic operations like New and Close (just for fun):

My Notes - Graphical menu

Graphical menu is only visible if mouse is on top of the so called caption bar (as in screenshot).

And of course this should be in x64 since I’m running my R2 on x64:
VS Configuration Manager dialog

If your wondering why you don’t have the option to use x64 then you haven’t most likely checked the option in the Visual Studio setup. Just go to Control Panel and locate VS and select option to change the setup:
Control panel - Visual Studio 
Then just check the x64 if that’s what you want:
VS setup 

And last but not least... I’ve put my My Notes to the Live Mesh folder and synchronized my content to other devices. It’s simple and since I’m saving my note content to Rich Text Format (RTF) I can open up my notes even in my Windows Mobile. So now I have pretty good solution for my notes.

Anyways... Happy hacking!

J

Filed under: , ,
Story of wrong content type and InfoPath publishing location
29 April 09 01:54 PM | jannemattila | 1 Comments   

I found myself troubleshooting on issue that I thought shouldn’t be issue anymore. I have created InfoPath form and published it to the SharePoint. However when I created new form using that template it ended up using wrong content type at my library. And this happens even with the SP2 installed (both at the client and at the server) so I had to dig a little deeper.

Here are the phases that I took:

1. Created new InfoPath “Example form”.
2. Published it to the server called “myserver” as an site content type.
3. Added new content type to “mylist”.
4. Clicked “New example form” on the library and filled the form and saved it to the library.
5. Noticed that form is not the content type that I was expecting. It was default content type at the list... (which was Office document in my case since I had multiple content types at my list)

Did some testing and noticed that it actually works fine IF I use the “myserver” in the address bar of IE and not the fully qualified domain name “myserver.example.loc”. And now you’re thinking that I’ve just missed the Alternate Access Mappings (AAM) settings but no... I have those set for both addresses so that wasn’t the case.

Next I tried to fiddle around with InfoPath and tried different publishing addresses at the “Enter the location of your SharePoint or InfoPath Forms Services site:” –publishing wizard dialog:
InfoPath publishing wizard dialog 

And this is the place when it got interesting... Since I noticed that if I use “myserver” address at the publishing wizard dialog then content type goes wrong when using SharePoint through “myserver.example.loc” address. And also if I use the longer address at the publish wizard it doesn’t work at the SharePoint using the short address form.

So next I thought that Security Level could be the problem (which was set to Domain):
InfoPath publishing wizard dialog - Security level: Domain

...but if that would be the case then I couldn’t even use the form. Now the form works normally expect it will store the saved item into wrong content type.

For me the case was closed. I just published the form in “long address format” and I was happy :-) But I still wonder what went wrong in the background...

Anyways... Happy hacking!

J

Treasure hunting with Microsoft Tag
31 March 09 10:58 PM | jannemattila | 2 Comments   

Many people know geocaching (Wikipedia) and think of it as one of the modern treasure hunting games. Few days ago I found myself playing around with Microsoft Tag and I thought that this could be another treasure hunting game! Therefore I thought that I’ll do a different post this time.

First I’ll show how you can try out Microsoft Tag. First go to this page: http://tag.microsoft.com/. Click on the “Sign Up” –button (or “Sign In” if you have already done so). After sign in you have possibility to create categories, create tags and view reports about your tag usage.

As an example I’ll create a new tag category:
Create tag category

And I’ll use “Example tags” for the name:
Example tags category 
Then I’m going to create example tag that points to my blog:
Example link to my blog

After save has done it’s magic I can go and render my new fancy tag:
Launch tag rendering

Then it asks me that what kind of rendering do I want:
Tag rendering options  
I selected Render Type as PDF and Plain as the output format. Of course that result can be then printed out since it’s just image on the PDF. Here is the result:
Rendered tag

Now you can go to http://tags.microsoft.com with your mobile phone and download Microsoft Tag Reader for your phone. If you go there directly with your brower you can see list of supported platforms:
Supported phones

If you now start Tag Reader in your phone it will automatically start you phones camera and starts displaying picture from the camera. If you now point it to tag (like the one in this post :-) it recognizes the image and launches the action that I have configured. And since I configured tag to go to this blog you probably ended up to my blog with your mobile browser :-) And that’s cool right!

And finally we have the tools to build our own treasure hunt game! So now you need to do some planning and then you just create tags to support you treasure hunt game. But I’ll leave you the planning part...

NOTE: By the time of writing Microsoft Tag is in Beta phase which means creating of tags is free:
Beta statement

So now it’s your time to go and create few tags!

Anyways... Happy hacking!

J

Filed under:
Visual Studio 2008: Track Active Item in Solution Explorer
21 February 09 08:58 PM | jannemattila | 3 Comments   

If you’re working on solution that has many projects and many project items and you tend to get lost between your files... You might want to go to Tools –> Options –> Projects and Solutions and set Track Active Item in Solution Explorer on. For me it was a big relief that I found it. I’m working on project that has quite many projects under the solution and I have found myself constantly “searching” for files that are at the same location as the currently open file. And this is the painkiller for that pain:

 Visual Studio 2008 - Track Active Item in Solution Explorer

I’m not sure but if I have to guess... this was on by default on previous version of VS but not anymore on 2008. Because I know that I have enjoyed this feature in the past :-) But I might be wrong and I have manually set that on in the past too.

Anyways... Happy hacking!

J

Creating Excel Game (or something similar for fun)
29 January 09 09:47 PM | jannemattila | 2 Comments   

Awhile back I saw really interesting article: Microsoft Excel: Revolutionary 3D Game Engine?
After that I was forced to do small test on that and that of course resulted to this post :-)

I just grabbed the idea and made small “car game” (but in reality it just vaguely reminds of car game) on top of Excel. And here is the result: Car Game example
My car (or just blue box if you wish) can be controlled with mouse. If you press left mouse button it increases the speed of the car (a.k.a. gas pedal). I was too lazy to “invent” brake so car just slowly slows down if user isn’t pressing the left mouse button. User can control the “car” by moving mouse from left to right. Right mouse button quits the game.

Click here for the video.

Since I just wanted to test basic input and drawing mechanisms I didn’t even bother to think of creating any physics. I’ll leave that to you! But here’s the source code for my example:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
' WinAPI stuff:
Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)
Declare Function GetAsyncKeyState Lib "user32" (ByVal vKey As Long) As Integer
Declare Sub GetCursorPos Lib "user32" (ByRef lpoint As POINTAPI)
Declare Function ShowCursor Lib "user32" (ByVal bShow As Long) As Long

Type POINTAPI
  x As Long
  y As Long
End Type 

Sub GameLoop()

  ' Input related variables:
  Dim mouseLocation As POINTAPI
  Dim mouseLocationPrevious As POINTAPI

  ' Get & Set original mouse position:
  GetCursorPos mouseLocation
  mouseLocationPrevious = mouseLocation

  ' Initialize the system:
  ActiveSheet.Range("Xdiff").Value = 0
  ActiveSheet.Range("Ydiff").Value = 0
  ActiveSheet.Range("SteeringWheel").Value = 90
  ActiveSheet.Range("Pedal").Value = 0
  ActiveSheet.Range("CarX").Value = 250
  ActiveSheet.Range("CarY").Value = 250

  ' Hide mouse cursor:
  ShowCursor 0

  ' We're going to loop until mouse click:
  While GetAsyncKeyState(vbKeyRButton) = 0

    ' Magic:
    Sheets("GameBoard").Range("Z_SortArea").Sort _
      Sheets("GameBoard").Range("NormalZ"), xlAscending

    GetCursorPos mouseLocation
    DrawCar "car1", mouseLocation, mouseLocationPrevious

    ActiveSheet.Range("CarX").Value = _
      ActiveSheet.Range("CarX").Value - ActiveSheet.Range("SpeedY").Value
    ActiveSheet.Range("CarY").Value = _
      ActiveSheet.Range("CarY").Value - ActiveSheet.Range("SpeedX").Value
    mouseLocationPrevious = mouseLocation

    ' Let’s take a nap:
    Sleep(10)

    If GetAsyncKeyState(vbKeyLButton) <> 0 Then
      ' User is pressing the gas pedal => More speed:
      ActiveSheet.Range("Pedal").Value = _
        ActiveSheet.Range("Pedal").Value + ActiveSheet.Range("Accelerate").Value
      If ActiveSheet.Range("Pedal").Value > ActiveSheet.Range("MaxPedal").Value Then
        ActiveSheet.Range("Pedal").Value = ActiveSheet.Range("MaxPedal").Value
      End If
    Else
      ' User isn't pressing the gas pedal => Take of some speed (if moving):
      ActiveSheet.Range("Pedal").Value = _
        ActiveSheet.Range("Pedal").Value - ActiveSheet.Range("Brake").Value
      If ActiveSheet.Range("Pedal").Value < 0 Then
        ActiveSheet.Range("Pedal").Value = 0
      End If
    End If
  End While

  ' Bring back the mouse cursor:
  ShowCursor 1
End Sub

Sub DrawCar(carID As String, _
  mouseLocation As POINTAPI, _
  mouseLocationPrevious As POINTAPI)

  Dim diffX As Double
  Dim diffY As Double
  Dim Points(1 To 5, 1 To 2) As Single

  Dim carX As Double
  Dim carY As Double
  Dim carWidth As Double
  Dim carHeight As Double

  carX = ActiveSheet.Range("CarX").Value
  carY = ActiveSheet.Range("CarY").Value
  carHeight = ActiveSheet.Range("CarSize1").Value
  carWidth = ActiveSheet.Range("CarSize2").Value

  ' Get input and store current values to sheet:
  ActiveSheet.Range("Xdiff").Value = mouseLocationPrevious.x - mouseLocation.x
  ActiveSheet.Range("Ydiff").Value = mouseLocationPrevious.y - mouseLocation.y

  ActiveSheet.Range("SteeringWheel").Value = _
    ActiveSheet.Range("SteeringWheel").Value + ActiveSheet.Range("Xdiff2").Value

  Points(1, 1) = carX - carWidth
  Points(1, 2) = carY + carHeight
  Points(2, 1) = carX + carWidth
  Points(2, 2) = carY + carHeight
  Points(3, 1) = carX + carWidth
  Points(3, 2) = carY - carHeight
  Points(4, 1) = carX - carWidth
  Points(4, 2) = carY - carHeight
  Points(5, 1) = Points(1, 1)
  Points(5, 2) = Points(1, 2)

  ' Draw this car:
  On Error Resume Next
  ActiveSheet.Shapes(carID).Delete
  Err.Clear ' Deleting Shape that doesn't exist => Error
  ActiveSheet.Shapes.AddPolyline(Points).Name = carID
  ActiveSheet.Shapes(carID).Rotation = ActiveSheet.Range("SteeringWheel").Value
End Sub

I did my tests on Excel 2007 and I used .xlsm format (Macro enabled). You can grab my file from here.

So if you want to open that example it gives you this security warning:
Security warning

You need to click Options... button just below ribbon. And then check Enable this content and click OK:
Security Alert - Macro

And if you want to run the game you can just press Alt-F8 and then hit enter (or click Run):
Macro

Well I have to say that I enjoyed playing with Excel. Maybe some day I’m going to use this for some serious thing or not :-)

Anyways... Happy hacking!

J

Filed under: , ,
Attaching debugger to w3wp.exe using nice and easy keyboard shortcut
30 October 08 10:56 PM | jannemattila | 3 Comments   

How many times have you done some web development and used following method to attach your Visual Studio Debugger to w3wp.exe (a.k.a. Debug > Attach to Process –method):
image 

And then you scroll the long list and find your w3wp.exe and press attach:
VSDebugger

I’ll bet that you have done that a lot :-) At least I have.

Let’s create macro that does that very same thing but so that you don’t have to take your fingers of the keyboard.
First open up Macro Explorer (using View > Other windows > Macro Explorer or just hit Alt-F8). Then open up example AttachToCalc macro under Samples > VSDebugger:
image 

Right click and select edit:
image

Copy contents of that and create new macro under My Macros:
image 

And give it a name MyVSDebugger. Then paste the source code to it. Then modify the process name from calc.exe to w3wp.exe and remove the Exit For. You should have something like this left:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
Imports System
Imports EnvDTE
Imports EnvDTE80
Imports EnvDTE90
Imports System.Diagnostics

Public Module MyVSDebugger

  ' This subroutine attaches to w3wp.exe:
  Sub AttachToW3WP()
    Dim attached As Boolean = False
    Dim proc As EnvDTE.Process

    For Each proc In DTE.Debugger.LocalProcesses
      If (Right(proc.Name, 8) = "w3wp.exe") Then
        proc.Attach()
        attached = True
      End If
    Next

    If attached = False Then
      MsgBox("Couldn't find w3wp.exe")
    End If

  End Sub

End 
Now you should have this kind of view at the Macro Explorer:
image

Now let’s add keyboard shortcut for our macro from Tools > Options and Environment > Keyboard:
image
Just find your new macro and set focus to Press shortcut keys field and press your favorite keyboard shortcut and press Assign and then press OK. NOTE: You might have another command already using that combination but you can override it if you like.

Now we’re ready to use that. If you want to build your solution you can Ctrl-Shift-B and if you want to attach to w3wp.exe you’ll just press Ctrl-Shift-V. This is extremely handy if you have Post-Build event nicely set.

Anyways... Happy hacking!

J

Web Services and namespaces (or WCF?)
15 October 08 10:27 AM | jannemattila | 2 Comments   

You might have encountered following situation:
1. You have created class library “MyLibrary” and it contains following class:

1
2
3
4
5
6
7
8
namespace MyLibrary
{
  public class Employee
  {
    public string FirstName;
    public string LastName;
  }
}

2. You have created Web Service “MyWeb” using following VS template:
Web Service project
  - It references “MyLibrary”
  - It contains following method:

1
2
3
4
5
6
7
8
public class MyWeb : System.Web.Services.WebService
{
  [WebMethod]
  public void AddNewEmployee(MyLibrary.Employee employee)
  {
    // TODO: implement
  }
}

3. Finally you create Windows Forms application “My Win App”:
  - You “Add Web Reference” to “MyWeb” and you name it “WebServices”
  - You write following code to use that web service:

1
2
3
4
5
WebServices.Employee employee = new WebServices.Employee();
employee.FirstName = "John";
employee.LastName = "Doe";
WebServices.MyWeb myWeb = new WebServices.MyWeb();
myWeb.AddNewEmployee(employee);

4. You run your application and all is fine.
5. Later you notice that you need to add reference to your “MyLibrary” into your “My Win App”
(There could be many reasons for this. For example you want to use same business logic that web service uses etc.)
6. You add following code to you “My Win App”:

1
2
3
MyLibrary.Employee employee2 = new MyLibrary.Employee();
MyLibrary.EmployeeManager employeeManager = new MyLibrary.EmployeeManager();
employeeManager.AddNewEmployee(employee2);

7. Code works fine but then you notice that you actually have the same class from two different namespaces. What if you try to mix and match them (and sometimes you just have to do that)? Let’s see what happens:

1
2
3
WebServices.Employee employee = new WebServices.Employee();
MyLibrary.EmployeeManager employeeManager = new MyLibrary.EmployeeManager();
employeeManager.AddNewEmployee(employee);

8. When you try to compile your application and you’ll receive following error:
VS compile error  Error    11    The best overloaded method match for 'MyLibrary.EmployeeManager.AddNewEmployee(MyLibrary.Employee)' has some invalid arguments    C:\<path>\MyWinApp\MainForm.cs    41    1    MyWinApp
Error    12    Argument '1': cannot convert from 'MyWinApp.WebServices.Employee' to 'MyLibrary.Employee'    C:\<path>\MyWinApp\MainForm.cs    41    32    MyWinApp

9. You open up the generated proxy code:
Reference

10. You locate the code where Employee is defined and comment that part. And then you compile again with following results:
Error    11    The type or namespace name 'Employee' could not be found (are you missing a using directive or an assembly reference?)    C:\<path>\MyWinApp\Web References\WebServices\Reference.cs    82    36    MyWinApp

11. You fix that by resolving the missing type:
VS Resolve

12. You compile and you’re happy right (obviously you need to modify also all WebServices.Employee types to MyLibrary.Employee types)?

Well you might be happy since now your code works... BUT you have manually edited generated file which will be re-generated every time you do “Update Web Reference” from Visual Studio and you’ll lose you modifications. And that’s not nice.

If this would be question for me I would give you following answer (you might find different opinions on this one): Go to the WCF route instead :-) If Windows Communication Foundation (WCF) is something new to you I think you should check these out and find more information on the web: Overview of WCF from Wikipedia and Windows Communication Foundation home on MSDN.

I’m going to run through this same example with WCF way and then we can (hopefully) see why it fits like good glove.

1. Create new WCF project called “MyWcf” using following VS template:
WCF 1
2. Add reference to “MyLibrary”
3. Delete IService1.cs and Service1.svc from your newly created project.
4. Add new item “MyWcfService.svc” (using WCF Service template)
5. Modify “IMyWcfService.cs” file:

1
2
3
4
5
6
7
8
9
10
11
12
using System.ServiceModel;
using MyLibrary;

namespace MyWcf
{
  [ServiceContract]
  public interface IMyWcfService
  {
    [OperationContract]
    void AddNewEmployee(Employee employee);
  }
}
6. Modify “MyWcfService.cs” file:
1
2
3
4
5
6
7
8
9
10
11
12
13
using System;
using MyLibrary;

namespace MyWcf
{
  public class MyWcfService : IMyWcfService
  {
    public void AddNewEmployee(Employee employee)
    {
      // TODO: implement
    }
  }
}
7. Open up “web.config” and modify the system.serviceModel section as follows:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<system.serviceModel>
 <services>
  <service behaviorConfiguration="MyWcf.MyWcfServiceBehavior" name="MyWcf.MyWcfService">
   <endpoint address="" binding="basicHttpBinding" contract="MyWcf.IMyWcfService">
    <identity>
     <dns value="localhost" />
    </identity>
   </endpoint>
   <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
  </service>
 </services>
 <behaviors>
  <serviceBehaviors>
   <behavior name="MyWcf.MyWcfServiceBehavior">
    <serviceMetadata httpGetEnabled="true" />
    <serviceDebug includeExceptionDetailInFaults="false" />
   </behavior>
  </serviceBehaviors>
 </behaviors>
</system.serviceModel>
(you might notice that most important part is the binding what I have changed to be basicHttpBinding)

8. Go back to your “My Win App” project.
  - Remove “WebServices” web references
  - Add new “Service Reference” to your newly created WCF Service and name it “WcfServices”
  - Verify that you have “Reuse types in referenced assemblies” checked in settings (you can see them if you click Advanced... button from the “Add Service Reference” dialog):
WCF 2 

9. Modify your code to use this new service:
1
2
3
4
5
MyLibrary.Employee employee = new Employee();
employee.FirstName = "John";
employee.LastName = "Doe";
WcfServices.MyWcfServiceClient myWcf = new MyWinApp.WcfServices.MyWcfServiceClient();
myWcf.AddNewEmployee(employee);
10. Enjoy one of the benefits of WCF :-)

This is just one of the many benefits that WCF over the “good old ASP.NET Web Services”. So if you’re interested then you should start looking more information on the web.

Anyways... Happy hacking!

J

Tip: Disable RunOnce from Internet Explorer in your VPC images
17 September 08 02:30 PM | jannemattila | 3 Comments   

If you’re working with VPC images that cannot connect to internet you might have noticed annoying thing at Internet Explorer. IE tries to connect to internet so that it could finish up the setup. It’s good if you CAN connect to internet but it’s really annoying if you won’t ever have network connection (and this happens typically if you don’t want to connect your VPC to network). And waiting for the timeout isn’t that nice (+ pressing the stop button doesn’t help that much).

This can be however changed through registry. Just add two keys (or modify existing) RunOnceHasShown and RunOnceComplete. Here is example .reg file for that:

Windows Registry Editor Version 5.00

[HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\Main]
"RunOnceHasShown"=dword:00000001
"RunOnceComplete"=dword:00000001

After that you should have following keys under HKCU\Software\Microsoft\Internet Explorer\Main:

image

And now if you launch IE it won’t try to connect to internet. You might also want to change your home page to be something simple like about:blank.

This was just small tip to make your development life a bit easier in the world of VPC images.

Anyways… Happy hacking!

J

Filed under:
Use LINQ to access CRM objects
29 August 08 03:43 PM | jannemattila | 5 Comments   

If you have written small console application to check some data from CRM database you have probably already read this article from MSDN: Use Filtered Views. That is okay but honestly I’m currently more into LINQ solution. I’ll show you what I mean...

First I'll create new Console Application project and Add New Item to it and select LINQ to SQL Classes and name it CRMDataClasses.dbml:
LINQDataClasses

Then I'll use Server Explorer to connect to CRM database:
ServerExplorer

And then I'll drag Account, Contact, FilteredAccount and FilteredContact to the canvas of our newly created CRMDataClasses.dbml: CRMDataClasses

Now I'm ready to use LINQ to these views:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
CRMDataClassesDataContext dataContext = new CRMDataClassesDataContext();

var queryContact = from contact in dataContext.Contacts
          where contact.MobilePhone.Length > 0 &&
          contact.LastName.Length > 0
    select contact;

Console.WriteLine("Contact(s):");
foreach (Contact c in queryContact)
{
  Console.WriteLine(c.FirstName + " " + c.LastName + ", " + c.MobilePhone);
}

var queryFilteredContact = from contact in dataContext.FilteredContacts
          select contact;
Console.WriteLine("");

Console.WriteLine("Filtered contact(s):");
foreach (FilteredContact c in queryFilteredContact)
{
  Console.WriteLine(c.lastname);
}

On lines 3 to 6 I queried all contacts that have lastname and mobilephone filled in. On lines 14 to 15 I'm querying all contacts where current user has access to. NOTE: It doesn't return anything if you use SQL Authentication! So both of these can be used to fill you applications needs. But do notice that for some reason the attributes at the FilteredContacts are all lower case and in Contacts their naming is a bit different. So if you plan to change from Contacts to FilteredContact your going to have to change the casing of the attributes little bit.

This was just quick advice how you can leverage LINQ to your CRM solutions.

Anyways... Happy hacking!

J

Maximize the use of CPU with parallel extensions (+ some WPF stuff)
26 August 08 10:03 PM | jannemattila | 3 Comments   

Since this is my 40th post to this blog I decided to go back to square one… or post one actually :-) I’m going to create Windows Presentation Foundation (WPF) application that solves the Knight’s Tour puzzle. I actually didn’t know about this puzzle before I bought book called Puzzles for Programmers and Pros. That book had interesting puzzle that lead in to this post. So here we go!

I said that I’m going to create WPF application for my UI. You might ask why not the “good old” Windows Forms application...? Well for these simple reasons:

1.  I don’t like to write code to OnPaint / MainForm_Paint methods.
2. I wanted to define my user interface and then just say in code “hey knight go there” and it should just draw the UI with the knight in the correct position. But the defined UI must be also scalable.
3. WPF doesn’t have same barriers than Windows Forms does => It’s the face of future applications!

I don’t probably have to explain my reason #1 for you if you have experienced the same that I have :-) You’ll end up writing the UI code a lot and that’s not what you’re trying to do. You’re trying to solve puzzle and you are suddenly focusing for the UI code. That’s wrong approach. Therefore reason #2 goes hand-in-hand with #1.

So let’s look the the UI of the running application:

WPF UI

It’s the view of the classic chess board and I decided to take shortcut when creating the knight. I decided to use gray circle instead (or ellipse actually) :-) And for the layout management I just took the easy approach by using Grid and defining Columns and Rows. Here is the XAML for the UI:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
<Window x:Class="Window1"
   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
   Title="Knight's Tour" MinHeight="100" MinWidth="100" 
     Width="300" Height="300" Loaded="Window_Loaded">
  <Grid x:Name="Board">
    
    <Grid.ColumnDefinitions>
      <ColumnDefinition />
      <ColumnDefinition />
      <ColumnDefinition />
      <ColumnDefinition />
      <ColumnDefinition />
      <ColumnDefinition />
      <ColumnDefinition />
      <ColumnDefinition />
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
      <RowDefinition />
      <RowDefinition />
      <RowDefinition />
      <RowDefinition />
      <RowDefinition />
      <RowDefinition />
      <RowDefinition />
      <RowDefinition />
    </Grid.RowDefinitions>

    <Ellipse x:Name="Knight" Fill="Gray" Panel.ZIndex="1"
         Grid.Column="{Binding Path=KnightX}" 
         Grid.Row="{Binding Path=KnightY}" />
    
    <Rectangle x:Name="A8" Fill="White" />
    <Rectangle x:Name="B8" Grid.Column="1" />
    <!-- Etc... -->
  </Grid>
</Window>

You probably noticed the interesting part of the XAML... and that’s the lines 30 and 31 where Binding is defined. It means that these values coming from the public properties of the DataContext. So let’s look at the code behind that XAML and let’s discuss the binding little bit more:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Windows;
using System.Windows.Media;
using System.Windows.Shapes;

public partial class Window1 : Window, INotifyPropertyChanged
{
  private int knightX = 0;
  public int KnightX
  {
    get { return knightX; }
    set
    {
      knightX = value;
      NotifyPropertyChanged("KnightX");
    }
  }

  private int knightY = 0;
  public int KnightY
  {
    get { return knightY; }
    set
    {
      knightY = value;
      NotifyPropertyChanged("KnightY");
    }
  }

  private void Window_Loaded(object sender, RoutedEventArgs e)
  {
    Knight.DataContext = this;
    // Now moving the Knight is easy!
    KnightX = 3;
    KnightY = 3;
  }

  public event PropertyChangedEventHandler PropertyChanged;
  private void NotifyPropertyChanged(String info)
  {
    if (PropertyChanged != null)
    {
      PropertyChanged(this, new PropertyChangedEventArgs(info));
    }
  }
  //...
You might already noticed that my window also implements INotyfyPropertyChanged interface. And my two properties actually call NotifyPropertyChanged method when they are changed. So what’s this all about? Well if you don’t do this your values will be updated for the first time and after that they don’t actually get “bubbled” up to the ellipse anymore... unless you implement the notify mechanisms yourself. This is quite important and you should probably read more information about it on MSDN.

For the actual solving part I just used classic “old recursion” to solve the puzzle. And this is the part where we finally are going to the title of my post...

Classic one worker thread approach gives “fairly easy to implement but sub-optimal” solution. And you might ask why? And to answer this question I’m going so show you picture of task manager:
CPU1 

This picture was taken when my solver was running in “full speed ahead” –mode. And guess what... I’m not impressed! I’m actually just using single CPU (see the third box where green line has reached the roof)!!! So my worker thread approach is far from optimal resource usage.

Okay... What can I do then? I could do multiple threads and handle them manually but that’s again writing a lot of code that doesn’t have anything to do with the actual solving!? So if I would chosen Windows Forms + manual handling of multiple threads I would have a lot of code and just small fraction of that would actually do work that I was originally planning to do.

This is where Parallel Extensions (download) comes into the game! It’s additional library (System.Threading.dll) sitting on top of .NET Framework 3.5 and it’s currently in CTP phase. But I still highly recommend you to check it out if you want easily get more horse power to your algorithms.

I analyzed my code and noticed part where I could do things differently:

1
2
3
4
5
6
7
8
9
10
11
// My code was this:
foreach (int location in startLocations)
{
  // Calculations here!
}

// And I changed it to this:
Parallel.ForEach<int>(startLocations, (location) =>
{
  // Calculations here!
});

So I changed code in line 2 to be the code at line 8. What was the result at the task manager then:
CPU2 

Well I believe that I managed to get better use of the available horse power :-) It shows of course in the results:
“foreach”: ~50 solved solutions in ~5 minutes
”Parallel.ForEach”: ~450 solved solutions in < 5 minutes

To summarize... I just changed 1 line of code and I was able to get unbelievable results from it! So if you’re doing something similar then I recommend checking out the parallel extensions first before doing “own custom solution” for that.

I originally thought that I would go little bit deeper into the details of my solver but this post ended up too long even without it so maybe I’ll pass this time... But I’ll include video clip that shows the UI of the application when it’s solving.

Anyways... Happy hacking!

J

P.S. I’m also interested in F# and I’m probably going to do something fun with that too.

SQL Server Profiler and SPQuery
21 June 08 10:58 PM | jannemattila | 1 Comments   

Question: I’m using SPQuery to retrieve items from my SharePoint list and now I want to know little bit more about SPQuery properties. Actually I’m interested about performance related things since I’m not sure about my query currently. I currently have following code to retrieve my data:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
using (SPSite site = new SPSite("http://mysharepoint"))
{
  using (SPWeb web = site.RootWeb)
  {
    SPList docs = web.Lists["MyDocs"];
    SPQuery query = new SPQuery();
    query.Query = @"<Query>
        <Where>
         <And>
           <Eq>
            <FieldRef Name='MyField' />
            <Value Type='Text'>12345</Value>
           </Eq>
           <Eq>
            <FieldRef Name='ContentType' />
            <Value Type='Text'>MyContentType</Value>
           </Eq>
         </And>
        </Where>
      </Query>";

    SPListItemCollection items = docs.GetItems(query);
    foreach (SPListItem item in items)
    {
      Console.WriteLine("Item: " + item.Title);
    }
  }
}

Answer: To answer this question I need to step into dark side for a minute... I mean that I’m going to ask you to play with SQL Server Profiler to analyze your query more closely. This is of course to give some ideas how to tune your query using query properties and nothing else. I don’t want you to start use any custom SQL queries or other weird hacks that you might come up. Just tune the query and that’s it.
NOTE: Do this stuff only in you own dev box. Don’t even think anything else.

Before we start using the SQL Server Profiler you might want to stop SharePoint related services so that it’s easier to read the SQL trace. I’ve stopped IIS Admin (+related), Office SharePoint Server Search and Windows SharePoint Services*. Now you can start SQL Server Profiler and you’re ready to start tracing. Just create new trace (File->New Trace...) and select Tuning for your template:
SQLServerProfiler1

And if I now run your query I’ll get something like 200+ rows in my trace window. But you’re probably just interested for the rows that tell what is going on. If you pause the trace after the query then it’s most likely the last line in the grid:
SQLServerProfiler2 
It gives you fairly long SQL (mine was ~4500 characters long) and it’s not trivial to understand what it is really doing.

But first you probably notice the interesting  SELECT TOP 2147483648 ... And that’s the first thing you might want to change (of course you know best what you’re trying to achieve). But for that you have property called RowLimit. So if you add “query.RowLimit = 10;” to your code and re-run the trace you get following output:
SQLServerProfiler3 
So now you have SELECT TOP 11 ... which is better (note that the actual limit is your RowLimit + 1). If you only need to display n rows from database then don’t retrieve all and display just n => Use RowLimit to narrow down the resultset.

Next thing we need to take into consideration is ViewFields. If I know that I’m only going to show Title, then why should I need to retrieve more fields. Let’s narrow down the fields using ViewFields:

1
2
query.ViewFields = @"<FieldRef Name='ID'/>
                     <FieldRef Name='Title'/>";

And again let’s test the trace and compare the query for the first trace. You may notice that the SQL is only ~3000 chars long anymore and amount of columns at the resultset is a lot less (screenshot from management studio when both queries have been executed):
SQLServerProfiler4 
Notice the size of scrollbar…. larger is better :-)

Now I have just added few lines of code and the result is ~1500 shorter SQL and we’re only getting the amount of rows from DB that we need to. I’m not going to play with another properties but if you’re interested you might want to start with Include* properties.

I showed small example that how can use SQL Server toolset to verify (at least for some extend) that your queries are going for the right direction.

Anyways... Happy hacking!

J

Creating Localization Tool with Silverlight
08 June 08 03:11 PM | jannemattila | 3 Comments   

Since Silverlight 2 is in Beta 2 phase it’s definately time to create small application with it. Together with my friend we’e created small example application called Localization Tool. Idea in our example application is pretty simple... allow end users to modify texts used in application. And for the end user it should be easy, intuitive and of course fast. We used a lot of information available from internet in order to help us in the implementation (see links at the end of this post).

Before going into implementation details you can check out the final solution in action (click the image to open video in new window):

 Localization Tool

In our solution we took WCF + LINQ + SQL approach and created following simple datatable:
Localization Tool table
That table is then used to store data like this:
Localization Tool table data
After that we’ve created LINQ to SQL data class for our table:
Localization Tool table data classes
Then we created service that provides data access to our localization table. All code behind that service is here:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
using System;
using System.Collections.Generic;
using System.Linq;

namespace LocalizationTool_Web
{
public class LocalizationService : ILocalizationService
{
public List<Localization> GetLocalizationByLanguage(string language)
{
LocalizationDataClassesDataContext dataContext =
new LocalizationDataClassesDataContext();
var query = from localization in dataContext.Localizations
where localization.Language.Equals(language)
select localization;
return query.ToList();
}

public void UpdateLocalization(Localization localization)
{
LocalizationDataClassesDataContext dataContext =
new LocalizationDataClassesDataContext();
var updateRow = dataContext.Localizations.First(
loc =>
loc.LanguageKey.Equals(localization.LanguageKey) &&
loc.Language.Equals(localization.Language));
updateRow.Text = localization.Text;
updateRow.Comment = localization.Comment;
dataContext.SubmitChanges();
}

public String [] GetLocales()
{
LocalizationDataClassesDataContext dataContext =
new LocalizationDataClassesDataContext();
var query = (from localization in dataContext.Localizations
select localization.Language).Distinct();

return query.ToArray();
}
}
}

Now we’re ready to create UI for our application! We’ve used stackpanels for the layout management and then we used few Style elements to make things look little bit better.
Here is small example about the styles in our App.xaml:

 

1
2
3
4
5
6
7
8
9
10
11
12
<Application xmlns="http://schemas.microsoft.com/client/2007"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="LocalizationTool.App">
<Application.Resources>

<Style x:Key="Border" TargetType="Border">
<Setter Property="CornerRadius" Value="10"/>
<Setter Property="Background" Value="#FFdedede"/>
<Setter Property="VerticalAlignment" Value="Top"/>
<Setter Property="Margin" Value="8,8,8,8"/>
</Style>
<!-- ... and few more styles ... –>


At the UserControl_Loaded we query for all the possible locales so that we can list them add the ListBox. Here is the code for that (unfortunately the code looks terrible since it’s splitted into several rows only for display reasons):

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
private void UserControl_Loaded(object sender, RoutedEventArgs e)
{
LocalizationClientService.LocalizationServiceClient client =
new LocalizationTool.LocalizationClientService.LocalizationServiceClient();
client.GetLocalesCompleted +=
new EventHandler<LocalizationClientService.GetLocalesCompletedEventArgs>
(client_GetLocalesCompleted);
client.GetLocalesAsync();
}

void client_GetLocalesCompleted(object sender,
LocalizationClientService.GetLocalesCompletedEventArgs e)
{
languages.ItemsSource = e.Result;
}

Using that same method we query all the localizations specific for that selected locale. There’s nothing fancy about that.. but let’s look at the search functionality little bit closer.
Our search button was defined like this in our Page.xaml:

 

1
2
3
<TextBox Style="{StaticResource TextBox}" 
TextChanged="searchCriteria_TextChanged"
x:Name="searchCriteria" />

And in our code behind we had following code to execute the query:

 

1
2
3
4
5
6
7
8
String search = searchCriteria.Text.ToLower();
var query = from row in rows
where
row.LanguageKey.ToLower().Contains(search) ||
row.Text.ToLower().Contains(search) ||
row.Comment.ToLower().Contains(search)
select row;
SetDatagridItemSource(query.ToArray());

And you can probably pretty easily see that actually that search box functionality doesn’t retrieve data from server at all. It uses the previously retrieved data (variable rows) and filters out it by using linq. Therefore the performance is really good.

We also added functionality to view two different languages at the same time. This helps to make the translations since the user can directly see what’s the equivalent row in another language. This was implemented withthe concept base language. User can select what language he/she wants to use at the compare. Here’s example of that:
Localization Tool lock base language 
This was implemented by using the RowDetails of datagrid. Here is the xaml of our datagrid:

 

1
2
3
4
5
6
7
8
9
10
11
12
13
<System_Windows_Controls:DataGrid 
AutoGenerateColumns="True" x:Name="resultsDatagrid"
Width="770" Height="290" Margin="10,10,10,10"
CommittingEdit="resultsDatagrid_CommittingEdit"
SelectionChanged="resultsDatagrid_SelectionChanged"
LoadingRowDetails="resultsDatagrid_LoadingRowDetails">
<System_Windows_Controls:DataGrid.RowDetailsTemplate>
<DataTemplate>
<StackPanel x:Name="tooltipPanel"
Orientation="Horizontal" Background="LightYellow" />
</DataTemplate>
</System_Windows_Controls:DataGrid.RowDetailsTemplate>
</
System_Windows_Controls:DataGrid>

And in resultsDatagrid_LoadingRowDetails we just searched for the corresponding data row from our local base language array. If row was found then we dynamically created TextBoxes to display the values of base language.

This was just small example application that demonstrates the possibilities of Silverlight. Hopefully you got the idea that you can do pretty cool business applications with it.

Anyways... Happy hacking!

J

Links:

Silverlight.Net - Getting started
Silverlight 2 Beta1 + WCF + LINQ to SQL = a powerfull combination
Displaying SQL Database Data in a DataGrid using LINQ and WCF
Scott Guthrie: Silverlight Tutorial Part 3: Using Networking to Retrieve Data and Populate a DataGrid

Filed under: ,
Attachment(s): LocalizationTool.zip
Link: SharePoint slow spin-up times…
29 May 08 06:14 PM | jannemattila | 1 Comments   

I accidently found myself on this page: SharePoint 2007 Quirks - Solving painfully slow spin-up times. After reading that article I was forced to test that. And my stsadm experience was really fast after that! So this link deserves a link post even if I don’t do those normally :-)

Anyways... Happy hacking!

J

More Posts Next page »
Page view tracker