C# ASP.NET 中 List<T> 和 ListViews 的 Dictionary<T>
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/583689/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Dictionary<T> of List<T> and ListViews in ASP.NET
提问by George Stocker
Preamble
前言
I'm asking this question because even though I've read through a lot of ListView resources, I'm still not 'getting' it.
我问这个问题是因为即使我已经阅读了很多 ListView 资源,我仍然没有“理解”它。
Background
背景
I have a bunch of Foo
's that have a list of items associated with them (known asBar
), 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):
我有一堆Foo
's ,它们有一个与它们相关联的项目列表(称为Bar
),我将它们从数据访问/业务逻辑层中提取为包含 aFoo
及其关联的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 | | | | |_______________|___| | ------------------------------------------------------------------
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.
好的,这是怎么回事。这是一个列表视图;这些项目从数据库中提取到Dictionary<Foo, List<Bar>>
. 我试图从字典中获取键值以显示在“项目名称”下,并试图让“List<T> Bar”在 ListView 的右侧显示为 DropDownList。
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.
所以回顾一下,我想将 Dictionary.Key“Name”放入 ListView 的左侧,将 Dictionary.Value(恰好是一个列表)放入右侧的 DropdownList。
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):
问题:
- Is it possible to use a Dictionary in this way?
- Any pointers on where I'm going wrong? (Resources, hints, etc. would help)
- Is there a better way to do this?
- If this question is clear as mud, please comment so I can figure out how to improve it.
- 可以以这种方式使用字典吗?
- 关于我哪里出错的任何指示?(资源、提示等会有所帮助)
- 有一个更好的方法吗?
- 如果这个问题很清楚,请发表评论,以便我弄清楚如何改进它。
采纳答案by stevemegson
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:
出现您的问题是因为在 DataBindFooList() 中对 ddlListOfBars 进行数据绑定是没有意义的,因为要进行数据绑定的不仅仅是一个 DropDownList。当您调用 lv.DataBind() 时,ListView 会为每个 Foo 创建 ItemTemplate 的副本,每个副本都包含一个 ddlListOfBars。您需要告诉它在运行时将每个 DropDownList 绑定到正确的 List<Bar> 。您可以通过使用数据绑定表达式而不是在后面的代码中设置 ddlListOfBars 的数据源来做到这一点:
<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.
请注意,您还需要使用“Key.Name”来获取 Foo 的 name 属性。您绑定到的单个字典项是 KeyValuePair<Foo,List<Bar>>,它有一个 Key 属性和一个 Value 属性来分别访问 Foo 和 List<Bar>。
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
编辑
如果您在 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...
ListViewContents.ascx...
<asp:Label ID="lbName" runat="server"/>
<asp:DropDownList ID="ddlListOfBars" runat="server"></asp:DropDownList>
ListViewContents.ascx.cs...
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();
}
回答by Andrew Barrett
Is something like this what you want:
你想要的是这样的:
<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>
Then I wrote a very quick nasty test
然后我写了一个非常快速的讨厌的测试
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();
}
Seems to do what you want, but my code is just quick test code, so be warned. It did render as expected though.
似乎做你想做的,但我的代码只是快速测试代码,所以请注意。不过,它确实按预期呈现。