我有以下SQL
SELECT Equipment.* ,cast(EquipmentId as varchar(100)) + ' ' + EquipmentName as Name
FROM Equipment
WHERE Equipment.EquipmentCategoryID = @EquipmentCategoryID
AND (Equipment.EquipmentSubCategoryID = @EquipmentSubCategoryID
OR (@EquipmentSubCategoryID is null OR @EquipmentSubCategoryID = '' ))
在SQL Server中,它的行为符合预期。当@EquipmentCategoryId
为12且@EquipmentSubCategoryID
为null时,它返回我想要的所有值。当@EquipmentCategoryId
为12而@EquipmentSubCategoryID
是另一个数字时,它会返回较小的行数,这也是我想要的。
在GridView的ASP.NET下拉列表中,它的行为不符合预期,返回dropdownlist
中每个GridView
的所有行,即使@EquipmentSubCategoryID
具有不同的数字,在SQL Server中工作。 dropdownlist
就是这样绑定的。
protected void ServiceFormsGV_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
HiddenField EquipmentCategoryIDHF = (HiddenField) e.Row.FindControl("EquipmentCategoryIDHF");
HiddenField EquipmentSubCategoryIDHF = (HiddenField) e.Row.FindControl("EquipmentSubCategoryIDHF");
DropDownList EquipmentDD = (DropDownList) e.Row.FindControl("EquipmentDD");
EquipmentDS.SelectParameters["EquipmentCategoryID"].DefaultValue = EquipmentCategoryIDHF.Value;
EquipmentDS.SelectParameters["EquipmentSubCategoryID"].DefaultValue = EquipmentSubCategoryIDHF.Value;
EquipmentDD.Items.Clear();
EquipmentDD.Items.Add(new ListItem());
EquipmentDD.DataBind();
}
}
我可以确认每次通过HiddenFields显示正确值的方法,但ServiceFormsGV
GridView
包含每个DropDownList
中的所有行。
GridView如下。
<asp:GridView ID="ServiceFormsGV" runat="server" AutoGenerateColumns="False" DataKeyNames="ServiceFormID,EquipmentCategoryID1" DataSourceID="ServiceFormsDS" OnDataBound="ServiceFormsGV_DataBound" OnRowDataBound="ServiceFormsGV_RowDataBound">
<Columns>
<asp:TemplateField HeaderText="Machine Id">
<ItemTemplate>
<asp:DropDownList ID="EquipmentDD" runat="server" AutoPostBack="True" DataSourceID="EquipmentDS" DataTextField="EquipmentName" AppendDataBoundItems="True"
DataValueField="EquipmentID" OnSelectedIndexChanged="EquipmentDD_SelectedIndexChanged">
在SQLDataSource中我有
CancelSelectOnNullParameter="False"
这是必要的。
我在配置数据源中测试了查询,它的行为符合预期。
答案 0 :(得分:1)
这种行为背后的原因是SqlDataSource
被用作GridView内部下拉列表的DataSource。
在DataGridView_RowDataBound事件期间,您将更改SqlDataSource
参数的默认值并重新绑定行的下拉列表。当您更改参数的默认值时,SqlDataSource
执行查询的结果会影响所有下拉列表,因此最终所有下拉列表都将具有由gridview的最后一行传递的值生成的查询结果。这就是为什么你在网格的所有下拉列表中得到相同的结果。
您需要每次都运行查询并检索结果并将其单独绑定到每个下拉列表,而不使用其中的任何公共数据源。
虽然您找到的解决方案没有问题,但它需要打开SQL连接并针对DataGridView的每一行对数据库运行查询。
我建议的方法是从Equipment表中检索所有行,并将它们存储为页面级别的实体集合,然后在rowDataBound事件期间过滤当前Category和SubCategory的集合,并将过滤后的结果绑定到下拉列表。
以下是实体设备
public class Equipment
{
public int Id { get; set; }
public string Name { get; set; }
public string CategoryId { get; set; }
public string SubCategoryId { get; set; }
public string FullName
{
get
{
return string.Format("{0} {1}", Id, Name);
}
}
}
在Page_load中,通过从数据库中的Equipment表中检索所有行来填充设备集合。
public partial class _Default : Page
{
private List<Equipment> equipments;
protected void Page_Load(object sender, EventArgs e)
{
equipments = new List<Equipment>();
var commandText = "SELECT EquipmentId, EquipmentName, CategoryId, SubCategoryId FROM Equipment";
using (var connection = new SqlConnection("Data Source=.;Initial Catalog=LocalDevDb;User id=sa;Password=Password1"))
{
using (var command = new SqlCommand(commandText, connection))
{
command.CommandType = System.Data.CommandType.Text;
connection.Open();
using (var reader = command.ExecuteReader(System.Data.CommandBehavior.CloseConnection))
{
while (reader.Read())
{
var equipment = new Equipment
{
Id = reader.GetInt32(0),
Name = reader.GetString(1),
CategoryId = reader.GetString(2),
SubCategoryId = reader.GetString(3),
};
equipments.Add(equipment);
}
}
}
}
}
}
根据CategoryId和SubCategoryId过滤此集合,并将结果绑定到DropDown。
protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
DropDownList EquipmentDD = (DropDownList)e.Row.FindControl("dropDownList");
HiddenField EquipmentCategoryIDHF = (HiddenField) e.Row.FindControl("EquipmentCategoryIDHF");
HiddenField EquipmentSubCategoryIDHF = (HiddenField) e.Row.FindControl("EquipmentSubCategoryIDHF");
var categoryId = EquipmentCategoryIDHF.Value;
var subCategoryId = EquipmentSubCategoryIDHF.Value;
Func<Equipment, bool> criteria;
if(!string.IsNullOrEmpty(subCategoryId))
{
criteria = criteria = equip => equip.CategoryId == categoryId && equip.SubCategoryId == subCategoryId;
}
else
{
criteria = equip => equip.CategoryId == categoryId;
}
var list = equipments.Where(criteria).ToList();
EquipmentDD.DataSource = list;
EquipmentDD.DataBind();
EquipmentDD.Items.Insert(0, new ListItem());
}
}
在我的示例中,使用String数据类型创建了CategoryId和SubCategoryId列。如果它们与表的列不同,则需要将它们更改为适当的。
这可以帮助您解决问题。
答案 1 :(得分:0)
我找到的解决方案是SqlDataSource
需要在行的GridView
中。因此,与DropDownList
中的ItemTemplate
位于同一位置。那就是为RowDataBound方法中的每一行更新SqlDataSource。
protected void ServiceFormsGV_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
HiddenField EquipmentCategoryIDHF = (HiddenField) e.Row.FindControl("EquipmentCategoryIDHF");
HiddenField EquipmentSubCategoryIDHF = (HiddenField) e.Row.FindControl("EquipmentSubCategoryIDHF");
SqlDataSource EquipmentDS = (SqlDataSource)e.Row.FindControl("EquipmentDS");
DropDownList EquipmentDD = (DropDownList) e.Row.FindControl("EquipmentDD");
EquipmentDS.SelectParameters["EquipmentCategoryID"].DefaultValue = EquipmentCategoryIDHF.Value;
EquipmentDS.SelectParameters["EquipmentSubCategoryID"].DefaultValue = EquipmentSubCategoryIDHF.Value;
EquipmentDD.Items.Clear();
EquipmentDD.Items.Add(new ListItem());
EquipmentDD.DataBind();
}
}
<asp:GridView ID="ServiceFormsGV" runat="server" AutoGenerateColumns="False" DataKeyNames="ServiceFormID,EquipmentCategoryID1" DataSourceID="ServiceFormsDS" OnDataBound="ServiceFormsGV_DataBound" OnRowDataBound="ServiceFormsGV_RowDataBound">
<Columns>
<asp:TemplateField HeaderText="Machine Id">
<ItemTemplate>
<asp:DropDownList ID="EquipmentDD" runat="server" AutoPostBack="True" DataSourceID="EquipmentDS"
DataTextField="EquipmentName" AppendDataBoundItems="True"
DataValueField="EquipmentID" OnSelectedIndexChanged="EquipmentDD_SelectedIndexChanged">
<asp:SqlDataSource ID="EquipmentDS" runat="server" CancelSelectOnNullParameter="False" ConnectionString="<%$ ConnectionStrings:XXXXXXXXXXXXXXXXX %>" SelectCommand="SELECT Equipment.* ,cast(EquipmentId as varchar(100)) + ' ' + EquipmentName as Name FROM Equipment WHERE Equipment.EquipmentCategoryID = @EquipmentCategoryID AND (Equipment.EquipmentSubCategoryID = @EquipmentSubCategoryID OR (@EquipmentSubCategoryID is null OR @EquipmentSubCategoryID = '' ) )">
<SelectParameters>
<asp:Parameter Name="EquipmentCategoryID" />
<asp:Parameter Name="EquipmentSubCategoryID" />
</SelectParameters>
</asp:SqlDataSource>
</ItemTemplate>
这很有道理并且有效。