question

RashmiGupta avatar image
0 Votes"
RashmiGupta asked JackJJun-MSFT commented

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

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?

dotnet-csharpdotnet-visual-basicoffice-vba-devdotnet-runtimedotnet-standard
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

Castorix31 avatar image
0 Votes"
Castorix31 answered Castorix31 commented

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
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

Thanks for answering. I guess it will demand deep understating the whole concept you are trying to explain and I have to submit my work today. I'll try it in future whenever I need.

0 Votes 0 ·

The main code is simple (most of code is declarations)
The main part is in CDDS.CDDS_ITEMPOSTPAINT
I test the flag LVIS_CUT (set in double-click (removed in Right double-click), that you can also set with your menu for example)
If it is set, I draw a Rectangle over the default drawing (PostPaint is generated after the default drawing)
You can also change colors in PrePaint, but if you draw there, it will erase the default drawing

0 Votes 0 ·
JackJJun-MSFT avatar image
0 Votes"
JackJJun-MSFT answered JackJJun-MSFT commented

@RashmiGupta, 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.








3.gif (85.6 KiB)
· 6
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

I've already tried this way and didn't succeed. Even I tried putting line no. 5 in your code above to line no. 4, but didn't work

0 Votes 0 ·

@RashmiGupta, Could you upload your project to OneDrive or GitHub? It will better for us to analyze your problem.

0 Votes 0 ·

Actually, it is my company's project and I can't share the whole code.

0 Votes 0 ·
Show more comments