Luka Ćetković Luka Ćetković - 2 months ago 15
C# Question

How to display a browsable(false) property

I want to display the

MachineName
property of the
System.ServiceProcess.ServiceController
in a
DataGridView
control:

dataGridView1.DataSource = ServiceController.GetServices();


It does not add the
MachineName
property. As far as I was able to find out this is due to the
[Browsable(false)]
attribute of the property.

But when I add columns manually like this:

dataGridView1.ColumnCount = 2;
dataGridView1.AutoGenerateColumns = false;
dataGridView1.Columns[0].Name = "Machine Name";
dataGridView1.Columns[0].DataPropertyName = "MachineName";
dataGridView1.Columns[1].Name = "Display Name";
dataGridView1.Columns[1].DataPropertyName = "DisplayName";

BindingSource bs = new BindingSource();
bs.DataSource = ServiceController.GetServices();
dataGridView1.DataSource = bs;


I expect the
MachineName
column to be filled when in fact while the column gets created the value displayed in the column is empty.

Is there a workaround so I can display this property?

Not a duplicate:

I'm not trying to override the datagrid view control so the AutoGenerateColumns Property of datagrid view will be visible in designer. I'm trying to Display a ServiceController Property with
[Browsable(false)]
attribute in the DataGridView
.

My final solution for anyone that is interested:

private void dataGridView1_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
{
if (e.ColumnIndex < 0 || e.RowIndex < 0)
return;
if ( this.dataGridView1.Columns[e.ColumnIndex].DataPropertyName == "MachineName")
{
var model = this.dataGridView1.Rows[e.RowIndex].DataBoundItem as ServiceController;
if (model != null)
e.Value = model.MachineName;
}
}

Answer

Here the column is not auto-generated. It's generated but the value of cell is null because the property is not browsable.

There are multiple solutions to solve the problem, including:

  • Use CellFormatting event and provide value for celll
  • Shape the result in a model or anonymous object with the same property names.

Using CellFormatting

You can use CellFormatting and find the DataBound item behind the row and use the value of property directly from the model:

void dataGridView1_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
{
    if (e.ColumnIndex < 0 || e.RowIndex < 0)
        return;
    var model = this.dataGridView1.Rows[e.RowIndex].DataBoundItem as Model;
    if (model != null)
        e.Value = model.SomeField;
}

Shape the result

You can shape the result of your query to a model or anonymous object having the same property names as your original model to preserve column settings:

dataGridView1.DataSource = list.Select(x => new { Field1= x.Field1, Field2 = x.Field2 })
                               .ToList();