vb.netwinformsdatagridviewdatagridviewcolumn

How to get Design > Name property of DGV column from Header Text property


I am trying to go through un-checked items within a CheckedListBox1 and based on the values returned hide relevant columns within DataGridView1 but the issue is that the values displayed in CheckedListBox1 are the HeaderText property of DGV column and not the Name property which is required for hiding the column within DGV.

See below code:

For Each checked_item As Object In CheckedListBox1.Items
            If Not CheckedListBox1.CheckedItems.Contains(checked_item) Then
                DataGridView1.Columns("").Visible = False
            End If
        Next

Is there a way to retrieve "Name" property of DGV column when referencing the column's HeaderText property?


Solution

  • You don't need the column name to hide the column. You need the column. The name is just a means to get the column. The issue is the way you're populating your CheckedListBox. Displaying the HeaderText makes perfect sense, because that's what the user actually sees. What you should be doing is putting the columns themselves into the CheckedListBox and just displaying the HeaderText. That way, the items are the columns, e.g.

    Dim columns = DataGridView1.Columns.Cast(Of DataGridViewColumn)().ToArray()
    
    With CheckedListBox1
        .DataSource = columns
        .DisplayMember = NameOf(DataGridViewColumn.HeaderText)
    End With
    

    The code you posted then becomes this:

    For i = 0 To CheckedListBox1.Items.Count - 1
        Dim column = DirectCast(CheckedListBox1.Items(i), DataGridViewColumn)
    
        column.Visible = CheckedListBox1.GetItemChecked(i)
    Next
    

    Note that you should generally set the DataSource last when binding but that doesn't seem to work with a CheckedListBox, which doesn't offically support data-binding. For that reason, the DataSource is set first.

    EDIT:

    I'm adding this after the comment was added to the question about the ItemCheck event and the checking of the items at startup. The key here is to not actually act on the event until the list has been initialised, i.e. all the items have been initially checked. One way to do that would be like so:

    Private isLoaded As Boolean = False
    
    Private Sub Form1_Load(...) Handles MyBase.Load
        'Bind the data and check the items in the CheckedListBox here.
    
        isLoaded = True
    End Sub
    
    Private Sub CheckedListBox1_ItemCheck(...) CheckedListBox1.ItemCheck
        If isLoaded Then
            'Act here.
        End If
    End Sub
    

    The other way to is to prevent event being raised by not handling it while the initialisation is taking place. That can be done in a couple of ways but I'll leave that to you as an exercise if that's what you want to do.

    As the ItemCheck event is raised before the state of an item changes, you will need to treat the current item differently to the other items. My loop above would become this:

    For i = 0 To CheckedListBox1.Items.Count - 1
        Dim column = DirectCast(CheckedListBox1.Items(i), DataGridViewColumn)
    
        'For the item that is being checked/unchecked, use its new state.
        'For other items, use their current state.
        column.Visible = If(i = e.Index,
                            e.NewValue = CheckState.Checked,
                            CheckedListBox1.GetItemChecked(i))
    Next
    

    That said, if all items are initially checked and all columns are initially visible, it's only the current item that you need to care about, so there's no need for a loop at all:

    Dim column = DirectCast(CheckedListBox1.Items(e.Index), DataGridViewColumn)
    
    column.Visible = (e.NewValue = CheckState.Checked)