February 20, 2013

Multiple return types? Tuple!


mathematical tuple
When coding there's one rule I don't want to break (It's my own rule btw):

Whenever a code block needs to be copied, it needs to be in a separate method.

Of course the disadvantage of this approach is that whenever you code a bug in this piece of code, it will surface wherever it's used in your application.

However, this (in my opinion) outweighs the frustration of fixing the same bug on multiple locations again and again and again and...


My problem.


In general, when using this 'generic' code, I settle for a single return value. A boolean result to indicate everything worked out fine (or not!) is enough. Sometimes I would like to have more return values then a single type. The most obvious options:
1 - Use a struct return value
2 - Use an object as return value
3 - Return a collection object (Dictionary, List, etc)
4 - Use ref parms...

Problem solved?


(1) requires a definition. Typically the return struct is specific to the function it returns. I need to define each struct or create something generic...
(2) as (1) : definitions : I'm a lazy programmer ;)
(3) when al return values are of the same type it's definitely an option, but when that's not the case...
(4) big function signature and the variables need to be declared 'upfront' even though they may remain 'empty'

Problem solved!


You can return a mixed type collection! It's not dynamic, so you cannot add elements on the fly like a 'usual' collection. Consider this (console example) code:

 using System;  
 using System.Collections.Generic;  
 using System.Linq;  
 using System.Text;  
 namespace ConsoleApplication1  
 {  
   class Program  
   {  
     static void Main(string[] args)  
     {  
       // the tuple for the result Item1: bool, Item2: String 
       Tuple<bool, String> result;  
       MyObject test = new MyObject();  

       result = test.TestMethod(new MyObject(true));  
       Console.WriteLine("test.TestMethod(new MyObject(true));");  
       Console.WriteLine(String.Format("succes:{0}\terr:{1}",result.Item1,result.Item2));  
       Console.ReadLine();  

       result = test.TestMethod(new MyObject(false));  
       Console.WriteLine("test.TestMethod(new MyObject(false));");  
       Console.WriteLine(String.Format("succes:{0}\terr:{1}",result.Item1,result.Item2));  
       Console.ReadLine();  
     }  
   }
  
   class MyObject  
   {  
     public bool BooleanProperty { get; set; }  
     public MyObject() : this(true) { }  
     public MyObject(bool succes)  
     {  
       BooleanProperty = succes;  
     }
  
     public Tuple<bool, String> TestMethod(MyObject obj)  
     {  
       bool succes = true;  
       String err = String.Empty;  
       try  
       {  
         if (!obj.BooleanProperty) throw new InvalidOperationException("Something went wrong!");  
       }  
       catch (Exception ex)  
       {  
         succes = false;  
         err = ex.Message;  
       }  
       return Tuple.Create<bool, String>(succes, err);  
     }  
   }  
 }  

You define the types in the Tuple declaration. Not just value types, any object can be added. You just need to keep the result Tuple 'in sync' with the expected return Tuple. The elements are stored in Item1, Item2, etc. Visual Studio intellisence shows the types of these items :)

Now we can return a 'mixed collection' 'on the fly' :)

October 18, 2012

Transparent picturebox overlay in winforms


I stumbled into an annoying problem when doing some graphics coding in a windows forms environment. The task seemed rather simple: Have a panel with a background image, drag images -in my case as listview items- onto that panel where a picturebox is shown to display the dragged image. When done, merge the picturebox images with the background to store the final picture as a single image.

My problem


When I drag an image (listview item) onto the panel a picturebox is created at the dragged location and the image is displayed. However, troubles arise when two pictureboxes overlap. Here's the catch: Setting transparency on your picturebox will make the background reflect the picturebox control background!
So the result lookst like this:
(I colored the second picturebox transparent area a little 'red-ish' to show the problem!)

Problem Solved?


I did some research on the net, but to no avail. So, I improvised:
  1. We know the picturebox transparent area will reflect the picturebox parent image/foreground
  2. I do need the complete picture anyway
  3. There's no "free painting" involved, just 'reorganizing' pictures
  4. Speed is not an issue, since by my (educated) guess, in my app there will be dragged less than well... lets say 50 images to the panel.
  5. Considering point 4, I just might 'get away' with creating the final picture every time a picturebox is created/dragged/transformed...
  6. Control tags can contain Objects (other controls!)

 Problem solved!


Now consider this layout:
  1. A panel containing the background image (background)
  2. A Panel containing the imaged where background and picturebox images are merged (canvas) and the parent of my pictureboxes
  3. The pictureboxes dragged onto the canvas

The trick now is to 'reconstruct' the panel canvas background image every tima a picturebox is changed/added.
  • We first create the background panel with the (clean) background image (pnlBackground).
  • Next we create the canvas panel where pnlCanvas.Tag = pnlBackground. The canvas is a child control of the background!
  • Every time a new picturebox is added, the picturbox.Tag = pnlBackground. The pictureboxes are children of the canvas!
Do you see where I'm going here?
Now on every event changing the pictureboxes on the canvas panel we call a function to reconstruct the canvas panel background image. Events like dragdrop on the canvas panel (adding a new picturebox) and events of the picturebox itself (dragging, rotating, etc)

The merging function should accept a picturebox and a panel (overload it). When called with a picturebox we have:
Panel pnlCanvas = sender.Tag as Panel (sender == picturebox)
Panel pnlBackground = pnlCanvas.Tag as Panel

Now, take the pnlBackground image and merge each picturebox image with it. The resulting image is your new pnlCanvas image.

The end result will look like this:

Each picturebox transparent area reflects the parent control foreground, which is the merged picture of pnlCanvas! Since the pictureboxes are still there (overlaying the pnlCanvas) they are still available for editing by the user (dragging, rotating, etc)

 There's lots of code available about merging images, so no code in this post. Just the basic idea on how I solved the problem. It might not be the best solution, but it works for me. As mentioned above: My 'canvas' will not contain over 50 pictureboxes so speed is not an issue to me, but 'reconstructing' (merging) the canvas picture will cost you...



October 11, 2012

Custom Cursor Hotspot - HowTo...

When I recently implemented some drag and drop functionality I wanted to create a nice "drag cursor". A little different from the default. A quick "Google" showed me how to use a bitmap as a cursor.

My Problem



When creating a cursor from a bitmap the new cursor hotspot is the center point of that cursor image.

Though I had a nice cursor now, using it posed a challenge for my users. People -rightfully- assume the "fingertip" to be the point where they are pointing at not the center of their cursor.



Problem solved?!

Another Google search brought me the solution. To create my custom cursor (assuming the image is one of my resources) I had this code:

 Cursor.Current = New Cursor(My.Resources.addCursor.GetHicon())  

To create a custom cursor with a custom hotspot I changed it to:

 Cursor.Current = FormHelper.CreateCursor(My.Resources.addCursor, New Point(5, 5))  

The voodoo happens in the CreateCursor -static- method. Though you're probably not interested, I copied the source anyway:

#Region "Create Custom Cursor" 
  
   Private Structure IconInfo  
     Public fIcon As Boolean  
     Public xHotspot As Int32  
     Public yHotspot As Int32  
     Public hbmMask As IntPtr  
     Public hbmColor As IntPtr  
   End Structure  

   <DllImport("user32.dll", EntryPoint:="CreateIconIndirect")> _  
   Private Shared Function CreateIconIndirect(ByVal iconInfo As IntPtr) As IntPtr  
   End Function  

   <DllImport("user32.dll", CharSet:=CharSet.Auto)> _  
   Public Shared Function DestroyIcon(ByVal handle As IntPtr) As Boolean  
   End Function  

   <DllImport("gdi32.dll")> _  
   Public Shared Function DeleteObject(ByVal hObject As IntPtr) As Boolean  
   End Function  

   ''' <summary>  
   ''' Create a custom winforms cursor with a designated hotspot  
   ''' </summary>  
   ''' <param name="bmp">Image to be used as cursor</param>  
   ''' <param name="hotspot">Hotspot location of the cursor</param>  
   ''' <returns></returns>  
   ''' <remarks>  
   ''' Requires imports:  
   ''' Imports System.Drawing  
   ''' Imports System.Runtime.InteropServices  
   ''' Imports System.Windows.Forms  
   '''</remarks>  
   Public Shared Function CreateCursor(ByVal bmp As Bitmap, ByVal hotspot As Point) As Cursor  
     'Setup the Cursors IconInfo  
     Dim tmp As New IconInfo  
     tmp.xHotspot = hotspot.X  
     tmp.yHotspot = hotspot.Y  
     tmp.fIcon = False  
     tmp.hbmMask = bmp.GetHbitmap()  
     tmp.hbmColor = bmp.GetHbitmap()  
     'Create the Pointer for the Cursor Icon  
     Dim pnt As IntPtr = Marshal.AllocHGlobal(Marshal.SizeOf(tmp))  
     Marshal.StructureToPtr(tmp, pnt, True)  
     Dim curPtr As IntPtr = CreateIconIndirect(pnt)  
     'Clean Up  
     DestroyIcon(pnt)  
     DeleteObject(tmp.hbmMask)  
     DeleteObject(tmp.hbmColor)  
     Return New Cursor(curPtr)  
   End Function  

#End Region  

Don't forget the required imports! (In case you it did interest you)

August 27, 2012

Named pipes in .Net


Recently I did a job involving sending SMS messages from a web service. The message application app is SMS Studio, from CodeSegment. This application is used for some time by our client and in the past we've only used VB Script to interface with it.
Using VB Script, the easy way to send an SMS was to make SMS Studio create a named pipe to receive incoming messages and 'place' the SMS content in that pipe by our script.


My problem

Seems straight forward. In vb script we create an fso object and write to the pipe. Should be as easy -if not easier- in .Net right? Wrong! The Filestream object in System.IO does not allow your to write to a 'device'. Anything named "\\.\[device]\[name]" is not allowed. Apparently "pipe" is considered a device... "\\.\pipe\SendSMS" dit not work..

Problem Solved?!

Making a long story short: What I was looking for was here: System.IO.Pipes. It is available as of  framework 3.5.

This is how we did it in vb script:
 Set fso = Server.CreateObject("Scripting.FileSystemObject")  
 Set pipe = fso.CreateTextFile("\\.\pipe\SendSMS")  
 pipe.Write(msgText)  
 pipe.Close   

And the .Net way:
 Try  
    Using pipe As New NamedPipeClientStream(".", "SendSMS", PipeDirection.Out, PipeOptions.Asynchronous)  
      pipe.Connect(2000)  
      Using sw As New StreamWriter(pipe)  
        sw.AutoFlush = True  
        sw.Write(msgText)  
      End Using  
    End Using  
 Catch ex As Exception  
    Messagebox.Show(ex.Message & Environment.Newline & "SMS Studio offline?", "SMS not send")  
 End Try  

Notice that the pipe name in .Net is only the name "SendSMS", not the 'full' name ("\\.\pipe\SendSMS") like in vb script! Also we use NamedPipeClientStream, because we 'connect' to an existing pipe. It turns out to be this simple.


August 01, 2012

Visual Studio; The Document outline window

I really love Telerik controls especially in a winforms and asp.net environment. In a windows form solution it gives you this visual edge where your apps just looks a little more professional and appealing. RadDock is by far my most favorite control, closely followed by RadCommandBar.


My problem


Okay, so Telerik did a great job with those winform controls. But the problem is the order I drag my controls from the toolbox to my form. Usually I add a RadCommandBar first docking it to the top of the form, followed by a RadDock docking the form. Occasionally I first add the dock then the bar, resulting in the bar overlaying the dock.

Not the desired end result...



Problem solved?


Sort of... Usually I went to the forms designer code behind and changed the Me.Controls.Add order.



Problem Solved!


But by chance I stumbled into a Visual Studio feature which is far more easy: The document outline window! A -almost "hidden"- window showing all controls on your form. Rearranging controls is reduced to drag'n'drop and clicking arrows. No more need to edit designer code behind.



To show this window from the main menu, select View -> Other Windows -> Document Outline



July 25, 2012

ASP.Net: Wait for postback response


We have a ASP.Net application where some postbacks might take some time to be handled by the server. When the user triggers a postback, we want the client to be forced to wait until the postback is handled by the server.


My Problem

I want this mechanism to kick in on every page of the site, though some pages do not realy require it.

Problem solved?

Obviously you end up in the master page, but as in animal farm: "All pages are equal, but some pages are more equal then others". I want certain pages to handle the postback slightly different from the default...

Problem Solved!

The solution contains 3 elements: html, css and a little javascript. It's the javascript that helped me out.

html:
     <div id="mainContent">  
       <div class="loadinggs" id="loadingoverlay">  
         <div class="loadingmsg">  
           <img src="../../Images/ajax-loader.gif" align="middle" alt="busy" />  
           Bezig met verwerken...  
         </div>  
       </div>  
       <asp:ContentPlaceHolder ID="MainContent" runat="server" />  
     </div>  
The place of the code depends on what part you want to block. The example code 'blocks' the main content, leaving the menu (in another placeholder) accessible.

CSS:
 .loadinggs  
 {  
   position:fixed;  
   width:100%;  
   height:100%;  
   background:rgba(255, 255, 255, 0.5);  
   z-index:1000000000000;  
   display:none;  
   }  
 .loadingmsg  
 {  
   position:absolute;  
   top:30%;  
   left:50%;  
   background:#fff;  
   border:2px solid #196DC1;  
   padding:5px;  
 }  

HTML & CSS by Gio! (thanks again!)
The CSS is primarily IE9 (as by my requirement), but you can easily tweak it to support other browsers aswell.

Javascript

 <%--  
     Initializing the Page PageRequestManager, handling 4 key events:  
     1 - BeginRequest - Start of a postback  
     2 - Endrequest  - Server response on postback event  
     3 - PageLoading - ... (self explainatory I guess)  
     4 - PageLoaded  -  
     By default on each page a animated loading img is shown. But certain pages have additional functionality.  
     In appl_init we check if additional functions were provided for each event. If not the default behaviour is applied.  
 --%>  
 <script type="text/javascript">  
   var pgRegMgr;  
   // add an event handler to 'pageload'  
   Sys.Application.add_init(appl_init);  
   /*  
   The PageRequestManager contains postback information.  
   When this page initializes, we can add handlers to this manager to catch events.  
   NOTE: This javascript code need te be placed AFTER the </body> tag !!!!  
   */  
   function appl_init() {  
     // if we do not have the PageRequestManager instance, get it AND add the handler(s)  
     if (pgRegMgr == null) {  
       if (Sys != null) {  
         if (Sys.WebForms != null) {  
           pgRegMgr = Sys.WebForms.PageRequestManager.getInstance();  
           // check for specific event handlers, if not found use the default  
           if (window.pageBeginRequest) { pgRegMgr.add_beginRequest(pageBeginRequest); } else { pgRegMgr.add_beginRequest(BeginHandler); }  
           if (window.pageEndRequest) { pgRegMgr.add_endRequest(pageEndRequest); } else { pgRegMgr.add_endRequest(EndHandler); }  
           if (window.pageLoading) { pgRegMgr.add_pageLoading(pageLoading); } else { pgRegMgr.add_pageLoading(BeginHandler); }  
           if (window.pageLoaded) { pgRegMgr.add_pageLoaded(pageLoaded); } else { pgRegMgr.add_pageLoading(EndHandler); }  
         }  
       }  
     }  
   }  
   /*  
   Default pageBeginRequest and pageLoading behaviour.  
   */  
   function BeginHandler() {  
     document.getElementById('loadingoverlay').style.display = 'block';  
   }  
   /*  
   Default pageEndRequest and pageLoaded behaviour.  
   */  
   function EndHandler() {  
     document.getElementById('loadingoverlay').style.display = 'none';  
   }  
 </script>  
 <asp:ContentPlaceHolder ID="AfterBody_AddedHandlers" runat="server" />  

Now on each postback of a control the content part of the screen is 'locked' until the server responds. The script supports the usage of  a specific handler on the content page hosted by the master. Just add the handlers in the <asp:Content> tag and do enclose them with <script></script> tags. And -if applicable- don't forget to hide the loading message...

 <asp:Content ID="Content2" ContentPlaceHolderID="AfterBody_AddedHandlers" runat="Server">  
   <script type="text/javascript">  
     /*  
     When a postback was handled by the server (Code behind was executed...)  
     we want to check if a specific control was causing the postback...  
     */  
     function pageEndRequest() {  
       //do specific page stuff...  
     }  
     /*  
     Catch the pageLoaded event.  
     */  
     function pageLoaded() {  
      //eg. call a specific function like a body onload  
       UpdateTotals();  
       document.getElementById('loadingoverlay').style.display = 'none';  
     }  
   </script>  
 </asp:Content>  

July 23, 2012

Sync Outlook with Android!

Looking for free software to synchronize your outlook data with your Android device?
After searching the web with google again and again I found a solution. They say the best things in life are free, but your should really consider a donation to these developers!

MyPhoneExplorer



This is what you are looking for! Fully functional, not a trial version. And do donate, it's worth it!