How to change the selected listviewitem's backcolor to transparent on a click of toolstripmenuitem?

Rashmi Gupta 81 Reputation points
2021-10-05T03:34:26.647+00:00

Hi,
I have a listview which shows images of symbols n I am introducing a method to cut n copy the selected symbols. I am using a toolstripmenu having Cut n Copy menu items which pops up on right click after listviewitem selection, just like the file system do. I want to change the backcolor of selected items when user selects "Cut" from the toolstripmenu.
In the handling Cut's click event handler method , I tried to change the selected items' backcolor property but didn't succeed.
I set the focus to false for each selected item, then changed its backcolor, didn't succeed.
I set the selected property to false for each selected item, then changed its backcolor, didn't succeed.
I changed the backcolor of each selected item,then changed its focus to false , didn't succeed.
I changed the backcolor of each selected item,then changed its selected property to false , didn't succeed.
The listview's OwnerDraw property was set to false and it was displaying items' images properly. I found out that to change the backcolor, I've to set listview's OwnerDraw property = true which calls the DrawItem event. Then I should change the color in the DrawItem event handler method.
So I change the listview's OwnerDraw property = true in the Cut's click event handler method and implemented the DrawItem event handler method like this :

      Private Sub tsmCopySymbl_Click(sender As Object, e As EventArgs) Handles tsbCopySymbl.Click, tsbCutSymbl.Click

        cutSymbol = If(sender.Equals(tsbCutSymbl), True, False)
             '
`            'Code for copying items
             '
            ListViewHyDwExplorer.OwnerDraw = True
        End If
    End Sub

     Private Sub ListViewHyDwExplorer_DrawItem(sender As Object, e As DrawListViewItemEventArgs) Handles ListViewHyDwExplorer.DrawItem`enter code here`
          if cutSymbol then
            For Each item As ListViewItem In ListViewHyDwExplorer.SelectedItems
                Dim itemRect As Rectangle = item.GetBounds(ItemBoundsPortion.ItemOnly)
                Dim grayBrush As Brush = New SolidBrush(Color.LightGray)
                e.Graphics.FillRectangle(grayBrush, itemRect)
            Next
          End If
        End Sub

It fills the selected item's rectangle but, it erases all the other items and I know that to draw the each item, I've to put the code to draw listviewitems, in DrawItem event handler method. But, it is already a large code; the listview is working fine and showing items' image properly and I don't wanna change the working things just to change the backcolor of selected items just for a particular event.
I also Tried to get the graphics of selected item's image and fill item's rectangle with desired color but it didn't work.
Can any one please tell me the easier way to do it without creating a mess up?

.NET
.NET
Microsoft Technologies based on the .NET software framework.
3,395 questions
C#
C#
An object-oriented and type-safe programming language that has its roots in the C family of languages and includes support for component-oriented programming.
10,277 questions
VB
VB
An object-oriented programming language developed by Microsoft that is implemented on the .NET Framework. Previously known as Visual Basic .NET.
2,578 questions
.NET Runtime
.NET Runtime
.NET: Microsoft Technologies based on the .NET software framework.Runtime: An environment required to run apps that aren't compiled to machine language.
1,125 questions
0 comments No comments
{count} votes

2 answers

Sort by: Most helpful
  1. Castorix31 81,741 Reputation points
    2021-10-05T07:34:45+00:00

    You can use Custom Draw instead of Owner Draw
    For example in this test I draw a Light Gray rectangle in CDDS_ITEMPOSTPAINT event when I double-click on an item

    Code in C# as you tagged dotnet-csharp, same code in VB :

    137647-listview-customdraw.gif

    Test :

    public class ListViewCustom : ListView  
    {   
        [StructLayout(LayoutKind.Sequential)]  
        private struct RECT  
        {  
            public int left;  
            public int top;  
            public int right;  
            public int bottom;  
        }  
      
        [StructLayout(LayoutKind.Sequential)]  
        private struct NMHDR  
        {  
            public IntPtr hwndFrom;  
            public IntPtr idFrom;  
            public int code;  
        }  
      
        [StructLayout(LayoutKind.Sequential)]  
        private struct NMLISTVIEW  
        {  
            public NMHDR hdr;  
            public int iItem;  
            public int iSubItem;  
            public uint uNewState;  
            public uint uOldState;  
            public uint uChanged;  
            public Point ptAction;  
            public IntPtr lParam;  
        }  
      
        [StructLayout(LayoutKind.Sequential)]  
        private struct NMCUSTOMDRAW  
        {  
            public NMHDR hdr;  
            public int dwDrawStage;  
            public IntPtr hdc;  
            public RECT rc;  
            public IntPtr dwItemSpec;  
            public uint uItemState;  
            public IntPtr lItemlParam;  
        }  
      
        [StructLayout(LayoutKind.Sequential)]  
        private 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;  
        }  
      
        [FlagsAttribute]  
        private enum CDRF  
        {  
            CDRF_DODEFAULT = 0x00000000,  
            CDRF_NEWFONT = 0x00000002,  
            CDRF_SKIPDEFAULT = 0x00000004,  
            CDRF_DOERASE = 0x00000008,  
            CDRF_SKIPPOSTPAINT = 0x00000100,  
            CDRF_NOTIFYPOSTPAINT = 0x00000010,  
            CDRF_NOTIFYITEMDRAW = 0x00000020,  
            CDRF_NOTIFYSUBITEMDRAW = 0x00000020,  
            CDRF_NOTIFYPOSTERASE = 0x00000040  
        }  
      
        [FlagsAttribute]  
        private enum CDDS  
        {  
            CDDS_PREPAINT = 0x00000001,  
            CDDS_POSTPAINT = 0x00000002,  
            CDDS_PREERASE = 0x00000003,  
            CDDS_POSTERASE = 0x00000004,  
            CDDS_ITEM = 0x00010000,  
            CDDS_ITEMPREPAINT = (CDDS_ITEM | CDDS_PREPAINT),  
            CDDS_ITEMPOSTPAINT = (CDDS_ITEM | CDDS_POSTPAINT),  
            CDDS_ITEMPREERASE = (CDDS_ITEM | CDDS_PREERASE),  
            CDDS_ITEMPOSTERASE = (CDDS_ITEM | CDDS_POSTERASE),  
            CDDS_SUBITEM = 0x00020000  
        }  
      
        [StructLayout(LayoutKind.Sequential)]  
        private struct LV_ITEM  
        {  
            public uint mask;  
            public int iItem;  
            public int iSubItem;  
            public uint state;  
            public uint stateMask;  
            public string pszText;  
            public int cchTextMax;  
            public int iImage;  
            public IntPtr lParam;  
            public int iIndent;  
            public int iGroupId;  
            public uint cColumns; // tile view columns  
            public IntPtr puColumns;  
            public IntPtr piColFmt;  
            public int iGroup; // readonly. only valid for owner data.  
        }  
      
        public const int LVM_FIRST = 0x1000;  
        public const int LVM_SETITEMSTATE = (LVM_FIRST + 43);  
        public const int LVM_GETITEMSTATE = (LVM_FIRST + 44);  
      
        private const int NM_FIRST = 0;  
        private const int NM_CLICK = (NM_FIRST - 2);  
        private const int NM_DBLCLK = (NM_FIRST - 3);  
        private const int NM_RETURN = (NM_FIRST - 4);  
        private const int NM_RCLICK = (NM_FIRST - 5);  
        private const int NM_RDBLCLK = (NM_FIRST - 6);  
        private const int NM_SETFOCUS = (NM_FIRST - 7);  
        private const int NM_KILLFOCUS = (NM_FIRST - 8);  
        private const int NM_CUSTOMDRAW = (NM_FIRST - 12);  
        private const int WM_REFLECT = 0x2000;  
        private const int WM_NOFITY = 0x004e;  
      
        private const int LVIS_FOCUSED = 0x0001;  
        private const int LVIS_SELECTED = 0x0002;  
        private const int LVIS_CUT = 0x0004;  
        private const int LVIS_DROPHILITED = 0x0008;  
        private const int LVIS_GLOW = 0x0010;  
        private const int LVIS_ACTIVATING = 0x0020;  
        private const int LVIS_OVERLAYMASK = 0x0F00;  
        private const int LVIS_STATEIMAGEMASK = 0xF000;  
        private static int INDEXTOSTATEIMAGEMASK(int i)  
        {  
            return ((i) << 12);  
        }  
      
        [DllImport("User32.dll", SetLastError = true, CharSet = CharSet.Auto)]  
        public static extern int SendMessage(IntPtr hWnd, uint msg, int wParam, IntPtr lParam);  
      
        [DllImport("User32.dll", SetLastError = true, CharSet = CharSet.Auto)]  
        private static extern int SendMessage(IntPtr hWnd, uint msg, int wParam, ref LV_ITEM lParam);  
      
        private static void ListView_SetItemState(IntPtr hwndLV, int i, uint state, uint mask)  
        {  
            LV_ITEM lvi = new LV_ITEM();  
            lvi.stateMask = mask;  
            lvi.state = state;  
            SendMessage(hwndLV, LVM_SETITEMSTATE, i, ref lvi);  
        }  
      
        private static uint ListView_GetItemState(IntPtr hwndLV, int i, uint mask)  
        {  
            return (uint)SendMessage(hwndLV, LVM_GETITEMSTATE, i, (IntPtr)mask);  
        }  
      
        protected override void WndProc(ref Message m)  
        {  
            if (m.Msg == WM_REFLECT + WM_NOFITY)  
            {  
                var pnmhdr = (NMHDR)m.GetLParam(typeof(NMHDR));  
                if (pnmhdr.code == NM_CUSTOMDRAW)  
                {  
                    var pnmlv = (NMLVCUSTOMDRAW)m.GetLParam(typeof(NMLVCUSTOMDRAW));  
                    switch (pnmlv.nmcd.dwDrawStage)  
                    {  
                        case (int)CDDS.CDDS_PREPAINT:  
                            m.Result = new IntPtr((int)CDRF.CDRF_NOTIFYITEMDRAW);  
                            break;  
                        case (int)CDDS.CDDS_ITEMPREPAINT:  
                            m.Result = new IntPtr((int)(CDRF.CDRF_NOTIFYSUBITEMDRAW | CDRF.CDRF_NOTIFYPOSTPAINT));  
                            break;  
                        case (int)CDDS.CDDS_ITEMPOSTPAINT:  
                            int nItem = (int)pnmlv.nmcd.dwItemSpec;  
                            uint nItemState = ListView_GetItemState(m.HWnd, nItem, LVIS_CUT);  
                            bool bCut = (nItemState & LVIS_CUT) == LVIS_CUT;  
                            Rectangle itemRect = this.GetItemRect(nItem);  
                            if (nItem != -1)  
                            {  
                                if (bCut)  
                                {  
                                    using (Graphics gr = Graphics.FromHdc(pnmlv.nmcd.hdc))  
                                    {  
                                        Brush grayBrush = new SolidBrush(Color.FromArgb(120, 211, 211, 211));  
                                        gr.FillRectangle(grayBrush, itemRect);  
                                    }                                    
                                }  
                            }  
                            break;  
                    }  
                }  
                else if (pnmhdr.code == NM_DBLCLK)  
                {  
                    var pnmlv = (NMLISTVIEW)m.GetLParam(typeof(NMLISTVIEW));  
                    int nItem = pnmlv.iItem;  
                    if (nItem != -1)  
                    {  
                        ListView_SetItemState(m.HWnd, nItem, LVIS_CUT, LVIS_CUT);  
                    }  
                }  
                else if (pnmhdr.code == NM_RDBLCLK)  
                {  
                    var pnmlv = (NMLISTVIEW)m.GetLParam(typeof(NMLISTVIEW));  
                    int nItem = pnmlv.iItem;  
                    if (nItem != -1)  
                    {  
                        ListView_SetItemState(m.HWnd, nItem, 0, LVIS_CUT);  
                    }  
                }  
                return;  
            }  
            else  
                base.WndProc(ref m);  
        }  
    }  
    

  2. Jack J Jun 24,296 Reputation points Microsoft Vendor
    2021-10-05T08:11:30.043+00:00

    @Rashmi Gupta , based on my test, I reproduced the problem that "I tried to change the selected items' backcolor property but didn't succeed".

    According to my further test, I find that we need to unselect the selected items to set the backcolor property correctly.

    Code:

     Private Sub ToolStripButton1_Click(sender As Object, e As EventArgs) Handles ToolStripButton1.Click  
            For Each item As ListViewItem In ListView1.SelectedItems  
      
                item.BackColor = Color.LightGray  
                item.Selected = False  
      
            Next  
      
      
        End Sub  
    

    Completed Code:

    Public Class Form1  
        Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load  
            ListView1.View = View.Details  
            ListView1.Columns.Add("Name")  
            ListView1.Columns.Add("Age")  
            ListView1.Columns.Add("ID")  
      
            Dim myItems As String() = New String() {  
                                "test1",  
                                "22",  
                                "1001"}  
            Dim myItems1 As String() = New String() {  
                                "test2",  
                                "23",  
                                "1002"}  
            Dim myItems2 As String() = New String() {  
                                "test3",  
                                "24",  
                                "1003"}  
            ListView1.Items.Add(New ListViewItem(myItems))  
            ListView1.Items.Add(New ListViewItem(myItems1))  
            ListView1.Items.Add(New ListViewItem(myItems2))  
      
        End Sub  
        Dim cutSymbol As Boolean = False  
        Private Sub ToolStripButton1_Click(sender As Object, e As EventArgs) Handles ToolStripButton1.Click  
            For Each item As ListViewItem In ListView1.SelectedItems  
      
                item.BackColor = Color.LightGray  
                item.Selected = False  
      
            Next  
      
      
        End Sub  
    End Class  
    

    Result:

    137655-3.gif


    If the response is helpful, please click "Accept Answer" and upvote it.

    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.