Tuesday, January 13, 2004

You've probably noticed that the "Home" key press is not possible to catch in either of the Key event handles of the Form or Control. The solution to that will be to use the RegisterHotKey API in conjunction with MessageWindow:

using System;

using Microsoft.WindowsCE.Forms;

using System.Windows.Forms;

using System.Runtime.InteropServices;

public class MessageWin : MessageWindow

{

    //event for client

    public System.EventHandler HomeKeyPress;

 

    public MessageWin()

    {

       //register to listen for home key

       RegisterHotKey(this.Hwnd, VK_LWIN, 8, VK_LWIN);

    }

  

    ~MessageWin()

    {

       Unregister();

    }

 

    protected override void WndProc(ref Message m)

    {

       if (m.Msg == WM_HOTKEY)

       {

          if ((int)m.WParam == VK_LWIN)

             //Raise event

             if (HomeKeyPress!=null)

                   HomeKeyPress(this, null);

       }

       base.WndProc (ref m);

    }

 

  #region P/Invokes

    private const int VK_LWIN    =    0x5B;

    private const int WM_HOTKEY   =      0x0312;

    [DllImport("coredll.dll")]

    public static extern bool RegisterHotKey(

         IntPtr hWnd, // handle to window

         int id, // hot key identifier

         int Modifiers, // key-modifier options

         int key //virtual-key code);

    [DllImport("coredll.dll")]

    public static extern bool UnregisterHotKey(

         IntPtr      hWnd,

         int         id);

   #endregion

 }

The usage of this class should be pretty obviouse:

MessageWin  msgWin = new MessageWin();

msgWin.HomeKeyPress+=new EventHandler(msgWin_HomeKeyPress);

 

private void msgWin_HomeKeyPress(object sender, System.EventArgs e)

{

      MessageBox.Show("Home Key Pressed.");

}

 

1/13/2004 9:27:59 PM (GMT Standard Time, UTC+00:00)  #     | 
 Monday, January 12, 2004

To draw a rectangle with rounded corners is not a trivial task in Compact Framework due to lack of ability to draw arcs (Graphics.DrawArc, GraphicPaths in the big .NET, etc..). OK, so why don't we just use Graphics.DrawEllipse to draw a rounded corners instead? Definitelly we can do that, but we would have to somehow wipe out the internal arcs:

So, my solutuion to that problem is to create a poligon shape that would fill the rectangle with the required back color and would wipe out unneeded arcs:

public static void DrawRoundedRectangle(Graphics g, Pen p, Color backColor, Rectangle rc, Size size)
{
   Point[] points = new Point[8];
   
   //prepare points for poligon
   points[0].X = rc.Left + size.Width / 2;
   points[0].Y = rc.Top + 1;
   points[1].X = rc.Right - size.Width / 2;
   points[1].Y = rc.Top + 1;

   points[2].X =  rc.Right;
   points[2].Y = rc.Top + size.Height / 2;
   points[3].X =  rc.Right;
   points[3].Y = rc.Bottom - size.Height / 2;

   points[4].X =  rc.Right - size.Width / 2;
   points[4].Y = rc.Bottom;
   points[5].X =  rc.Left  + size.Width / 2;
   points[5].Y = rc.Bottom;

   points[6].X =  rc.Left + 1;
   points[6].Y = rc.Bottom - size.Height / 2;
   points[7].X =  rc.Left + 1;
   points[7].Y = rc.Top + size.Height / 2;

   //prepare brush for background
   Brush fillBrush = new SolidBrush(backColor);

   //draw side lines and circles in the corners
   g.DrawLine(p, rc.Left  + size.Width / 2, rc.Top,
    rc.Right - size.Width / 2, rc.Top);
   g.FillEllipse(fillBrush, rc.Right - size.Width, rc.Top,
    size.Width, size.Height);
   g.DrawEllipse(p, rc.Right - size.Width, rc.Top,
    size.Width, size.Height);

   g.DrawLine(p, rc.Right, rc.Top + size.Height / 2,
    rc.Right, rc.Bottom - size.Height / 2);
   g.FillEllipse(fillBrush, rc.Right - size.Width, rc.Bottom - size.Height,
    size.Width, size.Height);
   g.DrawEllipse(p, rc.Right - size.Width, rc.Bottom - size.Height,
    size.Width, size.Height);
   
   g.DrawLine(p, rc.Right - size.Width / 2, rc.Bottom,
    rc.Left  + size.Width / 2, rc.Bottom);
   g.FillEllipse(fillBrush, rc.Left, rc.Bottom - size.Height,
    size.Width, size.Height);
   g.DrawEllipse(p, rc.Left, rc.Bottom - size.Height,
    size.Width, size.Height);
   
   g.DrawLine(p, rc.Left, rc.Bottom - size.Height / 2,
    rc.Left, rc.Top + size.Height / 2);
   g.FillEllipse(fillBrush, rc.Left, rc.Top,
    size.Width, size.Height);
   g.DrawEllipse(p, rc.Left, rc.Top,
    size.Width, size.Height);
   
   //fill the background and remove the internal arcs  
      g.FillPolygon(fillBrush, points);
   //dispose the brush
   fillBrush.Dispose();
  }

And this is how you'd use this method:

Rectangle rc =  new Rectangle(10, 10, 100, 30);

DrawRoundedRectangle(e.Graphics,

new Pen(Color.Black), Color.CadetBlue, rc, new Size(8, 8));

 
1/12/2004 11:52:30 PM (GMT Standard Time, UTC+00:00)  #     | 
 Monday, January 05, 2004
There was a really interesting discussion going on Robert Scoble blog when Neil has made a comment on a " rationale behind open source."

I find this whole issue to be ridiculous in the sense that open-source project can not be taking any jobs, but on the opposite way can help to keep jobs for the working people who would save some of their productive time by not re-inventing the wheel. What's your first move when working on the project and stumbling to the task you either don't know how to do or you know would take some time to develop? Mine would be to start "googling" and trying to find out if that was already done before. And when I discover that the stuff I am doing has never been done by anyone, I'd start doing on my own. And usually the solution would end up wither in one of OpenNETCF projects or in blog or in posts on the compactframework newsgroup.

1/5/2004 1:29:58 PM (GMT Standard Time, UTC+00:00)  #    Comments [34]  | 
 Thursday, January 01, 2004

Happy New Year to everybody!

The passed year was a good year for me. I've met many cool, smart intelligent and adherent people at the different events throughout a year... OpenNETCF has emerged and started shaping up.... I am sure that the New Year will be better. As Peter rightfully mentioned "Whidbey" is coming with CF v2 and a new generation of PPC and SmartPhone devices should start appearing this year.

On the personal front I hope (fingers crossed) to get into a very big and exciting Compact Framework project with one well-known company. I'll also strive to get around to finish up quite a few different projects for CF I have laying around (I agree with Chris  - I have to learn to not start a new project before finishing the old one too...): the mentioned before simple data storage, reporting engine, popup menu, Tab control, scrollbar etc...

1/1/2004 7:05:57 PM (GMT Standard Time, UTC+00:00)  #    Comments [1]  | 
 Wednesday, December 24, 2003

The current project I am working on required me to implement ”AutoSize" functionality. It means that I needed to draw a relatively long text into a width limited rectangle. In that case a text will be wrapped and I need to calculate a height of this wrapped text. In the .NET Framework one of the overrides of Graphics.MeasureString would do the job, but in CF this override is not implemented. Of course there is a GetTextExtentExPoint API that could be used to do the same, but it expects as a parameter handle to the device context which is not freely available in Compact Framework. So I decided to create a managed version of this function.

<DISCLAIMER>The algorithm that's used in this function is not optimized for speed and size. If you should come up with improvents to that let me know.</DISCLAMER>

  public SizeF MeasureStringExtend(Graphics g, string text, Font font, int desWidth)
  {
   string tempString = text;
   string workString = "";
   int npos = 1;
   int sp_pos = 0;
   int line = 0;
   int nWidth = 0;

   //get original size
   SizeF size = g.MeasureString(text, font);

   if (size.Width > desWidth)
   {
    while(tempString.Length > 0)
    {
     //Check for the last lane
     if (npos > tempString.Length)
     {
      line++;
      break;
     }
     workString = tempString.Substring(0, npos);
     //get the current width
     nWidth = (int)g.MeasureString(workString, font).Width;
     //check if we've got out of the destWidth
     if (nWidth > desWidth)
     {
      //try to find a space
      sp_pos = workString.LastIndexOf(" ");
      if (sp_pos > 0)
      {
       //cut out the wrap lane we've found
       tempString = tempString.Substring((sp_pos + 1), tempString.Length - (sp_pos + 1));
       line++;
       npos = 0;
      }
      else //no space
      {
       tempString = tempString.Substring(npos, tempString.Length - npos);
       line++;
       npos = 0;
      }
     }
     npos++;
    }
   }
   return new SizeF(desWidth, (line*size.Height)) ;
  }


 

12/24/2003 6:40:05 PM (GMT Standard Time, UTC+00:00)  #     | 
 Tuesday, December 23, 2003

XAML, WinFX, Indigo are the hottest buzz words in the IT these days. And those are very cool technologies indeed. Neil has expressed his dream of getting some of it for Smart Devices and I strongly second his motion.

Of course it's a technology that's still been developed.  But how feasible would be to implement XAML functionality for Compact Framework right now?  The most usability of XAML in this scenario I'd see its dynamic or "run-time" behavior. A lot of stuff could be done just using a simple reflection and XmlTextReader. I've put together a "proof of concept" project that could read an xml file and build a Form with controls on the fly.  Probably, it could become a starting point for one of the OpenNETCF.org projects. What're your thoughts on possible usage of XAML for Smart Devices?

12/23/2003 2:27:18 PM (GMT Standard Time, UTC+00:00)  #     | 
 Tuesday, December 09, 2003

You've probably noticed that some of the applications on Pocket PC 2003 and SmartPhones have this fancy looking gradient background. In all these cases it looks like a system list view control have been used... A quick search through a PPC 2003 SDK returns this result in the  List View Styles: "LVS_EX_GRADIENT Draws a background with a gradient. " Bingo! We're almost there. We know that ListView control in Compact Framework is just a wrapper for a native one, so here is the code that'll do the job:

//Some PInvokes and constants
[DllImport("coredll.dll")]
public static extern IntPtr GetCapture();

[DllImport("coredll.dll")]
private static extern int SendMessage(IntPtr hWnd, uint Msg, int wParam, int lParam);

const int LVS_EX_GRADIENT  =       0x20000000;
const int LVM_SETEXTENDEDLISTVIEWSTYLE  = 0x1000 + 54;

private void SetGradient(ListView listView)
{
     //Get a list view handle
     listView.Capture = true;
     IntPtr hList = GetCapture();
     //Apply extended style
     SendMessage(hList, (uint)LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_GRADIENT);
     listView.Capture = false;
     listView.Refresh();
}

12/9/2003 2:12:11 PM (GMT Standard Time, UTC+00:00)  #     | 
 Friday, December 05, 2003

VS.NET provides really sophisticated debugging options for developing SDP for Compact Framework. But sometimes there are situations when the only way to see what's happening in the code is to output some text/values to the Output window (or Console), but this option, as you know is missing from VS IDE. Although there's a solution to that - to implement System.Diagnostic.TraceListener and then to register it with the listeners collection. Take a look at this wonderful article on CodeProject.com. The sample from the article had successfully worked for me from devices and emulator with no problems.

12/5/2003 10:10:42 PM (GMT Standard Time, UTC+00:00)  #     |