4

我有一个 DataGridView 和一个我想显示的对象列表。

对象是这些:

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
}

在我的表单中,我绑定了旅行对象列表,如下所示:

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

我得到以下信息:

在此处输入图像描述

我想获取服务名称、源城市和命运城市。

提前致谢。

4

4 回答 4

5

而不是执行以下代码:

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

做这个:

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

然后,手动添加列:

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);  

然后,为 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;  
}  

有关单元格格式的完整指南,请在Antonio Bello 的博客上浏览此处,这就是我想到的地方。^_^ 两天前我也在这里问过同样的问题,得到了和你一样的答案,我知道这也不是你想做的。希望它可以帮助你。

于 2014-10-23T08:30:29.067 回答
4
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;
于 2013-06-01T05:59:46.587 回答
0

你的设计好奇怪。我有另一种方法是覆盖ToString()你的类(服务和城市)的方法,如下所示:

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;
  }
}

这工作正常。再说一次,你的设计有点奇怪^_^

于 2013-06-03T18:02:11.593 回答
0

CellFormatting 和 BindProperty 方法中的所有代码似乎过多。我的意思是,基本上必须做一些事情,但我认为它已经完成了。我在要绑定到网格行的对象中实现 INotifyPropertyChanged,然后将这些对象放入 BindingList。BindingList 直接用作网格的数据源。

这种方法意味着在您映射到网格行的基本实体类中输入更多内容,但我认为它可以在其他地方节省更多。要在您的类中实现 INotifyPropertyChanged:

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));
            }
        }
    }

然后在您的网格中放置一列,并为其指定“已选择”的 DataPropertyName 以匹配应出现在该列中的实体中的属性名称。显然,将您想要的任何属性添加到网格中,与实体的属性相匹配。关键是确保通过调用 PropertyChanged 来实现属性设置器。

这使您可以在网格和对象列表之间进行双向绑定。

我个人的观点:即使这样也太多代码了。我发现自己一直在写这些显而易见的东西:按名称获取属性并将其映射到其他知道该名称的东西(如本例中的网格列)。我无法理解为什么这些东西不会自动连接起来。列表和网格应该有足够的意义来自行确定这种基本排列。零行代码。好的,一行代码。Grid.Datasource = 列表。所以我就是这样做的。我很想知道更少的代码行来做到这一点。

于 2017-02-02T04:11:43.057 回答