Wednesday, July 20, 2005

Be sure to visit all the options under "Configuration" in the Admin Menu Bar above. There are 16 themes to choose from, and you can also create your own.

 

7/20/2005 8:00:00 AM (GMT Daylight Time, UTC+01:00)  #    Comments [4]  | 
 Thursday, July 14, 2005

I've seen the request on the CF newsgroups for the control that would be able to scroll and zoom in(out) an image. Immediatedly remembered that I had this kind of control developed for my AtlasCE for Smartphone. So I pulled down the code, cleaned it up and created a sample client:

The ImageViewer control's code doesn't have a lot of comments, but I hope that the code is self explanatory enough for you to figure out how it works.

The ImageView has just a handfull of public methods properties:

You can download the control's source code and a sample from here:

ImageViewerClient.zip (76.15 KB)
7/14/2005 10:11:05 PM (GMT Daylight Time, UTC+01:00)  #     | 
 Tuesday, July 05, 2005

This question has just come up on the .NetCF newsgroup. P/Invoke is again to the rescue:

public void SaveTextBox(TextBox textBox, string fileName)

{

      StringBuilder buffer = new StringBuilder(" ", 255);

      // Get TextBox's native handle

      textBox.Capture = true;

      IntPtr handle = GetCapture();

      textBox.Capture = false;

     

      // The EM_GETLINE requires the length of the buffer in the first byte.

      buffer[0] = (char)255;

 

      using(StreamWriter writer = new StreamWriter(fileName))

      {

            // Get line count

            int lineCount = SendMessage(handle, EM_GETLINECOUNT, 0, 0);

 

            for(int i=0;i<lineCount;i++)

            {

                  SendMessage(handle, EM_GETLINE, i, buffer);

                  writer.WriteLine(buffer.ToString());

            }

            writer.Flush();

      }

 

}

 

Required P/Invoke declarations:

const int EM_GETLINECOUNT    =  0x00BA;

const int EM_GETLINE         =  0x00C4;

 

[DllImport("coredll.dll")]

static extern IntPtr GetCapture();

 

[DllImport("coredll.dll")]

static extern int SendMessage(IntPtr hwnd, int msg, int wParam, int lParam);

 

[DllImport("coredll.dll")]

static extern int SendMessage(IntPtr hwnd, int msg, int wParam, StringBuilder lParam);

 

7/5/2005 9:57:45 PM (GMT Daylight Time, UTC+01:00)  #     | 
 Thursday, June 23, 2005

Continuing the theme of extending the functionality of the intrinsic controls in the .NetCF, I am going to show you the way to show the horizontal scrollbar in the ListBox.

In order to achieve this we once again turn to the Windows Mobile SDK docs. The docs state that we could use the LB_SETHORIZONTALEXTENT message to set the width of the scrollbar in the ListBox. But this will work only if the ListBox is defined with the WS_HSCROLL style which we should be able to modify by employing GetWindowLong and SetWindowLong API calls. I've taken the ListBoxExtender class from the previouse post and added the following code in it:

private void ModifyStyle(uint addStyle, uint removeStyle)

{    

      // Get current window style

      uint windowStyle = GetWindowLong(handle, GWL_STYLE);

 

      if (addStyle != 0)

      {

            // Modify style

            SetWindowLong(handle, GWL_STYLE, windowStyle | addStyle);

      }

      else

      {

            // Remove style

            SetWindowLong(handle, GWL_STYLE, windowStyle & ~removeStyle);

      }

      // Let the window know of the changes

      SetWindowPos(handle, IntPtr.Zero, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOZORDER | SWP_NOSIZE | SWP_FRAMECHANGED);

}

 

public void SetScrollWidth(int width)

{

      // Set the scroll width

      SendMessage(handle, LB_SETHORIZONTALEXTENT, width, 0);

}

 

public bool HorizontalScrollbar

{

      get

      {

            return horizontalScrollbar;

      }

      set

      {

            if (horizontalScrollbar == value)

                  return;

            horizontalScrollbar = value;

                       

            if (horizontalScrollbar)

            {

                  ModifyStyle((uint)WS_HSCROLL, 0);

            }

            else

            {

                  ModifyStyle(0, (uint)WS_HSCROLL);

            }

      }

}

We shouldn't forget the appropriate P/Invoke declarations:

const int LB_GETHORIZONTALEXTENT  = 0x0193;

const int LB_SETHORIZONTALEXTENT  = 0x0194;

 

const long WS_HSCROLL    =      0x00100000L;

 

const int SWP_FRAMECHANGED    = 0x0020;

const int SWP_NOMOVE          =     0x0002;

const int SWP_NOSIZE          =     0x0001;

const int SWP_NOZORDER        =     0x0004;

 

const int GWL_STYLE         =  (-16);

 

 

[DllImport("coredll.dll")]

static extern int SendMessage(IntPtr hwnd, int msg, int wParam, int lParam);

[DllImport("coredll.dll")]

static extern uint GetWindowLong(IntPtr hwnd, int index);

[DllImport("coredll.dll")]

static extern void SetWindowLong(IntPtr hwnd, int index, uint value);

[DllImport("coredll.dll")]

static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X,

      int Y, int cx, int cy, uint uFlags);

You can download the full version of the ListBoxExtender here:

ListBoxExtender.zip (1.35 KB)

After the code's updated, you can use the ListBoxExtender class the following way:

listBoxEx = new ListBoxExtender(listBox1);

...

listBoxEx.HorizontalScrollbar = true;

listBoxEx.SetScrollWidth(200);

Now, the most attentive should be able to notice that I am passing some hardcoded value to the SetScrollWidth method, which of course is not going to work for all possible cases. In order to have an appropriate behaviour of the scrollbar you will have to indentify the longest string item in your ListBox and pass it to the SetScrollWidth .

6/23/2005 10:10:20 PM (GMT Daylight Time, UTC+01:00)  #     | 
 Wednesday, June 22, 2005

As you know, the intrinsic controls (ListBox, TextBox, ComboBox etc..) in the .NET Compact Framework are just a wrappers around its native counterparts. It is also known that the managed versions do not expose all available functionality. For example, it is possible to search the items in the ListBox or ComboBox just simply sending a windows messages such as LB_FINDSTRINGEXACT or LB_FINDSTRING. In order to illustrate its usage I've created the ListBoxExtender class, that will expose Search methods in the easy to use form:

/// <summary>

      /// Summary description for ListBoxExtender.

      /// </summary>

      public class ListBoxExtender

      {

            private ListBox listBox;

            private IntPtr handle;

 

            public ListBoxExtender(ListBox listBox)

            {

                  this.listBox = listBox;

                  // Get native handle

                  this.listBox.Capture = true;

                  this.handle = GetCapture();

                  this.listBox.Capture = false;

            }

 

            /// <summary>

            /// Searches an item in the ListBox by the specified item value.

            /// </summary>

            /// <param name="item">Item to search.</param>

            /// <returns>The index of the found item.</returns>

            public int Search(string item)

            {

                  return Search(item, -1, true);

            }

 

            /// <summary>

            /// Searches an item in the ListBox by the specified item value.

            /// </summary>

            /// <param name="item">Item to search.</param>

            /// <param name="startIndex">The zero-based index of the item before the first item to be searched.</param>

            /// <returns>The index of the found item.</returns>

            public int Search(string item, int startIndex)

            {

                  return Search(item, startIndex, true);

            }

 

            /// <summary>

            /// Searches an item in the ListBox by the specified item value.

            /// </summary>

            /// <param name="item">Item to search.</param>

            /// <param name="startIndex">The zero-based index of the item before the first item to be searched.</param>

            /// <param name="exact">Specifies whether the exact or partial search is performed.</param>

            /// <returns>The index of the found item.</returns>

            public int Search(string item, int startIndex, bool exact)

            {

                  int result = -1;

 

                  if (exact)

                  {

                        result = SendMessage(handle, LB_FINDSTRINGEXACT, startIndex, item);

                  }

                  else

                  {

                        result = SendMessage(handle, LB_FINDSTRING, startIndex, item);

                  }

 

                  return result;

            }

 

            #region P/Invokes

 

            const int LB_FINDSTRING           = 0x018F;

            const int LB_FINDSTRINGEXACT      = 0x01A2;

 

            [DllImport("coredll.dll")]

            static extern IntPtr GetCapture();

            [DllImport("coredll.dll")]

            static extern int SendMessage(IntPtr hwnd, int msg, int wParam, string lParam);

 

            #endregion

      }

The usage of this class should be obviouse:

listBoxEx = new ListBoxExtender(listBox1);

...

listBox1.SelectedIndex = listBoxEx.Search("Some Item");

 

6/22/2005 5:48:35 PM (GMT Daylight Time, UTC+01:00)  #     | 
 Wednesday, June 01, 2005

Managed controls in the Compact Framework don't expose all available functionality of the native controls they wrap. And that is understandable since the CF team wanted to make them fast and small. For example, ComboBox control doesn't implement the DropDown event that could be quite helpfull to store a previouse value because it should fire before the SelectedIndexChanged event. So I've decided to implement this event using the NativeWindow class I blogged about the other day.

The Windows CE SDK documentation states that there's a CBN_DROPDOWN notification message that is send to the parent of the ComboBox when the listbox of a combo box is about to become visible. This message is sent in the form of WM_COMMAND.

A quick trip to the winuser.h file to pull out the values for the CBN_DROPDOWN and WM_COMMAND and here's the ComboSubclass class that catches this message and raises the DropDown event:

public class ComboSubclass : NativeWindow

{

    private const int WM_COMMAND = 0x111;

    private const int CBN_DROPDOWN   =  7;

 

    public event EventHandler DropDown;

 

    private ComboBox comboBox;

 

    public ComboSubclass(ComboBox comboBox, Control parent)

    {

        this.comboBox = comboBox;

        //Subclass parent form

        this.AssignHandle(parent.Handle);

    }

 

    protected override void WndProc(ref Message m)

    {

        if (m.Msg == WM_COMMAND)

        {

            // Make sure that's its our ComboBox

            if (m.LParam == comboBox.Handle)

            {

                if (DropDown != null)

                {

                    // Raise the event

                    DropDown(comboBox, null);

                }

            }

        }

        base.WndProc(ref m);

    }

}

The usage of this class should be pretty straightforward:

   comboSubclass = new ComboSubclass(comboBox1, this);

  comboSubclass.DropDown += new EventHandler(comboSubclass_DropDown);

           

 

  void comboSubclass_DropDown(object sender, EventArgs e)

  {

      prevIndex = ((ComboBox)sender).SelectedIndex;

  }

Update: You can achieve the same goal in the CF v1 by utilizing ApplicationEx class from SDF and WinProcFilter I posted last year.

6/1/2005 2:14:42 PM (GMT Daylight Time, UTC+01:00)  #     | 
 Monday, May 23, 2005

As you probably know, the CF team has added the capability to use managed delegates as a native callbacks in the CF v2. It means that it’s become quite possible to use API’s that require a callback function such as EnumFonts, EnumWindows etc… The same goes true for been able to use SetWindowLong to subclass window procedure. The full .NET Framework includes a very useful NativeWindow class that wraps window subclassing and creating new windows functionality in the very usable and convenient package. A few months ago, I’d created a .NET Compact Framework v2 implementation of the NativeWindow class with exactly the same functionality (AssignHandle, CreateHandle, WndProc etc...

 

So what can you do with this class? Subclass any control and catch the messages that are not exposed as events, create your own versions of the native controls (EDIT, LISTBOX, ListView etc…)

 

You should expect the NativeWindow to become a part of the Smart Device Framework for CF v2.

 

You can download the NativeWindow class and a test project from here:

NativeWindowTest.zip (62.02 KB)
5/23/2005 5:28:13 PM (GMT Daylight Time, UTC+01:00)  #     | 
 Thursday, May 12, 2005

Chris Tacke has officially announced release of the Smart Device Framework 1.3 at his presentation “OpenNETCF.org : Creating a Community-Driven Development Project” at MEDC. Take a look at these wonderful screenshots on the new integration in VS.NET features from Neil who is single-handedly has done a titanic job of redesigning dialogs and incorporating Application Blocks into SDF installation structure.

 

 

 

SDF
5/12/2005 9:03:07 PM (GMT Daylight Time, UTC+01:00)  #     |