【问题标题】:Binding objects DataGridView C#绑定对象 DataGridView C#
【发布时间】:2013-05-28 00:00:05
【问题描述】:

我有一个 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;

我得到以下信息:

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

提前致谢。

【问题讨论】:

    标签: c# binding


    【解决方案1】:

    而不是执行以下代码:

    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 的 博客上的 here,这是我的灵感来源。 ^_^ 两天前我也在这里问过同样的问题,得到了和你一样的答案,我知道这也不是你想做的。希望对你有帮助。

    【讨论】:

      【解决方案2】:
      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;
      

      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;
      

      【讨论】:

      • 感谢您的回答。如何更改标题文本?
      • @ehh 你指的是数据网格的标题吗?如果是,您可以在 datagridview 的属性中更改它。
      • 好的,谢谢。我想知道它是否可以作为匿名方法的一部分来完成。而不是让 Servicename 拥有“服务名称”(或不同的语法)
      • 谢谢,正是我想要的。我不得不把 .ToList();在 Linq 查询的末尾,让它显示在 datagridview 上。
      【解决方案3】:

      你的设计好奇怪。我有另一种方法是覆盖你的类(服务和城市)的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;
        }
      }
      

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

      【讨论】:

        【解决方案4】:

        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 = 列表。所以我就是这样做的。我很想知道更少的代码行来做到这一点。

        【讨论】:

          猜你喜欢
          • 2011-08-13
          • 1970-01-01
          • 1970-01-01
          • 2014-11-29
          • 1970-01-01
          • 1970-01-01
          • 2014-08-18
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多