23

I have a DataGridView and I need to add custom objects to it. Consider the following code:

DataGridView grid = new DataGridView();
grid.DataSource = objects;

With this code I get a DataGridView object with all properties as columns. In my case, I don't want to show all of this information; I want to show just two or three columns. I know that I can set

AutoGenerateColumns = false.

But I do not know how to proceed afterwards. One option is to hide all columns that do not interest me, but I think it would be better to do it in the opposite way. How can I do this?

Sabuncu
  • 5,095
  • 5
  • 55
  • 89
Cristhian Boujon
  • 4,060
  • 13
  • 51
  • 90

8 Answers8

31

Whenever I do this I usually make grid.DataSource the result of a LINQ projection on the objects.

So something like this:

grid.DataSource = objects.Select(o => new
    { Column1 = o.SomeValue, Column2 = o.SomeOtherValue }).ToList();

The nice thing is that you can then set AutoGenerateColumns to true, which will generate columns based on the properties of the projected objects.

Edit:

The one downside to this approach is that by projecting everything into an anonymous object, you can have problems in situations where you need to access a specific object in a click event, for example.

In this case you may be better off defining an explicit view model and projecting your objects into those. E.g.,

class MyViewModel
{
    public int Column1 { get;set; }
    public int Column2 { get;set; }
}

grid.DataSource = objects.Select(o => new MyViewModel()
    { Column1 = o.SomeValue, Column2 = o.SomeOtherValue }).ToList();

Edit 2:

MyViewModel represents all of the columns you want to display in the DataGridView. The example properties should of course be renamed to suit what you are doing. In general, the point of a ViewModel is to serve as a sort of converter that mediates between the model (in your case your list of objects) and the view.

If you are wanting to retain a reference to the underlying object, the best way might be to supply it via the constructor:

class MyViewModel
{
    public int Column1 { get;set; }
    public int Column2 { get;set; }

    ....

    private SomeType _obj;

    public MyViewModel(SomeType obj)
    {
        _obj = obj;
    }

    public SomeType GetModel()
    {
        return _obj;
    }
}

grid.DataSource = objects.Select(o => new MyViewModel(o)
    { Column1 = o.SomeValue, Column2 = o.SomeOtherValue }).ToList();

The reason I have gone for a getter method to retrieve the underlying model object is simply to avoid a column being generated for it.

nick_w
  • 14,758
  • 3
  • 51
  • 71
  • @Overflow012 what do you mean by that? – nick_w Feb 10 '13 at 02:40
  • I need get my custom object when I click in a row. If I do it this way I cant get it. I'm right? – Cristhian Boujon Feb 10 '13 at 03:05
  • @Overflow012 Good point, I see what you mean. Yes, if you want to do that then you would need to use an approach like in my edit. – nick_w Feb 10 '13 at 03:09
  • What is `MyViewModel` in yor example? – Cristhian Boujon Feb 10 '13 at 05:25
  • I am trying to understand what `objects` refers to in your code at the very top, before either of the edits. Is it, for example, a `DataTable`? Thank you. – Sabuncu Feb 11 '17 at 12:30
  • @Sabuncu I used `objects` so the terminology would be the same as in the question. The way I have done such things in the past, `objects` would generally be the result of a Linq to Entities query. – nick_w Feb 12 '17 at 01:13
  • Thanks for your answer. So then, what is `objects.Select()`? Isn't that also LINQ? Sorry if I'm asking obvious questions, it's just that I am not versed in LINQ. – Sabuncu Feb 12 '17 at 22:34
  • @Sabuncu Yes, `objects.Select()` is LINQ. In this case it would be a Linq to Entities operation that projects whatever is in `objects` into the desired structure for display. – nick_w Feb 12 '17 at 22:56
  • Thank you for your patience in answering my questions. – Sabuncu Feb 13 '17 at 13:09
11

You can also use Attribute [Browsable(false)] on any property in the underlying Objects, as may be appropriate. This of course would preempt the column from being browse-able some other place, so you might find that undesirable.

John
  • 633
  • 4
  • 9
  • 1+ This one have great point but some OP can't get it so we need a something like little bit presentation `:D` – spajce Feb 10 '13 at 04:45
11

You can use databindings with AutoGenerateColumns = false and using DataPropertyName like this

grid.Columns["Column_name_1"].DataPropertyName = "public_property_1";
grid.Columns["Column_name_2"].DataPropertyName = "public_property_2";

This way only bound columns will be shown in the datagridview, and you can create the columns in the editor if you want. Public properties can be any public attribute within your object.

If you are editing your data from the datagridview, then you should use NotifyPropertyChanged in the set methods. Se my question/answer here where I explain this all the way down.

Community
  • 1
  • 1
Alejandro del Río
  • 3,966
  • 3
  • 33
  • 31
8

The easiest is that you add the "System.ComponentModel.Browsable" attributes to your DataModel:

public class TheDataModel 
{
       [System.ComponentModel.Browsable(false)]
       public virtual int ID { get; protected set; }
       public virtual string FileName { get; set; }
       [System.ComponentModel.Browsable(false)]
       public virtual string ColumnNotShown1 { get; set; }
       [System.ComponentModel.Browsable(false)]
       public virtual string ColumnNotShown2  { get; set; }
}
mathtec
  • 191
  • 1
  • 6
7

This is my code from an old project. It can work for your case.

OleDbDataAdapter da = new OleDbDataAdapter("SELECT * FROM uyeler", baglanti);

da.Fill(dbDataSet1, "uyeler");

//Set AutoGenerateColumns False
dataGridView1.AutoGenerateColumns = false;

//Set Columns Count
dataGridView1.ColumnCount = 5;

//Add Columns
dataGridView1.Columns[0].Name = "İsim"; // name
dataGridView1.Columns[0].HeaderText = "İsim"; // header text
dataGridView1.Columns[0].DataPropertyName = "ad"; // field name

dataGridView1.Columns[1].HeaderText = "Soyisim";
dataGridView1.Columns[1].Name = "Soyisim";
dataGridView1.Columns[1].DataPropertyName = "soyad";

dataGridView1.Columns[2].Name = "Telefon";
dataGridView1.Columns[2].HeaderText = "Telefon";
dataGridView1.Columns[2].DataPropertyName = "telefon";

dataGridView1.Columns[3].Name = "Kayıt Tarihi";
dataGridView1.Columns[3].HeaderText = "Kayıt Tarihi";
dataGridView1.Columns[3].DataPropertyName = "kayit";

dataGridView1.Columns[4].Name = "Bitiş Tarihi";
dataGridView1.Columns[4].HeaderText = "Bitiş Tarihi";
dataGridView1.Columns[4].DataPropertyName = "bitis";

dataGridView1.DataSource = dbDataSet1;
dataGridView1.DataMember = "uyeler";
Athafoud
  • 2,898
  • 3
  • 40
  • 58
Ahmet Uğur
  • 462
  • 6
  • 12
  • 3
    dataGridView1.AutoGenerateColumns = false; prevents all columns from being shown on databind. Thank you! – Observer Sep 19 '16 at 15:52
  • your answer here is the most useful one since they dont put the `ColumnCount`. Future programmers will encounter this type of error such as Null reference exception when setting either Column.[0].Name/HeaderText/DataPropertyName – Shulz Feb 26 '20 at 20:33
  • Don't understand why AutoGenerateColumns property is not on the Properties window. – Sinan ILYAS Dec 06 '22 at 08:22
6

You can do something like this.

To display only particluar columns in a DataGridView first you take the data in a DataTable like this.

String query="Your query to dispplay columns from the database";
SqlCommand cmd=new SqlCommand(query,con); //con is your Connection String
con.Open();
DataTable dt=new DataTable();
SqlDataAdapter da=new SqlDataAdapter(cmd);
da.Fill(dt); //Now this DataTable is having all the columns lets say
/* Now take another temporary DataTable to display only particular columns*/
DataTable tempDT=new DataTable();
tempDT=dt.DefaultView.ToTable(true,"Your column name","your column name");
//Now bind this to DataGridView
grid.DataSource=tempDT;
con.Close();

I know this is a quite long process.Those who go for the performance might not like this. :P

But i think it works fine.

Sujith H S
  • 477
  • 8
  • 18
3
     SqlCommand cmd6 = new SqlCommand("SELECT * FROM tblinv WHERE invno='" + textBox5.Text + "'",cn);

        SqlDataReader sqlReader6 = cmd6.ExecuteReader();

        if (sqlReader6.HasRows)

        {
            DataTable dt = new DataTable();

            DataTable dt1 = new DataTable();

            dt.Load(sqlReader6);

            dt1 = dt.DefaultView.ToTable(true, "ChallanNo", "ProductName", "UoM", "Price", "Qty","Subtotal");

            dataGridView2.DataSource = dt1;
        }
  • 3
    it would be nice that you expain this solution to the person asking, so he could not only copy\paste it, but also benefit from it in other way, by learning – 4c74356b41 Nov 12 '16 at 12:25
0

Create new Model For List Like ....

             var today =DateTime.Today;
            DailyEnteryList = _context.Tbl_AllEntriries.Where(x => 
                x.CreatedOn.Value.Date == today.Date).
                Select(x=> new EntirysModel 
                {
                    EntiryNo=Convert.ToInt64(x.EntiryNo),
                    CustomerName=x.CustomerName,
                    Date=Convert.ToDateTime(x.Date),
                    ModelName=x.ModelName,
                }).ToList();

My EntirysModel

 public class EntirysModel
{
    public long EntiryNo { get; set; }
    public string CustomerName { get; set; }
    public DateTime Date { get; set; }
    public string ModelName { get; set; }
}

Then Add Columns in your grid

[1]

: https://i.stack.imgur.com/3dZAl.png

this is work best in my cash THanks !!!