#c# #asp.net #listbox
Вопрос:
Мой список правильно выбирает значения, но он разделяет значения по списку, а не вставляет все значения в одно поле списка.
Почему происходит такое поведение?
Код За
protected void GvInBlocks_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
List<string> list = new List<string>();
//Find listBoxCourse in GvChildBlock
ListBox listBoxCourse = e.Row.FindControl("listBoxCourse") as ListBox;
getCourseLB(listBoxCourse);
//Fill control
string CourseNames = (e.Row.FindControl("lblChildBlockCourse") as Label).Text;
list.Add(CourseNames);
foreach(ListItem items in listBoxCourse.Items)
{
if(list.Contains(items.Value))
{
items.Selected = true;
}
}
}
}
Язык разметки
<asp:Panel ID="pnlInBlocks" runat="server" Style="display: none">
<asp:GridView ID="GvInBlocks" runat="server" AutoGenerateColumns="false" CssClass="list" OnRowDataBound="GvInBlocks_RowDataBound">
<Columns>
<asp:TemplateField HeaderText = "Curso">
<ItemTemplate>
<asp:Label ID="lblChildBlockCourse" runat="server" Text='<%# Eval("CourseID") %>' Visible = "false" />
<asp:ListBox ID="listBoxCourse" runat="server" SelectionMode="Multiple">
</asp:ListBox>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
</asp:Panel>
Редактировать:
Я отредактировал код и разделил значения запятой , но результаты остались прежними, это из-за RowDataBound? Если база данных возвращает 2 строки, будет ли она возвращать 2 списка? Отредактированный код:
//Find listBoxCourse in GvChildBlock
ListBox listBoxCourse = e.Row.FindControl("listBoxCourse") as ListBox;
getCourseLB(listBoxCourse);
//Fill control
string CourseNames = (e.Row.FindControl("lblChildBlockCourse") as Label).Text;
string[] arrayNames = CourseNames.Split(',');
foreach(var names in arrayNames)
{
listBoxCourse.Items.FindByValue(names).Selected = true;
}
Комментарии:
1. строковые имена курсов = (например, Строка.FindControl(«lblChildBlockCourse») в качестве метки). Текст; FindControl выглядит так, как будто он возвращает несколько элементов, которые вы преобразуете в строку, поэтому он создает строку с каждым возвращенным элементом, разделенным запятыми.
2. Вы должны разделить предметы. Посмотрите, что возвращает FindControl, и вы сможете выполнить цикл foreach для них. Не хватает времени, чтобы сделать это самому. Я, наверное, смогу посмотреть его позже, если к тому времени кто-нибудь еще не ответит.
3. как-то разделены значения/текст в этой метке?
4. Теперь , когда я проверил, значения внутри метки не разделены запятыми или около того
5. @OldDog Проверьте правку, которую я сделал в этом посте выше.
Ответ №1:
Таким образом, список курсов выглядит так, как говорят:
Physics 204, Math 220, Computing 220
Итак, затем вам нужно разделить все вышесказанное на «список» для списка.
например: //Контроль заполнения
string CourseNames = (e.Row.FindControl("lblChildBlockCourse") as Label).Text;
CourseNames = CourseNames.Repace(", ",","); ' remove blanks
List<string> slCourse = (List<string>)CourseNames.Split(',').ToList();
listBoxCourse.DataSource = slCourse;
listBoxCourse.DataBind();
Теперь ваш список заполнен значениями.
Или существует 100% отдельный список вариантов, которые должны управлять полем «Список», и вы хотите выбрать/задать только ОДНО имя курса в качестве выбранного значения в поле «Список»?
Хорошо, для какого-то ОЧЕНЬ странного дизайна нам следует настроить эту настройку:
У вас есть несколько студентов, таблица курсов, которые они проходят, и 3-я таблица-это на самом деле просто список всех курсов.
но по какой-то странной причине у нас нет таблицы курсов, и у нас есть это:
Хуже того, у нас есть «одна» колонка, в которой есть список «идентификаторов», которые принимает студент (опять же, нарушает все правила — делает ЛЮБОЕ решение очень сложным).
И что еще хуже? Желаемый результат-отобразить ВСЕ курсы для каждой строки и выделить ТОЛЬКО тот, на который зачислен студент.
Мне кажется, что в каждой строке должны отображаться ТОЛЬКО их курсы, а не все, а затем в этом списке показать выделенные.
Но, давайте покончим с этим «ОЧЕНЬ странным вопросом с другой планеты, в котором нет смысла делать это таким образом.
Итак, мы должны заполнить сетку (легко). Мы также должны указать в списке ВСЕ КУРСЫ.
Итак, давайте сначала выполним эту часть, а ЗАТЕМ поработаем над основной частью.
Итак, у нас есть эта сетка — несколько столбцов и поле со списком
<div style="width:40%;padding:35px">
<asp:GridView ID="GVStudents" runat="server" CssClass="table" AutoGenerateColumns="False"
DataKeyNames="ID" OnRowDataBound="GVStudents_RowDataBound" >
<Columns>
<asp:BoundField DataField="FirstName" HeaderText="FirstName" />
<asp:BoundField DataField="LastName" HeaderText="LastName" />
<asp:BoundField DataField="CourseIDList" HeaderText="CourseIDList" />
<asp:TemplateField HeaderText="Courses" HeaderStyle-Width="190px">
<ItemTemplate>
<asp:ListBox ID="LstCourses" runat="server" Style="Height:120px;width:170px"
DataValueField ="ID"
DataTextField ="Course">
</asp:ListBox>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
</div>
Хорошо, теперь код, чтобы заполнить это:
public partial class StudentListBox1 : System.Web.UI.Page
{
DataTable rstCourses = new DataTable();
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
LoadGrid();
}
void LoadGrid()
{
rstCourses = MyRst("SELECT ID, Course from Courses ORDER BY Course");
// load grid
GVStudents.DataSource = MyRst("SELECT * FROM Students Order by FirstName");
GVStudents.DataBind();
}
protected void GVStudents_RowDataBound(object sender, GridViewRowEventArgs e)
{
// for each row, load up listbox with courses
if (e.Row.RowType == DataControlRowType.DataRow)
{
ListBox lv = (ListBox)e.Row.FindControl("LstCourses");
lv.DataSource = rstCourses;
lv.DataBind();
}
}
public DataTable MyRst(string strSQL)
{
DataTable rstData = new DataTable();
using (SqlConnection con = new SqlConnection(Properties.Settings.Default.TEST4))
using (SqlCommand cmdSQL = new SqlCommand(strSQL, con))
{
con.Open();
rstData.Load(cmdSQL.ExecuteReader());
}
return rstData;
}
И теперь на выходе получается вот это:
Поэтому следующим фрагментом кода было бы взять этот список идентификаторов из этого столбца и осветить курсы в списке курсов. (и если это сработает, то мы можем удалить строку «список идентификаторов» в этой сетке. Итак, давайте напишем эту часть, чтобы выделить курсы.
Код будет/может быть:
(мы добавляем сразу после кода привязки данных, который заполнил поле списка.
Так что теперь у нас сверху есть это:
protected void GVStudents_RowDataBound(object sender, GridViewRowEventArgs e)
{
// for each row, load up listbox with courses
if (e.Row.RowType == DataControlRowType.DataRow)
{
ListBox lv = (ListBox)e.Row.FindControl("LstCourses");
lv.DataSource = rstCourses;
lv.DataBind();
// get "item list" column (we NOT use from grid, since we plan to remove
// from grid display - so, get this from the data source
DataRowView gData = (DataRowView)e.Row.DataItem;
List<string> sIdList = gData["CourseIDList"].ToString().Split(' ').ToList();
foreach (ListItem lBox in lv.Items)
{
lBox.Selected = sIdList.Contains(lBox.Value);
}
}
}
И теперь у нас есть этот результат:
Теперь, мне кажется, было бы лучше показать ТОЛЬКО те курсы, которые у них есть в каждом списке.
С другой стороны, я полагаю, что мы могли бы начать использовать вышесказанное для галочки (выберите больше курсов для каждого пользователя). И мы могли бы использовать для этого вышеприведенную сетку.
Править ===========================================
Итак, теперь у нас есть дополнительная информация и что в каждой строке НЕТ списка курсов в качестве «идентификатора», разделенного некоторыми разделителями.
итак, мы можем сбросить столбец списка идентификаторов, и теперь у нас есть только информация о студентах в одной строке поле со списком курсов, подобных этому:
<asp:GridView ID="GVStudents" runat="server" CssClass="table" AutoGenerateColumns="False"
DataKeyNames="ID" OnRowDataBound="GVStudents_RowDataBound" >
<Columns>
<asp:BoundField DataField="FirstName" HeaderText="FirstName" />
<asp:BoundField DataField="LastName" HeaderText="LastName" />
<asp:TemplateField HeaderText="Courses" HeaderStyle-Width="190px">
<ItemTemplate>
<asp:ListBox ID="LstCourses" runat="server" Style="Height:120px;width:170px"
DataValueField ="ID"
DataTextField ="Course"
SelectionMode="Multiple"
SelectMethod="">
</asp:ListBox>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
И теперь наш код для заполнения поля списка становится таким:
protected void GVStudents_RowDataBound(object sender, GridViewRowEventArgs e)
{
// for each row, load up listbox with courses
if (e.Row.RowType == DataControlRowType.DataRow)
{
ListBox lv = (ListBox)e.Row.FindControl("LstCourses");
lv.DataSource = rstCourses;
lv.DataBind();
// now get all courses for this student
DataRowView gData = (DataRowView)e.Row.DataItem;
int StudentPK = (int)gData["ID"];
DataTable rstStudentCourses;
string strSQL = "SELECT Course_ID FROM StudentCourses WHERE Student_ID = " StudentPK;
rstStudentCourses = MyRst(strSQL);
foreach (ListItem lBox in lv.Items)
{
string sFind = "Course_ID = " lBox.Value;
lBox.Selected = (rstStudentCourses.Select(sFind).Count() > 0);
}
}
И выход такой:
Как уже отмечалось, возможно, было бы лучше, чтобы в каждой строке отображались ТОЛЬКО пройденные курсы, а не просто выделялись из ВСЕХ возможных курсов.
Конечно, это простое изменение, и мы бы СБРОСИЛИ данные курсов с глобальной областью действия и просто извлекли список курсов для каждой строки и непосредственно заполнили поле списка этими курсами (это было бы меньше кода, так как теперь не требовалось бы никакого цикла сопоставления со всем списком курсов в поле списка. (но просто запросите, чтобы заполнить список ТОЛЬКО курсами для одной строки/студента).
Комментарии:
1. Имена переменных курсов-это просто идентификаторы , но у этих идентификаторов нет запятой, чтобы разделить их. Выбранные значения в списке могут быть несколькими значениями , эти значения берутся из базы данных.
2. Проверьте мою правку выше в посте.
3. У вас было время, чтобы проверить это? @Альберт Д. Каллал?
4. Конечно, взгляните на мою правку. Я показываю, как создать поле со списком в сетке, а затем, как добавить каждый «идентификатор» в поле со списком. Я вроде как думаю, что было бы лучше просто показать, какие курсы у них есть в списке, вместо того, чтобы выделять, какие у них есть, но независимо от этого — смотрите мое редактирование и как это работает.
5. Хорошо , получил почти все, но я не могу сделать это так, как вы сделали в столбце «Список идентификаторов курса», как вам удалось вставить все идентификаторы в одну строку? Моя сетка создает строку для каждого «списка курсов».