Binding objects DataGridView C#

♀尐吖头ヾ 提交于 2019-12-29 07:21:09

问题


i have a DataGridView and a list of objects that i would like to show.

The Objects are these:

public class Entity
{
    public int ID { get; set; }
}    

public class Travel: Entity
{
    public Service Service { get; set; }
    public City Source { get; set; }
    public City Destiny { get; set; }
    public decimal Price { get; set; }
}

public class Service: Entity
{
    public string Name { get; set; }
}

public class City: Entity
{
    public string Name { get; set; } // Max 50 chars
}

In my form i bind the list of of Travel Objects like this:

List<Travel> travels = logic.GetAllTravels();
DgvRecorridos.DataSource = travels;

And i get the following:

I would like to get the Name of the Service, Source City and Destiny City instead.

Thanks in advance.


回答1:


List<Travel> travels = logic.GetAllTravels();
var _bind = from a in travels
            select new
            {
                Servicename = a.Service.Name,
                SourceName = a.Source.Name,
                DestinyName = a.Destiny.Name,
                Price = a.Price
            };
DgvRecorridos.DataSource = _bind;

or

List<Travel> travels = logic.GetAllTravels();
var _bind = travels.Select(a => new 
            { 
                Servicename = a.Service.Name,
                SourceName = a.Source.Name,
                DestinyName = a.Destiny.Name,
                Price = a.Price
            });
DgvRecorridos.DataSource = _bind;



回答2:


Instead of doing the following codes below:

List<Travel> travels = logic.GetAllTravels();  
DgvRecorridos.DataSource = travels;  

Do this:

List<Travel> travels = logic.GetAllTravels();  
BindingSource bs = new BindingSource();  
bs.DataSource = travels;  
DgvRecorridos.AutoGenerateColumn = false;  
DgvRecorridos.DataSource = bs;  

Then, add the columns manually:

DataGridViewColumn col1 = new DataGridViewTextBoxColumn();  
col1.DataPropertyName = "Service.Name";  
col1.HeaderText = "Service Name";  
dataGridView1.Columns.Add(col1);  

DataGridViewColumn col2 = new DataGridViewTextBoxColumn();  
col2.DataPropertyName = "City.Name";  
col2.HeaderText = "City Name";  
dataGridView1.Columns.Add(col2);  

DataGridViewColumn col3 = new DataGridViewTextBoxColumn();  
col3.DataPropertyName = "City.Name";  
col3.HeaderText = "Destiny Name";  
dataGridView1.Columns.Add(col3);  

DataGridViewColumn col4 = new DataGridViewTextBoxColumn();  
col4.DataPropertyName = "Price";  
col4.HeaderText = "Price";  
dataGridView1.Columns.Add(col4);  

Then, add a cell formatting event handler for the DataGridView:

private void dataGridView1_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)  
{  
    if (dataGridView1.Rows[e.RowIndex].DataBoundItem != null &&   
        dataGridView1.Columns[e.ColumnIndex].DataPropertyName.Contains("."))  
    {  
        e.Value = BindProperty(dataGridView1.Rows[e.RowIndex].DataBoundItem,
            dataGridView1.Columns[e.ColumnIndex].DataPropertyName);  
    }  
}  

private string BindProperty(object property, string propertyName)  
{  
    string retValue = "";  

    if (propertyName.Contains("."))  
    {  
        PropertyInfo[] arrayProperties;  
        string leftPropertyName;  

        leftPropertyName = propertyName.Substring(0, propertyName.IndexOf("."));  
        arrayProperties = property.GetType().GetProperties();  

        foreach (PropertyInfo propertyInfo in arrayProperties)  
        {  
            if (propertyInfo.Name == leftPropertyName)  
            {  
                retValue = BindProperty(propertyInfo.GetValue(property, null),   
                propertyName.Substring(propertyName.IndexOf(".") + 1));  
                break;  
            }  
        }  
    }  
    else  
    {  
        Type propertyType;  
        PropertyInfo propertyInfo;  

        propertyType = property.GetType();  
        propertyInfo = propertyType.GetProperty(propertyName);  
        retValue = propertyInfo.GetValue(property, null).ToString();  
    }  

    return retValue;  
}  

For a complete guide of the cell formatting, browse here on Antonio Bello's blog, it's where I got the idea. ^_^ I also asked here on SO the same question two days ago, and got the same answers like you, and I know that it's not what you want to do too. Hope it helps you.




回答3:


Your design is so strange. I have another approach is to override ToString() method of your classes (Service and City) like this:

public class Service: Entity
{
  public string Name { get; set; }
  public override string ToString(){
     return Name;
  }
}

public class City: Entity
{
  public string Name { get; set; } // Max 50 chars
  public override string ToString(){
     return Name;
  }
}

And that works OK. Again, your design is a little strange ^_^




回答4:


All that code in the CellFormatting and BindProperty methods seems excessive. I mean, something's got to basically do that, but I think it's already been done. I implement INotifyPropertyChanged in the object I want to bind to a grid row, and I put those objects into a BindingList. The BindingList is directly used as the datasource for the grid.

This approach means a little more typing in the basic entity class you're mapping to the grid row but I think it saves a lot more elsewhere. To implement INotifyPropertyChanged in your class:

public class Entity: INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
        public Entity()
        {
            Selected = false;
        }

        private bool _selected;
        public bool Selected
        {
            get
            {
                return _selected;
            }
            set
            {
                if (_selected != value)
                {
                    _selected = value;
                    OnPropertyChanged(nameof(Selected));
                }
            }
        }

        protected virtual void OnPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }

Then put a column in your grid and give it a DataPropertyName of "Selected" to match the name of the property in Entity that should appear in that column. Obviously add whatever properties you want to your grid, matching the properties of the entity. The key is to be sure to implement the property setter with the call to PropertyChanged.

This gets you two-way binding between the grid and your list of objects.

My personal opinion: even this is way too much code. I find myself constantly writing these kinds of things that do the obvious: take a property by name and map it to something else that knows that name (like the grid column in this example). It's just beyond my comprehension why these things don't just automatically hook up. A list and grid should have enough sense to figure this basic arrangement on their own. zero lines of code. Ok, one line of code. Grid.Datasource = List. So this is how I do it. I'd love to know a less lines of code way to do this.



来源:https://stackoverflow.com/questions/16869568/binding-objects-datagridview-c-sharp

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!