我问这个问题,因为尽管我已经阅读了很多ListView资源,但我仍然没有“得到”它。
我有一堆Foo
有一个与它们相关联的项目列表(称为 Bar
),我从数据中提取它们访问/业务逻辑层作为包含Foo
及其关联的Bars
的词典。我想将这些项目在网页上吐出一个ListView
,左侧是Foo.Name
,下拉列表中右侧是List<Bar>
。 (以下我美丽的ASCII艺术所示):
------------------------------------------------------------------ | 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);
}
<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>
答案 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();
}
似乎做你想做的事,但我的代码只是快速测试代码,所以要注意。它确实按预期呈现。