2 same value on gridview - c#

hello i am currently having search button on my form and i want to search is between 2 date and i want to have a alert message if i have 2 same record on other column this is my code for now
SqlConnection sqlCon = new SqlConnection(ConnectionString);
if (sqlCon.State == ConnectionState.Closed)
sqlCon.Open();
SqlDataAdapter sqlData = new SqlDataAdapter("DateFilter", sqlCon);
sqlData.SelectCommand.CommandType = CommandType.StoredProcedure;
sqlData.SelectCommand.Parameters.AddWithValue("#Date", TxtFromDate.Text);
sqlData.SelectCommand.Parameters.AddWithValue("#Date2", TxtToDate.Text);
DataTable dtbl = new DataTable();
sqlData.Fill(dtbl);
sqlCon.Close();
Gridview1.DataSource = dtbl;
Gridview1.DataBind();
Gridview1.UseAccessibleHeader = true;
Gridview1.HeaderRow.TableSection = TableRowSection.TableHeader;

It is really hard decrypting your question. It seems you have an existing SQL result in your DataGridView and then want to check via a button if there are multiple entries with the same "CreatedDate" value.
(1) You should use defined objects in order to be able to work with object items instead of DataTable row/column indexes which is a hassle.
Therefore you need to define your object, map your DataTable rows as objects items in a collection (here: a simple List<>) and then set this collection to your DataGridView.DataSource, e.g.:
// define single object
public class FinishedGood {
public int ID { get; set; }
public DateTime CreatedDate { get; set; }
...
}
// define object collection
public class FinishedGoods : List<FinishedGood> { }
// execute your existing SQL query and fill the DataTable
...
// convert DataTable to FinishedGoods
FinishedGoods finishedGoods = new FinishedGoods();
foreach (DataRow row in dtbl.Rows) {
finishedGoods.Add(new FinishedGood() {
ID = Convert.ToInt32(row["ID"]),
CreatedDate = DateTime.Parse(row["CreatedDate"].ToString());,
...
});
}
// set the collection as datasource
gv.DataSource = finishedGoods;
(2) Now, you can check the DataSource for duplicates via Linq:
using System.Linq;
private HashSet<FinishedGood> CheckForDuplicateCreatedDates() {
HashSet<FinishedGood> result = new HashSet<FinishedGood>();
// collect all createdDates
HashSet<DateTime> createdDates = new HashSet<DateTime>();
foreach (FinishedGood finishedGood in gv.DataSource){
if (!createdDates.Contains(finishedGood.createdDate)) {
createdDates.Add(finishedGood.createdDate);
}
}
// loop through all createdDates
foreach (DateTime createdDate in createdDates) {
// check if there are more than 2 entries with the createdDate in your DataSource
if (gv.DataSource.Count(x => x.CreatedDate == createdDate) > 2) {
// add those entries to your duplicate result list
foreach (FinishedGood finishedGood in gv.DataSource.Where(x => x.CreatedDate == createdDate)) {
result.Add(finishedGood);
}
}
}
return result;
}
(3) To show the alert popup, you can use MessageBox.Show().
(4) To highlight the corresponding rows in the DataGridview, you can use the result of (2) to find the corresponding row indexes and then adjust their DefaultCellStyle.
The button click would look something like this:
private void buttonCheck_Click(object sender, EventArgs e) {
// get duplicates
HashSet<FinishedGood> duplicates = CheckForDuplicateCreatedDates();
if (duplicates.Count() > 0) {
// show alert popup
MessageBox.Show("Duplicates found");
// highlight the corresponding rows
foreach (DataGridViewRow row in gv.Rows) {
if (duplicates.Contains((row.DataBoundItem as FinishedGood))) {
row.DefaultCellStyle.BackColor = Color.DarkRed;
row.DefaultCellStyle.ForeColor = Color.White;
}
}
}
}

Related

Get ID of value in a ComboBox

I have brought the data as below into the combobox. In my "BRANDS" table, the first column is brand_id and the second column is brand_name. I'm getting the names in the combobox, but I need to get the id's when saving it to the database. How can I do it ?
void markaekle() {
SqlCommand komut = new SqlCommand("Select * from MARKALAR", bgl.baglanti());
SqlDataReader dr = komut.ExecuteReader();
while (dr.Read())
{
comboBoxMarka.Properties.Items.Add(dr[1]);
}
bgl.baglanti().Close();
}
I need to save the id value to the database with a button like below:
private void BtnAnaGrupKaydet_Click(object sender, EventArgs e){
SqlCommand komut = new SqlCommand("INSERT INTO ANA_GRUP (marka_id,anagrup_isim,create_date) values (#p1,#p2,#p3)", bgl.baglanti());
komut.Parameters.AddWithValue("#p1", int.Parse(comboBoxMarka.Text));
komut.Parameters.AddWithValue("#p2", txtAnaGrup.Text);
komut.Parameters.AddWithValue("#p3", dateAnaGrup.DateTime);
komut.ExecuteNonQuery();
bgl.baglanti().Close();
MessageBox.Show("Ana Grup Sisteme Eklendi", "Bilgi", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
You can do many implementations.
Use Dataset and after executing your query, you can fill the dataset with the result. so you have all your data in your dataset. (define your database global) and after that when your button hits, you know which index of your combobox is selected. the index is the index of your dataset so you can access the id.
The simplest way is that use a Dictionary with Id and Name. after that is the same above.
To sum up, you need to have a global variable which stores the Id and Name of your query result. this variable can be a Dictionary or a dataset or ....
In order to get selected value instead of text. you would bind combobox like following:
List<DropDownKeyValue> list = new List<DropDownKeyValue>();
List.Add(new DropDownKeyValue
{
ID = 1,
Name = "Designation"
});
cmbSortBy.DisplayMember = "Name";
cmbSortBy.ValueMember = "ID";
cmbSortBy.DataSource = list;
to get selected ID you would use: cmbSortBy.SelectedValue object.
DropDownKeyValue class:
public class DropDownKeyValue
{
public int ID { get; set; }
public string Name { get; set; }
}
You need to bind your ComboBox to a DataSource. The easiest way for you to do this would be to amend your code along these lines:
SqlDataReader dr = komut.ExecuteReader();
var dt = new DataTable();
dt.Load(dr);
yourComboBox.DataSource = null;
yourComboBox.Items.Clear();
yourComboBox.DisplayMember = "brand_name";
yourComboBox.ValueMember = "brand_id";
yourComboBox.DataSource = dt;
You will now be able to access the id using yourComboBox.SelectedValue.
On the line below change values like.
komut.Parameters.AddWithValue("#p1",int.Parse(comboBoxMarka.SelectedValue.ToString()));

Prevent Duplicate Entries into ListView/Access DB [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 4 years ago.
Improve this question
I want to scan in serial numbers into a listview which stores the data into an access db. When the user clicks Submit, the program should either store the data or display a message that indicates the serial number was a duplicate. Here is my code:
Here is how I connect to the database:
namespace Serial_Number_Checker
{
public partial class Form1:Form
{
static string conString = ""
OleDbConnection con = new OleDbConnection(conString);
OleDbCommand cmd;
OleDbDataAdapter adapter;
DataTable dt = new DataTable();
Here is how I create columns for the listview:
public Form1()
{
InitializeComponent();
listView1.SelectedIndexChanged += new EventHandler(listView1_SelectedIndexChanged); // Adding columns to listView1
// list view properities
listView1.View = View.Details;
listView1.FullRowSelect = true;
// Add Columns
listView1.Columns.Add("Employee #", 150);
listView1.Columns.Add("Serial Number", 150);
listView1.Columns.Add("Date/Time", 150);
}
Here is the Add to listView portion:
// Add To ListView1
private void populate(String employeeid, String sn, String timestamp)
{
// Row
String[] row = { employeeid, sn, timestamp };
ListViewItem item = new ListViewItem(row);
listView1.Items.Add(item);
}
Here is the retrieve function:
// Retrieve Check In
private void retrieve()
{
listView1.Items.Clear();
//Sql statement
String sql = "Select * FROM SN_Incoming";
cmd = new OleDbCommand(sql, con);
//Open connection, retrieve, and fill listview1
try
{
con.Open();
adapter = new OleDbDataAdapter(cmd);
adapter.Fill(dt);
//Loop thru dt
foreach (DataRow row in dt.Rows)
{
populate(row[0].ToString(), row[1].ToString(), row[2].ToString());
}
con.Close();
//Clear datatable
dt.Rows.Clear();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
con.Close();
}
}
This is the submit button portion:
private void button1_Click(object sender, EventArgs e)
{
foreach (ListViewItem itemSelected in listView1.SelectedItems)
{
listView1.Items.Remove(itemSelected);
}
if (textBox1.Text == "")
{
MessageBox.Show("Please Enter A Serial Number!", "Input");
}
else
{
add(textBox1.Text);
}
textBox1.Text = "";
textBox1.Focus(); // Set Focus
textBox1.SelectionStart = textBox1.Text.Length == 0 ? 0 : textBox1.Text.Length - 1; // set text selection to end
textBox1.SelectionLength = 0; // Set text Selection Length
retrieve();
}
This should be most of the code. Anything helps.
From my understanding you want to prevent adding duplicate records to your ListView control. I will cover preventing duplicates in your ListView and in your Access Database.
ListView
I would handle this by assigning the serial number to the Tag property of each ListViewItem prior to adding it to the control. Then to ensure no duplicates are added, I would then use that Tag as a reference point for the new serial number to be added. For example:
// Make sure you include the using statement at the top of your code file.
using System.Linq;
private void populate(string employeeid, string, sn, string timestamp) {
ListViewItem lvi = listView1.Items.Cast<ListViewItem>()
.SingleOrDefault(s => s.Tag == sn);
if (lvi == null) {
lvi = new ListViewItem(employeeid);
lvi.SubItems.Add(sn);
lvi.SubItems.Add(timestamp);
lvi.Tag = sn;
listView1.Items.Add(lvi);
} else
MessageBox.Show("Serial number supplied already exists.");
}
The solution above utilizes LINQ which stands for Language Integrated Query. It was introduced in .NET 3.5. The method utilized essentially attempts to find a ListViewItem that contains the Tag property with a value of the supplied serial number.
The call to Cast allows you to utilize the SingleOrDefault method available to IEnumerable since the Items property of ListView does not derive from IEnumerable, but instead ListViewItemCollection.
You can take this down to a lower level of .NET by implementing a foreach loop instead of utilizing LINQ. For example:
private void populate(string employeeid, string, sn, string timestamp) {
foreach (ListViewItem lvi in listView1.Items) {
if (lvi.Tag == sn) {
MessageBox.Show("Serial number supplied already exists.");
return;
}
}
// We know the serial number doesn't exist, so just add the new item.
ListViewItem lvi = new ListViewItem(employeeid);
lvi.SubItems.Add(sn);
lvi.SubItems.Add(timestamp);
lvi.Tag = sn;
listView1.Items.Add(lvi);
}
Database
Since you're using Access for your database, you can follow this guide on preventing duplicate values in a column (in your case it will prevent duplicate serial numbers). Essentially, you just create a unique index for the field you wish to have unique. This is done by setting the field's Indexed property to Yes.
Set a field's Indexed property to Yes (No duplicates)
In the Navigation Pane, right-click the table that contains the field, and then click Design View.
Select the field that you want to make sure has unique values.
In the Field Properties pane, on the General tab, set the Indexed property to Yes (No duplicates).
Useful Points
LINQ expressions are broken down by the compiler to their basic implementations. For example, SingleOrDefault loops through a collection of objects, attempts to find a single object that meets the specified criteria, and then returns the result. If no object was found, it returns null. This is done with a foreach loop.
The foreach loop is actually faster than using LINQ in most cases. On a small scale this wouldn't even be noticed; however, increase the number of ListViewItem objects that you have to iterate through into the 300,000+ range and you have a substantial difference.
Also, it is more effective to add all of your ListViewItem objects to a generic collection, then finally to the ListView via AddRange. If I remember correctly, this is because Add and AddRange cause the ListView to re-sort, and as point 2 above stated, the more items you have, the worse this impacts performance. I've included an example of this kind of implementation below:
Add Range Implementation
List<ListViewItem> items = new List<ListViewItem>();
for (int i = 0; i < 50000; i++) {
ListViewItem lvi = new ListViewItem($"Some kind of text {i}.");
lvi.Tag = i;
items.Add(lvi);
}
listView1.Items.AddRange(items.ToArray());
Refactor Of Your Code
I took the liberty of refactoring your code to teach you more simplistic/efficient ways to accomplish your goal. You may want to take a look at the documentation for: using statement, string.IsNullOrWhiteSpace(), string.Empty. The one thing I will clue you in on with the using statement is that it will automatically close any open connections when the final portion of the block is executed, this is due to the disposal of the object:
When the lifetime of an IDisposable object is limited to a single method, you should declare and instantiate it in the using statement. The using statement calls the Dispose method on the object in the correct way, and (when you use it as shown earlier) it also causes the object itself to go out of scope as soon as Dispose is called. Within the using block, the object is read-only and cannot be modified or reassigned.
private void Click_Submit(object sender, EventArgs e) {
foreach (ListViewItem lvi in listView1.SelectedItems)
listView1.Items.Remove(lvi);
if (string.IsNullOrWhiteSpace(textBox1.Text))
MessageBox.Show("Please enter a serial number!", "Input");
else
InserSerialNumber(textBox1.Text);
textBox1.Text = string.Empty;
textBox1.Focus();
textBox1.SelectionStart = textBox1.Text.Length == 0 ? 0 : textBox1.Text.Length - 1;
textBox1.SelectionLength = 0;
LoadSerialNumbers();
}
private void InsertSerialNumber(string sn) {
using (OleDbCommand odc = new OleDbCommand("INSER INTO SN_Incoming(SN) VALUES(#SN)", con)) {
odc.Parameters.AddWIthValue("#SN", sn);
try {
con.Open();
odc.ExecuteNonQuery();
} catch (Exception e) { MessageBox.Show(e.Message); } finally { con.Close(); }
}
}
private void LoadSerialNumbers() {
listView1.Items.Clear();
DataTable dt = new DataTable();
using (OleDbCommand odc = new OleDbCommand("SELECT * FROM SN_Incoming", con)) {
try {
con.Open();
using (OleDbDataAdapter oda = new OleDbDataAdapter(odc))
ida.Fill(dt);
} catch (Exception e) { MessageBox.Show(e.Message); } finally { con.Close(); }
}
List<ListViewItem> items = new List<ListViewItem>();
foreach (DataRow row in dt.Rows) {
ListViewItem lvi = items.SingleOrDefault(s => s.Tag == row[1].ToString());
if (lvi != null)
continue;
lvi = new ListViewItem(new string[] { row[0].ToString(), row[1].ToString(), row[2].ToString() });
lvi.Tag = row[1].ToString();
items.Add(lvi);
}
listView1.Items.AddRange(items.ToArray());
}

How to set first index as blank in combobox

I have a combobox that is bound with a datasource. In this combobox I have to add a blank field at index 0.
I have written following code for getting records.
public List<TBASubType> GetSubType(int typ)
{
using (var tr = session.BeginTransaction())
{
try
{
List<TBASubType> lstSubTypes = (from sbt in session.Query<TBASubType>()
where sbt.FType == typ
select sbt).ToList();
tr.Commit();
return lstSubTypes;
}
catch (Exception ex)
{
CusException cex = new CusException(ex);
cex.Write();
return null;
}
}
}
After this it bind with combobox with data binding source as below code.
M3.CM.BAL.CM CMobj = new M3.CM.BAL.CM(wSession.CreateSession());
lstSubTypes = CMobj.GetSubType(type);
this.tBASubTypeBindingSource.DataSource = lstSubTypes;
If you just want to select nothing initially, you can use
comboBox1.SelectedIndex=-1;
Thus you can't modify Items when you are are bound to DataSource, then only option to add blank row is modifying your data source. Create some empty object and add it to data source. E.g. if you have list of some Person entities bound to combobox:
var people = Builder<Person>.CreateListOfSize(10).Build().ToList();
people.Insert(0, new Person { Name = "" });
comboBox1.DisplayMember = "Name";
comboBox1.DataSource = people;
You can define static property Empty in your class:
public static readonly Person Empty = new Person { Name = "" };
And use it to insert default blank item:
people.Insert(0, Person.Empty);
This also will allow to check if selected item is default one:
private void comboBox_SelectedIndexChanged(object sender, EventArgs e)
{
Person person = (Person)comboBox.SelectedItem;
if (person == Person.Empty)
MessageBox.Show("Default item selected!");
}
cboCustomers.Items.Add(""); // Just add a blank item first
// Then load the records from the database
try
{
OleDbConnection con = new OleDbConnection(strDBConnection);
OleDbCommand cmd = new OleDbCommand();
con.Open();
cmd.Connection = con;
cmd.CommandText = "SELECT * FROM Customers";
OleDbDataReader dr = cmd.ExecuteReader();
while (dr.Read())
{
cboCustomers.Items.Add(dr["Name"]);
}
con.Close();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
After creating my combo boxes, I added these lines to the end of the Load() method:
private void xyz_Load(object sender, EventArgs e)
{
this.xyzTableAdapter.Fill(this.DataSet.xyz);
this.comboBoxXYZ.SelectedIndex = -1;
}
replace xyz with the names you've given to your controls

getting a select statement column info from combobox

Hopefully i don't sound confusing but i am not sure if what i am trying to get at is possible.
I have a select statement to get name, id, guid. I am setting the display to name and the value to Id for each combobox. Is there a way that i could also assign the guid to the combo box so that i could use it in my winforms app?
here is what i have for select statement:
private void secondChild_drp_SelectedIndexChanged(object sender, EventArgs e)
{
string secondChildId = secondChild_drp.SelectedValue.ToString();
using (SqlConnection con = new SqlConnection(conString))
{
con.Open();
using (SqlDataAdapter sda = new SqlDataAdapter("SELECT ... WHERE em.ChildID = (" + secondChildId + ")", conString))
{
DataTable dt = new DataTable();
sda.Fill(dt);
thirdChild_drp.ValueMember = "ID";
thirdChild_drp.DisplayMember = "DisplayName";
thirdChild_drp.DataSource = dt;
}
}
cmd.CommandText="StoreProcName";
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#ChildID", secondChildId);
cmd.Connection = con2;
con2.Open();
reader = cmd.ExecuteReader();
var guid = reader.ToString();
reader.Close();
con2.Close();
}
right now when i run this it tells me reader = cmd.ExecuteReader(); has Procedure or function StoreProcName has too many arguments specified.
i just want to get the guid associated with the id i passed in.
You can get the guid from your datatable as follows where yourselectedid is the combobox selecteditem id.
var results = from row in dt.AsEnumerable()
where row.Field<int>("ID") == yourselectedid
select row;
now from results you can get all the desired columns you want
Basically the same answer as I already posted here:
You could define a simple object which you are filling from your data base query:
public class Item
{
public int ID { get; set; }
public string DisplayName { get; set; }
public Guid Guid{ get; set; }
}
Your implementation could look something like this (some mockup data):
listBox1.DataSource = items;
listBox1.DisplayMember = "DisplayName";
listBox1.ValueMember = "ID";
Then based on the value you selected, you can query through your items and get the item:
var key = (int)listBox1.SelectedValue;
foreach (var existingItem in items)
{
if (existingItem.Key == key)
{
//woohoo got it!
Debug.Print(existingItem.Guid.ToString())
}
}
you can put both of the value in the value member, separated by whichever character for separator like : "12;0000-000-0000" then separate again the Value Menber with a String.Split.

c# wpf datagrid add row

I need to insert values in a table that have different columns from time to time. The columns and row data are updated from MySql. Each row values are in single MySql cells with the following format:
ColumnName{Delimiter}Value{BigDelimiter}Column2Name{Delimiter}Value2...
So I split the cell strings to get the column header and value, as the user can rearrange columns, modify, delete or insert new ones. I searched for a solution, though I get nothing but empty rows:
private void GetDataTableValues()
{
if (dtData.Value != null)
{
try
{
LoadFields();
dgwDataMain.Items.Clear();
dgwDataMain.Columns.Clear();
foreach (Fields field in fields)
{
DataGridTextColumn column = new DataGridTextColumn();
column.Header = field.name;
column.Binding = new Binding(field.name);
dgwDataMain.Columns.Add(column);
}
if (connection.State == System.Data.ConnectionState.Broken || connection.State == System.Data.ConnectionState.Closed)
connection.Open();
command.Parameters.Clear();
DateTime dt = dtData.Value ?? DateTime.Now;
command.Parameters.Add("#date", MySqlDbType.Date, 50).Value = dt.ToString("yyyy-MM-dd");
command.CommandText = "SELECT value,team FROM sessions WHERE date=#date";
List<string> teams = new List<string>();
foreach (Control ctrl in panDataFilter.Children)
if ((ctrl as CheckBox).IsChecked == true)
teams.Add(Convert.ToString((ctrl as CheckBox).Content));
using (MySqlDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
bool v = false;
if (teams.Contains(reader[1].ToString()) || teams.Count == 0)
v = true;
if (v)
{
DatabaseObject obj = new DatabaseObject();
List<string> str2 = new List<string>(reader[0].ToString().Split(new string[] { "</s&p>" }, StringSplitOptions.None).ToList());
obj.Items = new List<string>(str2.Count);
foreach (string str in str2)
{
List<string> item = new List<string>(str.Split(new string[] { "<&p>" }, StringSplitOptions.None).ToList());
int index = dgwDataMain.Columns.Single(c => c.Header.ToString() == item[0].ToString()).DisplayIndex;
obj.Items.Insert(index, item[1].ToString());
}
dgwDataMain.Items.Add(obj);
}
}
}
}
catch (MySqlException ex)
{
MessageBox.Show(ex.ErrorCode.ToString() + ": " + ex.Message, "Error", MessageBoxButton.OK, MessageBoxImage.Exclamation);
}
}
}
public class DatabaseObject
{
public List<string> Items = new List<string>();
}
to delete extra row from datagrid is, just make property...
Canuseraddrows="false";
Please use Observablecollection to bind the data grid. By using observablecollection easily you can add or delete item and not required to reset the data source of data grid.
Sample Code:
observableCollection myClass = new
observableCollection();
myClass.add(Class)

Categories