Hide a ListView column List Form FormView as a detailed view without deleting the column or resizing it to zero

I have a C # Net 2.0 Windows Forms ListView with about ten columns filled with data when the application starts. The data is huge, so it cannot be reloaded quickly. My ListView has a Details View element and allows the user to resize each column separately.

The user can hide any of ten columns or several of them immediately and again display the columns at any time in a non-specific row. Data is not deleted when the column is hidden.

The following actions I tried but the result was not satisfied:

1) Resizing a column with a size of 0 will make it somewhat disappear until the user starts playing with columns. The user will accidentally resize them, because there is an option in my ListView that allows the user to manually resize each column.

2) When deleting a column, the following problem arises: when I try to add a column back, the column does not remember its position and size. Position is the main problem, I will try to explain why. If my user decides to hide “column 2” first and then “column 3” and then the user hides 3 to 2, then “Index 2” does not exist, so I cannot insert index No. 3, and the exception is raised. Even if I remember the position of the index before deleting, I cannot simply return the column back to this index, because I do not know if there were previous columns that were already hidden, or which column disappeared before or after, or whether or not were hidden. Thus, the scenario can be as follows: 1 shown, 2 hidden, 3 hidden, 4 shown, 5 hidden, 6 hidden, 7 hidden, 8 shown, 9 hidden, 10 hidden.

Possible solutions "1)" and "2)" are automatically excluded in the script. It is even better to make the column width equal to zero, but since my user will be able to resize the columns at any time as necessary, resizing to zero cannot be hidden from the user. The user will display it in size, and my system will assume that it is still hidden, etc. Etc., And it doesn’t look professional if the hidden columns can simply be “reversed” or as we might call it another.

Anyone have a better idea? Why is there no “visible” or “hidden” property in the ListView column, interesting? If someone has done this already before submitting the solution.

I must add that when adding data, I use automation of all the columns in my list. For this reason, the answer below does not work. The resize event cannot determine the width -1. All invisible columns with a width of 0 will be changed when the data is added. Since listview cuts out data that overlays the length of the column, I need to autoresist it forever. Explorer does not have this problem because it fits the columns to the length of the data. C # does not have such an extended list, here I have to set the columns to -1 every time I add data. The idea of ​​column.width = 0 for hiding columns does not work in this concept.

+4
source share
2 answers

Ok, your problem is actually How to hide a ListView column? . This has been requested by many people on the Internet. I searched for many but found nothing. I got the only solution: Sets the column width to zero . This will work with some tricks here:

//This will try hiding the column at index 1 listView1.Columns[1].Width = 0; //ColumnWidthChanging event handler of your ListView private void listView1_ColumnWidthChanging(object sender, ColumnWidthChangingEventArgs e){ if(e.ColumnIndex == 1){ e.Cancel = true; e.NewWidth = 0; } } 

It works almost perfectly. However, when the user moves the mouse over the pipe at the position of the hidden column, the Cursor indicator appears, which notifies the user of something like that . There is a column of zero width, just hold the mouse and drag and resize it . Of course, the user cannot resize it with Zero , because we Cancel and do NewWidth = 0 (as the code above does). But Cursor , notifying of such an operation, makes it a little unpleasant, here is a screenshot showing the problem:

enter image description here

Solving this problem is not easy. At least that’s how I feel. I was thinking about this solution, which seems to work fine. The idea is that we need to determine if the mouse is above the hidden column pipe, we must set Cursor = Cursors.Arrow . Here is the whole class, which I think is great for you:

 public class CustomListView : ListView { [DllImport("user32")] private static extern bool EnumChildWindows(IntPtr parentHwnd, EnumChildProc proc, object lParam); delegate bool EnumChildProc(IntPtr childHwnd, object lParam); public CustomListView() { VisibleChanged += (s, e) => { if (Visible && headerHandle == IntPtr.Zero&&!DesignMode) { EnumChildWindows(Handle, EnumChild, null); headerProc = new HeaderProc(this); headerProc.AssignHandle(headerHandle); } }; columnPipeLefts[0] = 0; } //Save the Handle to the Column Headers, a ListView has only child Window which is used to render Column headers IntPtr headerHandle; //This is used use to hook into the message loop of the Column Headers HeaderProc headerProc; private bool EnumChild(IntPtr childHwnd, object lParam) { headerHandle = childHwnd; return true; } //Updated code protected override void WndProc(ref Message m) { if (m.Msg == 0x101e&&hiddenColumnIndices.Contains(m.WParam.ToInt32()))//WM_SETCOLUMNWIDTH = 0x101e { if(m.LParam.ToInt32() > 0) hiddenColumnWidths[m.WParam.ToInt32()] = m.LParam.ToInt32(); return;//Discard the message changing hidden column width so that it won't be shown again. } base.WndProc(ref m); } //Save the column indices which are hidden List<int> hiddenColumnIndices = new List<int>(); //Save the width of hidden columns Dictionary<int, int> hiddenColumnWidths = new Dictionary<int, int>(); //Save the Left (X-Position) of the Pipes which separate Column Headers. Dictionary<int, int> columnPipeLefts = new Dictionary<int, int>(); protected override void OnColumnWidthChanging(ColumnWidthChangingEventArgs e) { if (hiddenColumnIndices.Contains(e.ColumnIndex)) { e.Cancel = true; e.NewWidth = 0; } base.OnColumnWidthChanging(e); } //We need to update columnPipeLefts whenever the width of any column changes protected override void OnColumnWidthChanged(ColumnWidthChangedEventArgs e) { base.OnColumnWidthChanged(e); UpdateColumnPipeLefts(Columns[e.ColumnIndex].DisplayIndex + 1); } int index = -1; protected override void OnColumnReordered(ColumnReorderedEventArgs e) { int i = Math.Min(e.NewDisplayIndex, e.OldDisplayIndex); index = index != -1 ? Math.Min(i + 1, index) : i + 1; base.OnColumnReordered(e); } //This is used to update the columnPipeLefts every reordering columns or resizing columns. private void UpdateColumnPipeLefts(int fromIndex) { int w = fromIndex > 0 ? columnPipeLefts[fromIndex - 1] : 0; for (int i = fromIndex; i < Columns.Count; i++) { w += i > 0 ? Columns.OfType<ColumnHeader>().Where(k=>k.DisplayIndex == i - 1).Single().Width : 0; columnPipeLefts[i] = w; } } //This is used to hide a column with ColumnHeader passed in public void HideColumn(ColumnHeader col) { if (!hiddenColumnIndices.Contains(col.Index)) { hiddenColumnWidths[col.Index] = col.Width;//Save the current width to restore later col.Width = 0;//Hide the column hiddenColumnIndices.Add(col.Index); } } //This is used to hide a column with column index passed in public void HideColumn(int columnIndex) { if (columnIndex < 0 || columnIndex >= Columns.Count) return; if (!hiddenColumnIndices.Contains(columnIndex)) { hiddenColumnWidths[columnIndex] = Columns[columnIndex].Width;//Save the current width to restore later Columns[columnIndex].Width = 0;//Hide the column hiddenColumnIndices.Add(columnIndex); } } //This is used to show a column with ColumnHeader passed in public void ShowColumn(ColumnHeader col) { hiddenColumnIndices.Remove(col.Index); if(hiddenColumnWidths.ContainsKey(col.Index)) col.Width = hiddenColumnWidths[col.Index];//Restore the Width to show the column hiddenColumnWidths.Remove(col.Index); } //This is used to show a column with column index passed in public void ShowColumn(int columnIndex) { if (columnIndex < 0 || columnIndex >= Columns.Count) return; hiddenColumnIndices.Remove(columnIndex); if(hiddenColumnWidths.ContainsKey(columnIndex)) Columns[columnIndex].Width = hiddenColumnWidths[columnIndex];//Restore the Width to show the column hiddenColumnWidths.Remove(columnIndex); } //The helper class allows us to hook into the message loop of the Column Headers private class HeaderProc : NativeWindow { [DllImport("user32")] private static extern int SetCursor(IntPtr hCursor); public HeaderProc(CustomListView listView) { this.listView = listView; } bool mouseDown; CustomListView listView; protected override void WndProc(ref Message m) { if (m.Msg == 0x200 && listView!=null && !mouseDown) { int x = (m.LParam.ToInt32() << 16) >> 16; if (IsSpottedOnAnyHiddenColumnPipe(x)) return; } if (m.Msg == 0x201) { mouseDown = true; int x = (m.LParam.ToInt32() << 16) >> 16; IsSpottedOnAnyHiddenColumnPipe(x); } if (m.Msg == 0x202) mouseDown = false; if (m.Msg == 0xf && listView.index != -1 && MouseButtons == MouseButtons.None) { //WM_PAINT = 0xf listView.UpdateColumnPipeLefts(listView.index); listView.index = -1; }; base.WndProc(ref m); } private bool IsSpottedOnAnyHiddenColumnPipe(int x) { foreach (int i in listView.hiddenColumnIndices.Select(j=>listView.Columns[j].DisplayIndex)) { if (x > listView.columnPipeLefts[i] - 1 && x < listView.columnPipeLefts[i] + 15) { SetCursor(Cursors.Arrow.Handle); return true; } } return false; } } } 
+8
source

Please replace the first lines of code with this here - it uses a more elegantly internal list view API to get the title descriptor - old code failed @EnumChildWindows ):

  [DllImport("user32.dll", EntryPoint = "SendMessage")] private static extern IntPtr SendMessage(IntPtr hwnd, int wMsg, IntPtr wParam, IntPtr lParam); const int LVM_FIRST = 0x1000; const int LVM_GETHEADER = (LVM_FIRST + 31); public CustomListView() { VisibleChanged += (s, e) => { if (Visible && headerHandle == IntPtr.Zero && !DesignMode) { IntPtr hwnd = SendMessage(this.Handle, LVM_GETHEADER, IntPtr.Zero, IntPtr.Zero); if (hwnd != null) { headerProc = new HeaderProc(this); headerHandle = hwnd; headerProc.AssignHandle(hwnd); } } }; columnPipeLefts[0] = 0; } 
0
source

Source: https://habr.com/ru/post/1495810/


All Articles