Словарь <T>списка <T>и ListViews в ASP.NET - PullRequest
19 голосов
/ 25 февраля 2009

Преамбула

Я задаю этот вопрос, потому что, хотя я прочитал много ресурсов 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>>. Я пытаюсь получить значение ключа из словаря для отображения в разделе «Имя элемента», и пытаюсь заставить «List Bar» отображаться в виде DropDownList на правой стороне ListView.

Диаграммы классов

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

Итак, подведем итоги. Я хочу поместить словарь Dictionary.Key «Имя» в левую часть 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 ]

9 голосов
/ 25 февраля 2009

Ваша проблема возникает из-за того, что не имеет смысла связывать ddlListOfBars с данными в DataBindFooList (), потому что не существует только одного DropDownList для привязки данных. Когда вы вызываете lv.DataBind (), ListView создает копию вашего ItemTemplate для каждого Foo, каждый из которых содержит ddlListOfBars. Вы должны сказать ему, чтобы он связывал каждый DropDownList с нужным списком . Вы можете сделать это, установив источник данных ddlListOfBars с выражениями привязки данных, а не в коде:

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

Обратите внимание, что вам также нужно использовать «Key.Name», чтобы получить доступ к свойству name вашего Foo. Отдельные элементы словаря, к которым вы привязываетесь, - это KeyValuePair >, который имеет свойство Key и свойство Value для доступа к Foo и List соответственно.

Редактировать
Если в 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();   
}
4 голосов
/ 25 февраля 2009

Это то, что вы хотите:

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

Кажется, ты делаешь все, что хочешь, но мой код - просто быстрый тестовый код, так что будьте осторожны. Это действительно рендеринг, как и ожидалось.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...