Commentor Blog

When Quality Matters

Commentor A/S

When Quality Matters

Contact usSend mail

Disclaimer

The opinions expressed herein are my own personal opinions and do not represent my employer's view in anyway.

© Copyright 2010

Enumerating Bluetooth Devices from .NETCF

I recently had a project where I needed to send data to Bluetooth devices. The client applications where to run in several platforms, currently only J2ME (Nokia phones) and Windows Mobile phones. Windows Mobile actually offers a pretty decent Bluetooth stack but not all devices use this. One of the devices I needed to use used the Widcomm stack. Luckily, there is an open source project called 32feet.NET which came in very handy for providing a layer over the 2 different stacks I use. The 32feet.NET library was also incredibly easy and fun to use.

In this article I'd like to demonstrate how to enumerate Bluetooth devices using .NETCF and the 32feet.NET library. The following code will work on both Microsoft and Widcomm Bluetooth stacks:

using System.Diagnostics;
using InTheHand.Net.Sockets;
 
namespace BluetoothSample
{
    static class Program
    {
        private static void Main()
        {
            BluetoothDeviceInfo[] devices;
            using (BluetoothClient sdp = new BluetoothClient())
                devices = sdp.DiscoverDevices();
 
            foreach (BluetoothDeviceInfo deviceInfo in devices)
            {
                Debug.WriteLine(string.Format("{0} ({1})",deviceInfo.DeviceName, deviceInfo.DeviceAddress));
            }
        }
    }
}

An interesting thing I had to consider for this project was the CPU architecture or endianness of the device I'm running on and the device I'm sending data to. I needed to reverse the byte order of the numeric data I sent and received.

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Posted by christian.resma.helle on Thursday, July 29, 2010 2:25 AM
Permalink | Comments (0) | Post RSSRSS comment feed

Improve .NETCF Build Performance in Visual Studio

A lot of .NETCF developers are surprisingly not aware of the Platform Verification Task in Visual Studio. Disabling this in the build process will speed up the build of .NETCF projects. To make things quick and short, here's what you need to do:

1) Open the file C:\WINDOWS\Microsoft.NET\Framework\v3.5\Microsoft.CompactFramework.Common.targets for editing.

2) Change the following:

   99   <Target
  100     Name="PlatformVerificationTask">
  101     <PlatformVerificationTask
  102       PlatformFamilyName="$(PlatformFamilyName)"
  103       PlatformID="$(PlatformID)"
  104       SourceAssembly="@(IntermediateAssembly)"
  105       ReferencePath="@(ReferencePath)"
  106       TreatWarningsAsErrors="$(TreatWarningsAsErrors)"
  107       PlatformVersion="$(TargetFrameworkVersion)"/>
  108   </Target> 

to:

   99   <Target
  100     Name="PlatformVerificationTask">
  101     <PlatformVerificationTask
  102       Condition="'$(DoPlatformVerificationTask)'=='true'"
  103       PlatformFamilyName="$(PlatformFamilyName)"
  104       PlatformID="$(PlatformID)"
  105       SourceAssembly="@(IntermediateAssembly)"
  106       ReferencePath="@(ReferencePath)"
  107       TreatWarningsAsErrors="$(TreatWarningsAsErrors)"
  108       PlatformVersion="$(TargetFrameworkVersion)"/>
  109   </Target>
 
The following configuration above was an excert from an article called Platform Verification Task leading to slow builds on compact framework projects

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Posted by christian.resma.helle on Wednesday, July 28, 2010 4:51 AM
Permalink | Comments (1) | Post RSSRSS comment feed

ListView Custom Drawing in .NETCF

In this article I would like to demonstrate how to do custom drawing in the ListView control that the .NET Compact Framework provides. I'll be extending the code I published previously in the article entitled ListView Extended Styles in .NETCF

This is normally a very tedious and frustrating task to do and to accomplish this task we'll have to take advantage of the custom drawing service Windows CE provides for certain controls. A very good reference for custom drawing is an MSDN article called Customizing a Control's Appearance using Custom Draw. Before going any further, I may have to warn you about the extensive interop code involved in this task.

We'll have to handle the ListView windows messages ourselves, and we accomplish this by subclassing this ListView. Subclassing a window means that we assign a new window procedure for messages that are meant for the ListView. This can be done through the SetWindowLong() method with the GWL_WNDPROC parameter. When subclassing, the developer is responsible for choosing which messages they want to handle, which to ignore, and which they let operating system handle. To have the operating system handle the message, a call to CallWindowProc() is done using a pointer to original window procedure.

Before setting the new window procedure its important to get a pointer to the original one in case the developer wishes to let the operating system handle the message. This is done through GetWindowLong()Let's get started...First we need to define the interop structures for custom drawing

 

    struct RECT
    {
        public int left;
        public int top;
        public int right;
        public int bottom;
    }
 
    struct NMHDR
    {
        public IntPtr hwndFrom;
        public IntPtr idFrom;
        public int code;
    }
 
    struct NMCUSTOMDRAW
    {
        public NMHDR nmcd;
        public int dwDrawStage;
        public IntPtr hdc;
        public RECT rc;
        public int dwItemSpec;
        public int uItemState;
        public IntPtr lItemlParam;
    }
 
    struct NMLVCUSTOMDRAW
    {
        public NMCUSTOMDRAW nmcd;
        public int clrText;
        public int clrTextBk;
        public int iSubItem;
        public int dwItemType;
        public int clrFace;
        public int iIconEffect;
        public int iIconPhase;
        public int iPartId;
        public int iStateId;
        public RECT rcText;
        public uint uAlign;
    }
 

Note: In C# (and VB and C++), the StructLayout is Sequencial by default, hence I didn't state itThe P/Invoke declarations we need are the following: 

 

    [DllImport("coredll.dll")]
    static extern IntPtr CallWindowProc(IntPtr lpPrevWndFunc, IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
 
    [DllImport("coredll")]
    static extern int SendMessage(IntPtr hWnd, int Msg, int wParam, ref RECT lParam);
 
    [DllImport("coredll.dll")]
    static extern uint SendMessage(IntPtr hwnd, uint msg, uint wparam, uint lparam);
 
    [DllImport("coredll.dll", SetLastError = true)]
    static extern int SetWindowLong(IntPtr hWnd, int nIndex, WndProcDelegate newProc);
 
    [DllImport("coredll.dll", SetLastError = true)]
    static extern IntPtr GetWindowLong(IntPtr hWnd, int nIndex);
 

And to make life a bit easier, I created some extension methods to the RECT struct we just defined.

 

     static class RectangleExtensions

    {
        public static Rectangle ToRectangle(this RECT rectangle)
        {
            return Rectangle.FromLTRB(rectangle.left, rectangle.top, rectangle.right, rectangle.bottom);
        }
 
        public static RectangleF ToRectangleF(this RECT rectangle)
        {
            return new RectangleF(rectangle.left, rectangle.top, rectangle.right, rectangle.bottom);
        }
    }
 
 

We'll need the following constants defined in the Platform SDK 

 

    const int GWL_WNDPROC = -4;
    const int WM_NOTIFY = 0x4E;
    const int NM_CUSTOMDRAW = (-12);
    const int CDRF_NOTIFYITEMDRAW = 0x00000020;
    const int CDRF_NOTIFYSUBITEMDRAW = CDRF_NOTIFYITEMDRAW;
    const int CDRF_NOTIFYPOSTPAINT = 0x00000010;
    const int CDRF_SKIPDEFAULT = 0x00000004;
    const int CDRF_DODEFAULT = 0x00000000;
    const int CDDS_PREPAINT = 0x00000001;
    const int CDDS_POSTPAINT = 0x00000002;
    const int CDDS_ITEM = 0x00010000;
    const int CDDS_ITEMPREPAINT = (CDDS_ITEM | CDDS_PREPAINT);
    const int CDDS_SUBITEM = 0x00020000;
    const int CDIS_SELECTED = 0x0001;
    const int LVM_GETSUBITEMRECT = (0x1000 + 56);
 
 

Custom drawing in the ListView will only work in the Details view mode. To ensure this, I set the View to View.Details in the constructor method. Since I'm extending my old ListViewEx (Enables ListView Extended Styles) I'm gonna enable Double buffering, Grid lines, and the Gradient background. I'm gonna enable subclassing on the ListView only when the parent is changed, this is because I need to receive messages sent to the parent control of the ListView. We also need a delegate for the new window procedure and a pointer to the original window procedure. And last but not the least we need the actual window procedure method. 

 

    delegate IntPtr WndProcDelegate(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam);
    IntPtr lpPrevWndFunc;
 
    public ListViewCustomDraw()
    {
        View = View.Details;
        DoubleBuffering = true;
        GridLines = true;
        Gradient = true;
 
        ParentChanged += delegate
        {
            lpPrevWndFunc = GetWindowLong(Parent.Handle, GWL_WNDPROC);
            SetWindowLong(Parent.Handle, GWL_WNDPROC, WndProc);
        };
    }
 
    private IntPtr WndProc(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam)
    {
        if (msg == WM_NOTIFY)
        {
            var nmhdr = (NMHDR)Marshal.PtrToStructure(lParam, typeof(NMHDR));
            if (nmhdr.hwndFrom == Handle && nmhdr.code == NM_CUSTOMDRAW)
                return CustomDraw(hWnd, msg, wParam, lParam);
 
        }
 
        return CallWindowProc(lpPrevWndFunc, hWnd, msg, wParam, lParam);
    }
 
 

In the new window procedure, we are only really interested in the WM_NOTIFY message, because this is what the NM_CUSTOMDRAW message is sent through. The LPARAM parameter of the message will contain the NMHDR which then contains the NM_CUSTOMDRAW message. The LPARAM also contains the NMLVCUSTOMDRAW which provide state and information about the ListView.

The trickiest part in performing custom drawing in the ListView is handling the drawing stage. We create a method called CustomDraw to handle the different drawing stages of the ListView 

 

    private IntPtr CustomDraw(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam)
    {
        int result;
        var nmlvcd = (NMLVCUSTOMDRAW)Marshal.PtrToStructure(lParam, typeof(NMLVCUSTOMDRAW));
        switch (nmlvcd.nmcd.dwDrawStage)
        {
            case CDDS_PREPAINT:
                result = CDRF_NOTIFYITEMDRAW;
                break;
 
            case CDDS_ITEMPREPAINT:
                var itemBounds = nmlvcd.nmcd.rc.ToRectangle();
                if ((nmlvcd.nmcd.uItemState & CDIS_SELECTED) != 0)
                {
                    using (var brush = new SolidBrush(SystemColors.Highlight))
                    using (var graphics = Graphics.FromHdc(nmlvcd.nmcd.hdc))
                        graphics.FillRectangle(brush, itemBounds);
                }
 
                result = CDRF_NOTIFYSUBITEMDRAW;
                break;
 
            case CDDS_SUBITEM | CDDS_ITEMPREPAINT:
                var index = nmlvcd.nmcd.dwItemSpec;
                var rect = new RECT();
                rect.top = nmlvcd.iSubItem;
                SendMessage(Handle, LVM_GETSUBITEMRECT, index, ref rect);
                rect.left += 2;
 
                Color textColor;
                if ((nmlvcd.nmcd.uItemState & CDIS_SELECTED) != 0)
                    textColor = SystemColors.HighlightText;
                else
                    textColor = SystemColors.ControlText;
 
                using (var brush = new SolidBrush(textColor))
                using (var graphics = Graphics.FromHdc(nmlvcd.nmcd.hdc))
                    graphics.DrawString(Items[index].SubItems[nmlvcd.iSubItem].Text,
                                        Font,
                                        brush,
                                        rect.ToRectangleF());
 
                result = CDRF_SKIPDEFAULT | CDRF_NOTIFYSUBITEMDRAW;
                break;
 
            default:
                result = CDRF_DODEFAULT;
                break;
        }
 
        return (IntPtr)result;
    }
 
 

In the first stage we handle is the CDDS_PREPAINT. Here we return CDRF_NOTIFYITEMDRAW to tell that we want to handle drawing of the row ourselves. After this we receive the CDDS_ITEMPREPAINT where we can draw the entire row.

We check if the row is selected through the uItemState field of NMCUSTOMDRAW, if this field has the CDIS_SELECTED flag then it means the item is selected, hence we draw a fill rectangle. After handling the CDDS_ITEMPREPAINT, we return CDRF_NOTIFYSUBITEMDRAW to tell that we want to draw the sub items ourselves.

For drawing the sub items we need to handle CDDS_SUBITEM | CDDS_ITEMPREPAINT. We can get the position index of the item through the dwItemSpec field of NMCUSTOMDRAW. To get the bounds of the current sub item we send the LVM_GETSUBITEMRECT message to the ListView and pass a pointer to RECT as the LPARAM. Before sending this message, set the "top" field of the RECT to the index of the sub item (retrieved from iSubItem field of NMLVCUSTOMDRAW. After drawing the sub item we return CDRF_SKIPDEFAULT | CDRF_NOTIFYSUBITEMDRAW to tell that we only care about handling the next sub item.

Well I hope you guys find this interesting and helpful. To keep things simple, I only demonstrated displaying plan text and a plain rectangle for the selection.

If you're interested in the full source code then you can grab it here.

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Posted by christian.resma.helle on Tuesday, July 27, 2010 2:54 AM
Permalink | Comments (1) | Post RSSRSS comment feed

ListView Background Image in .NETCF

In this short entry I'd like to demonstrate how to display a background image in the ListView control. For this we will send the LVM_SETBKIMAGE or the LVM_GETBKIMAGE message to the ListView control with the LVBKIMAGE struct as the LPARAM. Unfortunately, the Windows CE version of LVBKIMAGE does not support LVBKIF_SOURCE_URL flag which allows using an image file on the file system for the background image of the ListView.

The layout of the background image can be either tiled or specified by an offset percentage. The background image is not affected by custom drawing, unless of course you decide to fill each sub item rectangle. For setting the background image we use the LVBKIF_SOURCE_HBITMAP flag together with the layout which is either LVBKIF_STYLE_TILE or LVBKIF_STYLE_NORMAL. If we set the layout to LVBKIF_STYLE_NORMAL, then we have the option of setting where the image will be drawn by setting the value of xOffsetPercentage and yOffsetPercentage.

In this example I'd like to make use of extension methods to add the SetBackgroundImage() and GetBackgroundImage() methods to ListView. This can of course be easily used to in a property to an inherited ListView. 

public static class ListViewExtensions
{
    [DllImport("coredll")]
    static extern int SendMessage(IntPtr hWnd, int Msg, int wParam, ref LVBKIMAGE lParam);
 
    const int LVM_FIRST = 0x1000;
    const int LVM_SETBKIMAGE = (LVM_FIRST + 138);
    const int LVM_GETBKIMAGE = (LVM_FIRST + 139);
    const int LVBKIF_SOURCE_NONE = 0x00000000;
    const int LVBKIF_SOURCE_HBITMAP = 0x00000001;
    const int LVBKIF_STYLE_TILE = 0x00000010;
    const int LVBKIF_STYLE_NORMAL = 0x00000000;
 
    struct LVBKIMAGE
    {
        public int ulFlags;
        public IntPtr hbm;
        public IntPtr pszImage; // not supported
        public int cchImageMax;
        public int xOffsetPercent;
        public int yOffsetPercent;
    }
 
    public static void SetBackgroundImage(this ListView listView, Bitmap bitmap)
    {
        SetBackgroundImage(listView, bitmap, false);
    }
 
    public static void SetBackgroundImage(this ListView listView, Bitmap bitmap, bool tileLayout)
    {
        SetBackgroundImage(listView, bitmap, tileLayout, 0, 0);
    }
 
    public static void SetBackgroundImage(
        this ListView listView,
        Bitmap bitmap,
        bool tileLayout,
        int xOffsetPercent,
        int yOffsetPercent)
    {
        LVBKIMAGE lvBkImage = new LVBKIMAGE();
        if (bitmap == null)
            lvBkImage.ulFlags = LVBKIF_SOURCE_NONE;
        else
        {
            lvBkImage.ulFlags = LVBKIF_SOURCE_HBITMAP | (tileLayout ? LVBKIF_STYLE_TILE : LVBKIF_STYLE_NORMAL);
            lvBkImage.hbm = bitmap.GetHbitmap();
            lvBkImage.xOffsetPercent = xOffsetPercent;
            lvBkImage.yOffsetPercent = yOffsetPercent;
        }
 
        SendMessage(listView.Handle, LVM_SETBKIMAGE, 0, ref lvBkImage);
    }
 
    public static Bitmap GetBackgroundImage(this ListView listView)
    {
        LVBKIMAGE lvBkImage = new LVBKIMAGE();
        lvBkImage.ulFlags = LVBKIF_SOURCE_HBITMAP;
 
        SendMessage(listView.Handle, LVM_GETBKIMAGE, 0, ref lvBkImage);
 
        if (lvBkImage.hbm == IntPtr.Zero)
            return null;
        else
            return Bitmap.FromHbitmap(lvBkImage.hbm);
    }
}
 
Here's an example of exposing the background image as a property in an inherited ListView by using the extension methods above.
 
class ListViewEx : ListView
{
    public Bitmap BackgroundImage
    {
        get { return this.GetBackgroundImage(); }
        set { this.SetBackgroundImage(value, BackgroundLayout == BackgroundImageLayout.Tile); }
    }
 
    public BackgroundImageLayout BackgroundLayout { get; set; }
 
    public enum BackgroundImageLayout
    {
        Tile,
        Center
    }
}
 
A small catch with the ListView background image is that it is only supported in Windows CE 5.0 and later. Hope you found this information useful.

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Posted by christian.resma.helle on Tuesday, July 27, 2010 2:47 AM
Permalink | Comments (1) | Post RSSRSS comment feed

Problem upgrading to SQL Server (R2) before upgrading to TFS2010

When an instance of TFS2008 (or 2005) is to be upgraded to TFS2010 the SQL Server must be upgraded to 2008 (sp1) as a minimum. I expected this to be the smallest issue but the problem that:

"Rule 'Consistency validation for SQL Server registry keys' failed". The SQL Server registry keys from a prior installation cannot be modified. To continue, see SQL Server Setup documentation about how to fix registry keys.

It turned out to be a problem with the permissions for a registry key for SQL Server. Even though I tried to upgrade with an account with local admin rights there was a registry key which didn't allow access. For this particular instance it was the key:

HKEY_LOCAL_MACHINE\Software\Microsoft\Microsoft SQL Server\UDDI\MSSQLServer\SuperSocketNetLib\Lpc

The solution was to add the account which was used for the upgrade to have full access to this key. Probably write acces would have been sufficient.

The way to find out which key(s) it is/are is to look in the SQL Server installation log:

Folder: .\Microsoft SQL Server\100\Setup Bootstrap\LOG\ ("and then the date and time of the upgrade attempt")

Look for "System.UnauthorizedAccessException" in the Details.txt file

///Jørn

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Posted by jorn.floor.andersen on Monday, June 14, 2010 6:25 AM
Permalink | Comments (0) | Post RSSRSS comment feed

Error: Execution of a full-text operation failed. 'Access is denied.' Creating full text index on Workitem

Error:

TFS Error 2900: Execution of a full-text operation failed. 'Access is denied.' Creating full text index on Workitem

This error (actually the generic error 29000) came when installing TFS2008 on a dual-server configuration, where the data-tier was clustered. It turned out that the SQLFullTextService was running under the TFSService account and it didn't have sufficient rights to the databases.

Resolution: 

After the TFSSerice was made sysadmin on the database and the full-text service was restarted (from within SQLServer Mangement Studio or Cluster Admin - not the Service MMC as that would have made the fulltext service to fall to the secondary node) it worked.

Currently rated 5.0 by 3 people

  • Currently 5/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Posted by jorn.floor.andersen on Tuesday, December 09, 2008 6:13 PM
Permalink | Comments (8) | Post RSSRSS comment feed

Guide to upgrading TFS2005 to TFS2008

The link below is a guide to upgrading TFS2005 to TFS2008. It includes descriptions of different errors and work arounds for these found during a number of upgrades of various TFS installations. Further a number of the steps in the official upgrade guide is further detailed or corrected.

 

Team Foundation Server upgrade from 2005 to 2008.docx (35,18 kb)

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Posted by jorn.floor.andersen on Tuesday, December 09, 2008 3:52 PM
Permalink | Comments (3) | Post RSSRSS comment feed

Microsoft Visual Studio Team Explorer 2008 - ENU has encountered a problem during setup

If the Team Explorer is installed right after TFS has been installed the following error might occur:

This error can be ignored as long as it still says Succesfully installed in the end dialog. It seems to be related to the setup process running and some files still locked from the TFS install.

Currently rated 3.0 by 1 people

  • Currently 3/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Posted by jorn.floor.andersen on Tuesday, December 09, 2008 3:36 PM
Permalink | Comments (4) | Post RSSRSS comment feed

Materiale fra ALM seminar 13-11-2008: Projektstyring med TFS

Projektledelse med Team System 2008:

Projektledelse med Team System 2008.pdf (797,04 kb)

Projektledelse med Team System 2010:

Projektledelse med Team System 2010.pdf (383,65 kb)

Reports for VSTS 2008:

VSTS 2008 Reports.pdf (852,24 kb)

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Posted by jorn.floor.andersen on Saturday, November 15, 2008 6:15 AM
Permalink | Comments (11) | Post RSSRSS comment feed

ListView Extended Styles in .NETCF

In this article I would like to demonstrate how to extend the ListViewcontrol in the .NET Compact Framework. We will focus on enabling someof the ListView Extended Styles. If we take a look at the WindowsMobile 5.0 Pocket PC SDK we will see that there are certain features ofListView that aren't provided by the .NET Compact Framework.

Anexample of the ListView extended styles is displaying gridlines arounditems and subitems, double buffering, and drawing a gradientbackground. These extended styles can be enabled in native code byusing the ListView_SetExtendedListViewStyle macro or by sendingLVM_SETEXTENDEDLISTVIEWSTYLE messages to the ListView.

Send Message

Wewill be using a lot of P/Invoking so let's start with creating aninternal static class called NativeMethods. We need a P/Invokedeclaration for SendMessage(HWND, UINT, UINT, UINT).

internal static class NativeMethods
{
  [DllImport("coredll.dll")]
  public static extern uint SendMessage(IntPtr hwnd, uint msg, uint wparam, uint lparam);
}

Enabling and Disabling Extended Styles

Nowthat we have our SendMessage P/Invoke declaration in place, we canbegin extending the ListView control. Let's start off with creating aclass called ListViewEx that inherits from ListView. We need to lookinto the native header files of the Pocket PC SDK to get the ListViewMessages. For now we will only need LVM_[GET/SET]EXTENDEDLISTVIEWSTYLEmessage which will be the main focus of all the examples. I willdeclare my class as a partial class and create all the pieces one byone for each example. Let's create a private method called SetStyle(),this method will enable/disable extended styles for the ListView

public partial class ListViewEx : ListView
{
  private const uint LVM_FIRST = 0x1000;
  private const uint LVM_SETEXTENDEDLISTVIEWSTYLE = LVM_FIRST + 54;
  private const uint LVM_GETEXTENDEDLISTVIEWSTYLE = LVM_FIRST + 55;

  private void SetStyle(uint style, bool enable)
  {
    uint currentStyle = NativeMethods.SendMessage(
      Handle,
      LVM_GETEXTENDEDLISTVIEWSTYLE,
      0,
      0);

    if (enable)
      NativeMethods.SendMessage(
        Handle,
        LVM_SETEXTENDEDLISTVIEWSTYLE,
        0,
        currentStyle | style);
    else
      NativeMethods.SendMessage(
        Handle,
        LVM_SETEXTENDEDLISTVIEWSTYLE,
        0,
        currentStyle & ~style);
  }
}

Grid Lines

Formy first example, let's enable GridLines in the ListView control. Wecan do this by using LVS_EX_GRIDLINES. This displays gridlines arounditems and sub-items and is available only in conjunction with theDetails mode.

public partial class ListViewEx : ListView
{
  private const uint LVS_EX_GRIDLINES = 0x00000001;

  private bool gridLines = false;
  public bool GridLines
  {
    get { return gridLines; }
    set
    {
      gridLines = value;
      SetStyle(LVS_EX_GRIDLINES, gridLines);
    }
  }
}

Whatthe code above did was add the LVS_EX_GRIDLINES style to the existingextended styles by using the SetStyle() helper method we first created.

Aninteresting discovery to this is that the Design Time attributes of theCompact Framework ListView control includes the GridLines property. Nowthat we created the property in the code, when we open the VisualStudio Properties Window for our ListViewEx we will notice thatGridLines property we created falls immediately under the "Appearance"category and even includes a description :)

Double Buffering

Doyou notice that when you populate a ListView control with a lot ofitems, the drawing flickers a lot when you scroll up and down the list?Although it is not in the Pocket PC documentation for Windows Mobile5.0, the ListView actually has an extended style calledLVS_EX_DOUBLEBUFFER. Enabling the LVS_EX_DOUBLEBUFFER solves theflickering issue and gives the user a more smooth scrolling experience.

public partial class ListViewEx : ListView
{
  private const uint LVS_EX_DOUBLEBUFFER = 0x00010000;

  private bool doubleBuffering = false;
  public bool DoubleBuffering
  {
    get { return doubleBuffering; }
    set
    {
      doubleBuffering = value;
      SetStyle(LVS_EX_DOUBLEBUFFER, doubleBuffering);
    }
  }
}

Gradient Background

Anothercool extended style is the LVS_EX_GRADIENT. This extended style draws agradient background similar to the one found in Pocket Outlook. It usesthe system colors and fades from right to left. But what is really coolabout this is that this is done by the OS. All we had to do was enablethe style.

public partial class ListViewEx : ListView
{
  private const uint LVS_EX_GRADIENT = 0x20000000;

  private bool gradient = false;
  public bool Gradient
  {
    get { return doubleBuffering; }
    set
    {
      gradient = value;
      SetStyle(LVS_EX_GRADIENT, gradient);
    }
  }
}

Ifyou want to look more into extended styles then I suggest you check outthe Pocket PC Platform SDK documentation. There a few other extendedstyles that I did not discuss that might be useful for you. You can getthe definitions in a file called commctrl.h in your Windows Mobile SDK"INCLUDE" directory.

Currently rated 5.0 by 1 people

  • Currently 5/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Posted by christian.resma.helle on Thursday, October 30, 2008 7:25 AM
Permalink | Comments (2) | Post RSSRSS comment feed