C # .net ListView - Retrieves other information from different tables

Im using C # .net.

I have been looking around the internet and cannot find anything to help me.

I have a list of contractors, daily hours, daily slots (three different tables).

  • First line - contains contractor names.
  • The second line - unlimited - contains slots.

for example

alt text

I thought I could use a ListView, but I am having trouble working out where I would place the code.

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

      

Uses Linq model so can connect to client time interval

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

            contractorListView.DataSource = contractorDataSource;

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

      

Anyone have any ideas / example?

Thanks in advance for your help.

Clare

+2


source to share


3 answers


This is how I usually solve problems like this:

  • manually pull our data you want to show (by calling repository methods without using ObjectDataSource to do this). For efficiency, it often makes sense to do one big query that returns denormalized records, each containing all the columns you need (for example SELECT TimeSlot, CustomerName, ContractorName FROM (joins go here) ...

    )

  • create a custom collection class that puts this data in a format that can be easily associated with data. "Simple data binding" usually means that the data is organized in the order you intend to display. You might also need to do hacks, such as making all your rows the same length to bind data to the same number of table cells per row.

  • in your data binding expressions, cast the Container.DataItem to whatever type you need to pull properties of that type. This also has the added benefit of crashing when building a compilation with misspelled data binding errors, rather than waiting for the runtime to find errors.

  • for nesting, set the DataSource property of a nested template control (such as a repeater) to the property of the parent container. DataTemet

  • for header lines, here's the trick: put the header code directly in the ItemTemplate and use Container.ItemIndex == 0 to know when to show the header line or not. Since only Repeater (not ListView) supports the ItemIndex property, I tend to use Repeater instead of ListView for most read-only data binding tasks. This is why I changed my ListView in my example code below to use Repeater. You can do the same by adding an Index or RowNumber property to your custom data binding classes described above, but this is more complex.

The general idea is that you want to make the most of your intelligence from your data-binding code and from the actual methods of your page's code (or code) that is easier to write and debug.



Here's a working sample (with your classes and repository classes) to give you an idea of ​​what I'm talking about. You must be able to adapt this to your situation.

<%@ 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 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>

      

By the way, if you are building a completely new application and have some time to learn, I definitely suggest looking at ASP.NET MVC, which has a non-trivial learning curve, but makes a lot easier ... in partiuclar this kind of complex data rendering.

+4


source


Is this not just a cross-language situation? Take a look at my solution here:



Cross tab - save different dates (Meeting1, Meeting2, Meeting 3, etc.) in the same column

0


source


Why not create one query that fetches all of your information?

You can JOIN multiple tables.

If the connection becomes very complex, you can create a VIEW that creates a new virtual table to consolidate your information.

0


source







All Articles