List <t>的Dictionary <t>和ASP.NET中的ListViews </t> </t>

时间:2009-02-24 21:28:20

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

序言

我问这个问题,因为尽管我已经阅读了很多ListView资源,但我仍然没有“得到”它。

背景

我有一堆Foo有一个与它们相关联的项目列表(称为 Bar),我从数据中提取它们访问/业务逻辑层作为包含Foo及其关联的Bars的词典。我想将这些项目在网页上吐出一个ListView,左侧是Foo.Name,下拉列表中右侧是List<Bar>。 (以下我美丽的ASCII艺术所示):

的ListView

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

好的,这是正在发生的事情。这是一个ListView;这些项目从数据库中提取到Dictionary<Foo, List<Bar>>。我试图从词典中获取Key Value以显示在“Item of Item”下,并且我试图得到`List&lt; T&gt; Bar'在ListView的右侧显示为DropDownList。

类图

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

所以回顾一下,我想把Dictionary.Key“Name”放在ListView的左侧,将Dictionary.Value(恰好是一个列表)放到右侧的DropdownList中。

因此,对于每个键/值对,都会有一个名称和一个下拉列表,用于存放每个键的值。

但是我遇到了问题(显然),我希望有人可以告诉我我做错了什么。

代码背后:

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

ListView代码:

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

问题:

  1. 是否可以这样使用词典?
  2. 关于我哪里出错的指示? (资源,提示等会有所帮助)
  3. 有更好的方法吗?
  4. 如果这个问题很清楚,请发表评论,以便我能弄清楚如何改进它。

2 个答案:

答案 0 :(得分:9)

您的问题出现是因为在DataBindFooList()中数据绑定ddlListOfBars没有意义,因为数据绑定不只有一个DropDownList。当您调用lv.DataBind()时,ListView会为每个Foo创建一个ItemTemplate副本,每个Foo包含一个ddlListOfBars。您需要告诉它将每个DropDownList绑定到正确的List&lt; Bar&gt;就这样。您可以通过使用数据绑定表达式设置ddlListOfBars的数据源而不是后面的代码来执行此操作:

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

请注意,您还需要使用“Key.Name”来获取Foo的name属性。您绑定的各个字典项是KeyValuePair&lt; Foo,List&lt; Bar&gt;&gt;,它具有Key属性和Value属性以访问Foo和List&lt; Bar&gt;分别

修改
如果你在ItemTemplate中进行了很多工作,那么将内容移到用户控件中会很有用。用户控件可以具有强类型属性来访问DataItem,并且具有对其子控件的强类型访问。这为您提供了ItemDataBound事件的灵活性,而没有所有的转换和FindControl()噪声。我怀疑在这种情况下我会烦恼,但它会像

那样
<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();   
}

答案 1 :(得分:4)

这是你想要的东西:

   <asp:ListView ID="lvFooList" runat="server">
    <LayoutTemplate>
      <asp:PlaceHolder runat="server" ID="itemPlaceholder"></asp:PlaceHolder>
    </LayoutTemplate>
      <ItemSeparatorTemplate>
         <hr />
      </ItemSeparatorTemplate>
    <ItemTemplate>
      <asp:Label ID="lbName" runat="server"/>
      <asp:DropDownList ID="ddlListOfBars" runat="server"></asp:DropDownList>
    </ItemTemplate>
   </asp:ListView>

然后我写了一个非常快速的讨厌的测试

    public class Foo
    {
        public string Name;
    }

    public class Bar
    {
        public string ItemName { get; set; }
        public string ItemValue { get; set; }
    }

    protected void Page_Load(object sender, EventArgs e)
    {

        var fooKey1 = new Foo() {Name = "foo1"};
        var barList1 = new List<Bar>()
               {
                   new Bar() {ItemName = "bar1", ItemValue = "barV1"},
                   new Bar() {ItemName = "bar2", ItemValue = "barV2"}
               };
        var fooKey2 = new Foo() {Name = "foo2"};
        var barList2 = new List<Bar>()
               {
                   new Bar() {ItemName = "bar3", ItemValue = "barV3"},
                   new Bar() {ItemName = "bar4", ItemValue = "barV4"}
               };

        var dicFooBar = new Dictionary<Foo, List<Bar>>() {{fooKey1, barList1}, {fooKey2, barList2}};

        lvFooList.ItemDataBound += lvFooList_ItemDataBound;
        lvFooList.DataSource = dicFooBar;
        lvFooList.DataBind();
    }

    void lvFooList_ItemDataBound(object sender, ListViewItemEventArgs e)
    {
        var dataItem = (ListViewDataItem)e.Item;
        var fooBarList = (KeyValuePair<Foo, List<Bar>>)dataItem.DataItem;

        ((Label) dataItem.FindControl("lbName")).Text = fooBarList.Key.Name;

        var ddlListOfBars = (DropDownList) dataItem.FindControl("ddlListOfBars");
        ddlListOfBars.DataTextField = "ItemName";
        ddlListOfBars.DataValueField = "ItemValue";
        ddlListOfBars.DataSource = fooBarList.Value;
        ddlListOfBars.DataBind();
    }

似乎做你想做的事,但我的代码只是快速测试代码,所以要注意。它确实按预期呈现。