Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
93 views
in Technique[技术] by (71.8m points)

c# - Dictionary<T> of List<T> and ListViews in ASP.NET

Preamble

I'm asking this question because even though I've read through a lot of ListView resources, I'm still not 'getting' it.

Background

I have a bunch of Foo's that have a list of items associated with them (known as Bar), and I'm pulling them from the Data Access/Business Logic layer as Dictionary that holds a Foo and its associated Bars. I'd like to spit these items out in on the Webpage into a ListView that holds the Foo.Name on the left, and the List<Bar> on the right in a dropdownlist. (Shown with my beautiful ASCII art below):

ListView

------------------------------------------------------------------
|           Name Of Item          |  DropDownList (of List<T>)   |
|---------------------------------|  _____________________       |
|                foo1             |  |     bar1      | v |       |
|                                 |  |_______________|___|       |  
------------------------------------------------------------------
|                                 |  DropDownList (of List<T>)   |
|                                 |  _____________________       |
|                foo2             |  |     bar2      | v |       |
|                                 |  |_______________|___|       |
------------------------------------------------------------------

Alright, here's what's going on. This is a ListView; The items are pulled from a database into a Dictionary<Foo, List<Bar>>. I'm trying to get the Key Value from the dictionary to show up under 'Name of Item', and am trying to get the `List<T> Bar' to show up as a DropDownList on the right side of the ListView.

Class Diagrams

-----------------          -----------------
|   Foo         |          |  Bar          |
-----------------          -----------------
|  Id           |          |  ItemName     |
|  Name         |          |  ItemValue    |
|  BarID        |          |               |
-----------------          -----------------

So to recap, I want to place the Dictionary.Key "Name" into the left side of the ListView, and the Dictionary.Value (which happens to be a list) into a DropdownList on the right side.

So that, for every Key/Value pair, there'd be a Name and a dropdown list that would house each Key's Value.

But I'm running into problems (obviously), and am hoping someone can tell me what I'm doing wrong.

Code Behind:

  protected Dictionary<Foo, List<Bar>> FooDictionary
        {
            get; 
            set; 
        }

protected void DataBindFooList(List<int> SelectedFoos)
        {
            System.Web.UI.WebControls.ListView lv = lvFooList;

try
            {
                Dictionary<Foo, List<Bar>> fooDictionary =
                    new Dictionary<Foo, List<Bar>>();

                foreach (int Foo in SelectedFoos)
                {
                 // Build List of Foos to add as Dictionary.Keys
                 fooDictionary.Add(fooScalar, Bar)                     
                }
                FooDictionary = fooDictionary;
                lv.DataSource = FooDictionary;
                lv.DataBind();
                ddlListOfBars.DataSource = FooDictionary;
                ddlListOfBars.DataValueField = "ItemValue";
                ddlListOfBars.DataTextField = "ItemName";
                ddlListOfBars.DataBind();
            }
            catch (Exception ex)
            {
                SetMessage(divFooMsg, "Unable to retrieve Foos: " + 
                ex.Message, true, true);
            }

The ListView Code:

<asp:ListView ID="lvFooList" runat="server">
   <LayoutTemplate>
      <asp:PlaceHolder runat="server" ID="itemPlaceholder"></asp:PlaceHolder>
   </LayoutTemplate>
      <ItemSeparatorTemplate>
         <hr />
      </ItemSeparatorTemplate>
   <ItemTemplate>
      <%#Eval("Name") %>
      <asp:DropDownList ID="ddlListOfBars" runat="server"></asp:DropDownList>
    </ItemTemplate>
   </asp:ListView>

The Question(s):

  1. Is it possible to use a Dictionary in this way?
  2. Any pointers on where I'm going wrong? (Resources, hints, etc. would help)
  3. Is there a better way to do this?
  4. If this question is clear as mud, please comment so I can figure out how to improve it.
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Your problem arises because it doesn't make sense to databind ddlListOfBars in DataBindFooList(), because there isn't just one DropDownList to databind. When you call lv.DataBind(), the ListView creates a copy of your ItemTemplate for each Foo, each containing a ddlListOfBars. You need to tell it to bind each DropDownList to the right List<Bar> as it goes. You can do this by setting the datasource of ddlListOfBars with data binding expressions rather than in the code behind:

<ItemTemplate>
  <%#Eval("Key.Name") %>
  <asp:DropDownList
        ID="ddlListOfBars"
        runat="server"
        DataSource='<%#Eval("Value")%>'
        DataValueField="ItemValue"
        DataTextField="ItemName" />
</ItemTemplate>

Note that you also need to use "Key.Name" to get to the name property of your Foo. The individual dictionary items that you're binding to are KeyValuePair<Foo,List<Bar>>, which has a Key property and a Value property to access the Foo and List<Bar> respectively.

Edit
If you've got a lot going on in your ItemTemplate then it can be useful to move the contents out into a user control. The user control can have a strongly-typed property to access the DataItem, and has strongly-typed access to its child controls. This gets you the flexibility of the ItemDataBound event without all the the casting and FindControl() noise. I doubt I'd bother in this case, but it would go something like

<asp:ListView ID="lvFooList" runat="server">
<LayoutTemplate>
  <asp:PlaceHolder runat="server" ID="itemPlaceholder"></asp:PlaceHolder>
</LayoutTemplate>
  <ItemSeparatorTemplate>
     <hr />
  </ItemSeparatorTemplate>
<ItemTemplate>
  <uc:ListViewContents DataItem='<%# Container.DataItem %>' />
</ItemTemplate>

ListViewContents.ascx...

<asp:Label ID="lbName" runat="server"/>
<asp:DropDownList ID="ddlListOfBars" runat="server"></asp:DropDownList>

ListViewContents.ascx.cs...

public KeyValuePair<Foo,List<Bar>> DataItem
{
    get; set;
}

protected override void OnDataBinding(EventArgs e)
{
    base.OnDataBinding(e);

    lbName.Text = DataItem.Key.Name;

    ddlListOfBars.DataTextField = "ItemName";
    ddlListOfBars.DataValueField = "ItemValue";
    ddlListOfBars.DataSource = DataItem.Value;
    ddlListOfBars.DataBind();   
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...