#c# #sql-server #listbox #windows-forms-designer #.net-4.7.2
#c# #sql-сервер #listbox #windows-forms-designer #.net-4.7.2
Вопрос:
Я делюсь с вами фрагментом кода, который работает, за исключением той части, где я пытаюсь зациклить элементы моего listbox. Вот почему я здесь прошу вас о помощи. В последнее время я перешел с VBA на C #, поэтому я все еще новичок в этом и пока не понимаю всего. Итак, приведенный ниже код подключается к моей базе данных SQL Server и извлекает данные как в моем listbox, так и в DataGridView. Я также могу фильтровать с помощью двух текстовых полей. Итак, теперь у меня есть элементы в моем listbox и представление моей базы данных в DataGridView. Я хотел бы отфильтровать мой DataGridView (который заполняется таблицей данных) с помощью элемента моего списка. Я думаю, я пропустил только глупую часть. Почему я получаю этот CS0246 «Не удалось найти ListItem»
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Configuration;
using System.Data.SqlClient;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WindowsFormsAppTest
{
public partial class Form1 : Form
{
//Initialize the component and display the items within my listbox CS_Bonds_listBox
public Form1()
{
InitializeComponent();
string connetionString = @"Data Source=my_server;Initial Catalog=my_db;Integrated Security=SSPI";
SqlConnection conn = new SqlConnection(connetionString);
conn.Open();
DataSet ds = new DataSet();
SqlDataAdapter adapter = new SqlDataAdapter(
"SELECT DISTINCT RatingProvider FROM Bonds", conn);
adapter.Fill(ds);
this.CS_Bonds_listBox.DataSource = ds.Tables[0];
this.CS_Bonds_listBox.DisplayMember = "RatingProvider";
}
private void Form1_Load(object sender, EventArgs e)
{
}
DataTable dtTEST = new DataTable();
// Next, when clicking on my button Connect, I retrieve my db into a Datatable that is displayed within //the Datagridview1
private void buttonConnect_Click(object sender, EventArgs e)
{
string connetionString = @"Data Source=my_server;Initial Catalog=my_db;Integrated Security=SSPI";
SqlConnection cnn= new SqlConnection(connetionString);
cnn.Open();
MessageBox.Show("Connection Open !");
String sql = "Select * from Bonds";
SqlCommand command = new SqlCommand(sql, cnn);
SqlDataAdapter sqlDA = new SqlDataAdapter();
sqlDA.SelectCommand = command;
sqlDA.Fill(dtTEST);
dataGridView1.DataSource = dtTEST;
cnn.Close();
}
private void ISIN_Bonds_textBox_TextChanged(object sender, EventArgs e)
{
DataView dv = dtTEST.DefaultView;
dv.RowFilter = "ISIN LIKE '" ISIN_Bonds_textBox.Text "%'";
dataGridView1.DataSource = dv;
}
private void Ticker_Bonds_textBox_TextChanged(object sender, EventArgs e)
{
DataView dv1 = dtTEST.DefaultView;
dv1.RowFilter = "Ticker LIKE '" Ticker_Bonds_textBox.Text "%'";
dataGridView1.DataSource = dv1;
}
private void CS_Bonds_listBox_SelectedIndexChanged(object sender, EventArgs e)
{
string conString = @"Data Source=my_server;Initial Catalog=my_db;Integrated Security=SSPI";
string query = "SELECT ISIN, Ticker, CrediSight, FROM Bonds";
string condition = string.Empty;
foreach (ListItem item in CS_Bonds_listBox.Items)
{
condition = item.Selected ? string.Format("'{0}',", item.Value) : "";
}
if (!string.IsNullOrEmpty(condition))
{
condition = string.Format(" WHERE Country IN ({0})", condition.Substring(0, condition.Length - 1));
}
using (SqlConnection con = new SqlConnection(conString))
{
using (SqlCommand cmd = new SqlCommand(query condition))
{
using (SqlDataAdapter sda = new SqlDataAdapter(cmd))
{
cmd.Connection = con;
using (DataTable dt = new DataTable())
{
sda.Fill(dt);
dataGridView1.DataSource = dt;
//dataGridView1.DataBind();
}
}
}
}
}
}
}
Комментарии:
1. Если вы убедитесь, что все строки кода содержат не менее 4 пробелов в начале, они будут отображаться в stackoverflow правильно отформатированными
2. @CaiusJard спасибо, теперь должно быть лучше
![]()
Ответ №1:
В этой строке есть проблема:
foreach (ListItem item in CS_Bonds_listBox.Items)
ListItem — это WebForms, а ваше приложение — WinForms; ваш listbox не содержит списка объектов ListItem, поэтому эта строка кода все равно не сработала бы, даже если было импортировано соответствующее веб-пространство имен.
Поскольку вы привязали свой listbox к datatable, отображаемый список полон объектов DataRowView, так что это то, что вам нужно обработать. DataRowView имеет свойство Row, которое предоставляет вам базовую строку, к которой, в свою очередь, можно получить доступ по имени столбца.
Кроме того, чтобы упростить вашу жизнь, listbox имеет свойство SelectedItems, поэтому вам не нужно проверять каждый элемент на предмет выбора:
foreach (DataRowView drv in CS_Bonds_listBox.SelectedItems)
{
var dr = drv.Row as DataRow;
var rp = dr["RatingProvider"];
condition = $"'{rp}',"
}
В результате этого ваше условие будет заканчиваться запятой, поэтому обрежьте его, прежде чем создавать с ним предложение IN:
condition = condition.TrimEnd(',');
Этот метод может быть подвержен взлому SQL-инъекций, если пользователю удается изменить текст, отображаемый в элементах списка.
Лучший способ справиться с проблемой — это параметризация. Вы бы сделали это так:
var cmd = new SqlCommand("SELECT * FROM table WHERE Country IN(", connStr);
int i = 0;
foreach (DataRowView drv in CS_Bonds_listBox.SelectedItems)
{
var dr = drv.Row as DataRow;
var rp = dr["RatingProvider"];
cmd.CommandText = $"@p{i},";
cmd.Parameters.Add($"@p{i}", SqlDbType.VarChar).Value = rp;
i ;
}
cmd.CommandText = cmd.CommandText.TrimEnd(',') ")";
using(var da = new SqlDataAdapter(cmd))
{
var dt = new DataTable();
da.Fill(dt);
someGridView.DataSource = dt;
}
Это создает sql, который выглядит так, т. SELECT * FROM table WHERE Country IN(@p0,@p1,@p2....
Е. Мы объединяем заполнители параметров, а не объединяем значения. В то же время мы заполнили коллекцию параметров значениями параметров
Это также означает, что наша база данных не может быть взломана с помощью нашей программы, и наше приложение не погибает в куче, когда пользователь выбирает страну с таким именем, как Cote d'Ivoire
Некоторые другие вещи, на которые следует обратить внимание, чтобы привести в порядок ваш код:
SqlDataAdapter может принимать строку SQL и строку connection-string. Вам не нужно создавать для него SqlCommand. Вам не нужно открывать и закрывать для него conenctions; он знает, как все это сделать сам. Я использовал только SqlCommand, потому что я собирал коллекцию параметров по ходу работы. Обычно я бы сделал using(var da = SqlDataAdapter("SELECT...", "Server=..")
, потому что это делает вещи приятными и аккуратными.
Это означает, например, что ваш конструктор может быть просто:
//put this here once
private string _connStr = @"Data Source=my_server;Initial Catalog=my_db;Integrated Security=SSPI";
public Form1()
{
InitializeComponent();
var dt = new DataTable();
using(var da = new SqlDataAdapter("SELECT DISTINCT RatingProvider FROM Bonds", _connStr))
adapter.Fill(dt);
this.CS_Bonds_listBox.DataSource = dt;
this.CS_Bonds_listBox.DisplayMember = "RatingProvider";
}
Комментарии:
1. Большое вам спасибо за все ваши советы, это золото! Приятный французский плюс
Однако у меня есть несколько вопросов. Во-первых, как вам удается узнать, является ли это объектом WebForms или WinForms? Ваше предложение было определенно более логичным, чем мое, поэтому я внес изменения, но странно то, что, как только я запускаю приложение, оно вылетает прямо в последней строке «sda.Fill (dt) и предупреждает о неправильно вставленной скобке, но это похоже на то, что код помещает все элементы непосредственно вотсутствие условия даже позволяет мне щелкнуть или выбрать один из них. Надеюсь, это достаточно ясно…
2. Для webforms / winforms я узнаю большинство из них в наши дни, но если я этого не сделаю, то быстрый google «ListItem class» выдает это — думаю, Google давно понял, что я разработчик программного обеспечения, потому что первый удар — MSDN :), а вверху страницы находится пространство имен System.Web.UI .. Я не совсем понял другую проблему. Вы говорите, что ваша программа выходит из строя с сообщением об ошибке при запуске? Или то, что вы видите красную волнистую линию под вашим кодом, работает? Каково точное метеорное сообщение (в любом случае)?
3. @CaiuJard, спасибо за ответ, чувак, мне все еще нужно разобраться с этой справкой Microsoft, очевидно! Я дважды проверю свое сообщение об ошибке и свяжусь с вами после работы. Прошу прощения за мой поздний ответ.
4. Привет, @Caius Jard, наконец-то я смог подключиться и протестировать. Вот мое сообщение об ошибке, поэтому я предполагаю, что в строковом условии есть что-то: System.Data.SqlClient.SQLException: ‘Незакрытая кавычка после символьной строки ‘Underperform)’. Неправильный синтаксис рядом с ‘Underperform)’.’Но дело в том, почему он запускает фильтр при запуске приложения, а не при установке флажков
5. Вероятно, потому, что событие, к которому вы подключились, не подходит для того, что вам нужно.. Использовать другое событие в listbox?