c#.net ListView - 从不同的表中提取不同的信息

时间:2009-10-12 14:39:45

标签: c# .net asp.net data-binding listview

我正在使用c#.net。

我一直在寻找网络,找不到任何可以帮助我的东西。

我有一份承包商名单,每日营业时间,每日广告位(三张不同的牌桌)。

  • 第一行 - 包含承包商 名。
  • 第二行 - 无限制 - 包含 槽。

例如

alt text

我以为我可以使用ListView但是我无法解决我放置代码的问题。

    <asp:ListView ID="contractorListView" runat="server">
    <LayoutTemplate>
  <table runat="server">
   <tr>
    <td>Times</td>  
    // Contractors names pulled from another
    <th><asp:PlaceHolder id="itemPlaceholder" runat="server" /></th>
      </tr>
    </LayoutTemplate>
  <ItemTemplate>
   <tr>
    <td>Times pulled from one database table</td>
    <td align="left" style="width: 200px;">
     // Customers name - attached to correct time
     <asp:Label runat="server" Text='<%#Eval("person_name")%>' />
    </td> 
   </tr>
     </ItemTemplate>
    </asp:ListView>

使用Linq模型,以便连接到客户的开槽时间'

            ObjectDataSource contractorDataSource = new ObjectDataSource();
            contractorDataSource.SelectMethod = "GetContractorByDateCategory";
            contractorDataSource.TypeName = "contractBook.classes.contractorRepository";

            contractorListView.DataSource = contractorDataSource;

            contractorDataSource.DataBind();
            contractorListView.DataBind();

有人有任何想法/例子吗?

提前感谢您的帮助。

克莱尔

3 个答案:

答案 0 :(得分:4)

以下是我倾向于解决这样的问题:

  • 手动拉出您想要显示的数据(调用存储库方法,而不是使用ObjectDataSource来执行此操作)。为了提高效率,通常会生成一个返回非规范化记录的大查询,每个记录都包含您需要的所有列(例如SELECT TimeSlot, CustomerName, ContractorName FROM (joins go here) ...

  • 创建一个自定义集合类,将该数据放入易于数据绑定的格式中。 “易于数据绑定”通常意味着数据的组织顺序与您要显示的顺序相同。你也可能需要做一些黑客攻击,例如,使所有行的长度相同,以便每行数据表相同数量的表格单元格。

  • 在数据绑定表达式中,将Container.DataItem强制转换为您需要的任何类型,以便提取该类型的属性。这还有一个额外的好处,就是在编译时使用拼写错误的数据绑定表达式失败,而不是等到运行时才发现错误。

  • 用于嵌套,将嵌套模板控件(例如转发器)的DataSource属性设置为父Container.DataItem的属性

  • 对于标题行,这里有一个技巧:将标题代码直接放入ItemTemplate,并使用Container.ItemIndex == 0来知道何时显示标题行。由于只有Repeater(但不是ListView)支持ItemIndex属性,因此我倾向于使用Repeater而不是ListView来执行大多数只读数据绑定任务。这就是我在下面的代码示例中更改ListView以使用Repeater的原因。通过向上面描述的自定义数据绑定类添加Index或RowNumber属性可以完成同样的事情,但这更难。

一般的想法是,你想尽可能多地将你的数据绑定代码 out 推送到你的页面(或代码隐藏)代码中的实际方法中,这些代码更易于编写和调试。

这是一个工作示例(你的类和存储库类被模拟),让你知道我在说什么。你应该能够适应你的情况。

<%@ Page Language="C#"%>
<%@ Import Namespace="System.Collections.Generic" %>
<%@ Import Namespace="System.Linq" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<script runat="server">
    public class Person   // replace with your class
    {
        public string person_name {get; set;}
    }
    public class Repository  // replace with your class
    {
        public static IEnumerable<Record> GetCustomerByDateCategory()
        {
            // fake some data
            return new Record[] 
            {
                new Record { Time = new DateTime(2000, 1, 1, 8, 0, 0), Contractor = new Person {person_name = "Joe the Plumber"},  Customer = new Person {person_name = "Joe Smith"} },
                new Record { Time = new DateTime(2000, 1, 1, 8, 30, 0), Contractor = new Person {person_name = "Bob Vila"}, Customer = new Person {person_name = "Frank Johnson"} },
                new Record { Time = new DateTime(2000, 1, 1, 8, 30, 0), Contractor = new Person {person_name = "Mr. Clean"}, Customer = new Person  {person_name = "Elliott P. Ness"} },
            };
        }
        public class Record    // replace this class with your record's class
        {
            public DateTime Time {get; set;}
            public Person Contractor { get; set; }
            public Person Customer { get; set; }
        }
    }

    // key = time, value = ordered (by contractor) list of customers in that time slot
    public class CustomersByTime : SortedDictionary<DateTime, List<Person>>
    {
        public List<Person> Contractors { get; set; }

        public CustomersByTime (IEnumerable <Repository.Record> records)
        {
            Contractors = new List<Person>();
            foreach (Repository.Record record in records)
            {
                int contractorIndex = Contractors.FindIndex(p => p.person_name == record.Contractor.person_name);
                if (contractorIndex == -1)
                {
                    Contractors.Add(record.Contractor);
                    contractorIndex = Contractors.Count - 1;
                }
                List<Person> customerList;
                if (!this.TryGetValue(record.Time, out customerList))
                {
                    customerList = new List<Person>();
                    this.Add(record.Time, customerList);
                }
                while (customerList.Count < contractorIndex)
                    customerList.Add (null);    // fill in blanks if needed
                customerList.Add (record.Customer);    // fill in blanks if needed
            }
            MakeSameLength();
        }
        // extend each list to match the longest one. makes databinding easier.
        public void MakeSameLength()
        {
            int max = 0;
            foreach (var value in this.Values)
            {
                if (value.Count > max)
                    max = value.Count;
            }
            foreach (var value in this.Values)
            {
                while (value.Count < max)
                    value.Add(null);
            }
        }
    }

    protected void Page_Load(object sender, EventArgs e)
    {
        CustomersByTime Customers = new CustomersByTime(Repository.GetCustomerByDateCategory());
        CustomerListView.DataSource = Customers;
        CustomerListView.DataBind();
    }
</script> 
<html>
<head>
<style type="text/css">
    td, th, table { border:solid 1px black; border-collapse:collapse;}
</style>
</head>
<body>
  <asp:Repeater ID="CustomerListView" runat="server">
    <HeaderTemplate><table cellpadding="2" cellspacing="2"></HeaderTemplate>
    <ItemTemplate>
        <asp:Repeater runat="server" visible="<%#Container.ItemIndex==0 %>"
            DataSource="<%#((CustomersByTime)(CustomerListView.DataSource)).Contractors %>" >
          <HeaderTemplate>
            <tr>
               <th>Times</th>
           </HeaderTemplate>
          <ItemTemplate>
            <th><%#((Person)Container.DataItem).person_name %></th>
          </ItemTemplate>
          <FooterTemplate>            
            </tr>
          </FooterTemplate>
        </asp:Repeater>
      <tr>
        <td><%#((KeyValuePair<DateTime, List<Person>>)(Container.DataItem)).Key.ToShortTimeString() %></td>
        <asp:Repeater ID="Repeater1" runat="server" DataSource="<%# ((KeyValuePair<DateTime, List<Person>>)(Container.DataItem)).Value %>">
          <ItemTemplate>
            <td align="left" style="width: 200px;">
              <%#Container.DataItem == null ? "" : ((Person)(Container.DataItem)).person_name%>
            </td> 
          </ItemTemplate>
        </asp:Repeater>
      </tr>
    </ItemTemplate>
    <FooterTemplate></table></FooterTemplate>
  </asp:Repeater>
</body>
</html>
顺便说一下,如果你正在构建一个全新的应用程序并且有一些时间学习,我绝对建议你看一下ASP.NET MVC,它有一个非平凡的学习曲线,但却是很多更容易......在partiuclar中这种复杂的数据渲染。

答案 1 :(得分:0)

这不仅仅是一个交叉标签的情况吗?看看我的解决方案:

Cross Tab - Storing different dates (Meeting1, Meeting2, Meeting 3 etc) in the same column

答案 2 :(得分:0)

为什么不创建一个提取所有信息的查询?

您可以对多个表执行JOIN操作。

如果连接变得非常复杂,您可以创建一个VIEW,它会创建一个新的虚拟表来整合您的信息。