Check duplicate index value in listveiw - c#

I have a listview in C# with columns(ProdcutId,ProductName,UnitPirce,Quantity). I am inserting data in it from text boxes(txtproid,txtproname,txtunitprice,txtquantity). All these txtboxes are inserted once on a button click. What I want here is when i click the button,it should check the ProductId column in listview. If it contain the value coming from 'txtproid', It should not add all txtboxes in listview instead should show a messaage "This Product is Already Included". It should not check the whole item in listv.
I have tried many things but invain like:
int c = 0;
if (listView1.Items.Count != 0)
{
foreach (ListViewItem lv in listView1.Items)
{
c = 0;
if (lv.SubItems[0].Text == cmbpid.SelectedItem.ToString())
{
Validations.ErrorMessage("Item already exists in the Cart");
c = 1;
}
}
}
else if (c == 0)
{
ListViewItem lvi = new ListViewItem(cmbpid.Text);
lvi.SubItems.Add(cmbpname.Text);
lvi.SubItems.Add(txtunitprice.Text);
lvi.SubItems.Add(txtproquantity.Text);
lvi.SubItems.Add(txtunittotal.Text);
lvi.SubItems.Add(txtbatch.Text);
listView1.Items.Add(lvi);
//clear fields
quvar = 0;
totalvar = 0;
txtproquantity.Clear();
txtunitprice.Clear();
txtunittotal.Clear();
GetListviewTotal();
txtbatch.Clear();
cmbpid.SelectedIndex = -1;
cmbpname.SelectedIndex = -1;
}

Your task is divided two small functions.
First, check duplicate product id.(Let's say CheckSameProductId())
Second, insert data to ListView.(Let's say InsertProductData())
So, below form can be.
if (CheckDuplicateId())
{
//show error text
}
else
{
//insert text boxes's data to List View
InsertProductData();
}
And then, each function can write, for example.
//check whether it's already inserted
bool CheckDuplicateId()
{
foreach (ListViewItem lv in listView1.Items)
{
if (lv.SubItems[0].Text == cmbpid.SelectedItem.ToString())
{
//there is a duplicate data
return true;
}
}
//there is no duplicate data
return false;
}
//insert data using text boxes to listview ctrl
void InsertProductData()
{
foreach (Control x in this.Controls)
{
if (x is TextBox)
{
//I'm not sure your control z-order
lvi.SubItems.Add(((TextBox)x).Text);
}
}
}
I've not compiled above code, so you have to check that.

Related

Feeding a override value from OnSelectionChangeCommitted DataGridViewComboBoxEditingControl to column object

So I have this and I know it is wrong:
protected override void OnSelectionChangeCommitted(EventArgs e)
{
if (SelectedIndex == 0)
{
GENIO_Viewer.FullColourPaletteForm dlgColour = new GENIO_Viewer.FullColourPaletteForm();
if(dlgColour.ShowDialog() == DialogResult.OK)
{
bool bFound = false;
for(int i = 1; i < Items.Count; i++)
{
ComboboxColourItem ocbItem = (ComboboxColourItem)Items[i];
if(ocbItem.Index == dlgColour.iSelectedColour)
{
SelectedIndex = i;
bFound = true;
break;
// We can just select this one
}
}
if(!bFound)
{
// Add it
ComboboxColourItem ocbItem = ComboboxColourItem.Create((ushort)dlgColour.iSelectedColour);
Items.Add(ocbItem);
SelectedIndex = Items.Count - 1;
}
}
}
base.OnSelectionChangeCommitted(e);
}
This handler is part of my DataGridViewComboBoxEditingControl. But it is the wrong place to add new Items.
I can't workout how to get access to the owning Column as that is where I need to add the Item, otherwise I get exceptions.
I have looked here: https://msdn.microsoft.com/en-us/library/system.windows.forms.datagridviewcomboboxeditingcontrol(v=vs.110).aspx
But i can't see a property I can use to get the column object.
How do we do this from the editing control?
Further explaination:
The list combo items are added by the "column" object. Thus we have a set of 15 colours to choose from. Now I have added a genric colour tot he top of the list.
So, the user invokes the edit, droplist displays, and they pick item 0. We intercept this with the aforementioned handler. Since they picked item 0, we show a popup dialogue to let them choose a different colour.
When they have chosen, we must now either find it or add it to the the mandatory list of items for the column. Make sense now?
I tried to use the DataGridView Notify object but for some reason it is not showing in the list of available functions.
I don't use a DataSource. I populate like this in the columns constructor:
private void InitialiseComboItems()
{
List<ushort> listColours = new List<ushort>();
listColours.Add(0);
listColours.Add(1);
listColours.Add(2);
listColours.Add(3);
listColours.Add(4);
listColours.Add(5);
listColours.Add(6);
listColours.Add(7);
listColours.Add(8);
listColours.Add(9);
listColours.Add(250);
listColours.Add(251);
listColours.Add(252);
listColours.Add(253);
listColours.Add(254);
listColours.Add(255);
this.Items.Clear();
foreach (ushort iColourIndex in listColours)
this.Items.Add(ComboboxColourItem.Create(iColourIndex));
}
I also have a helper method:
public ComboboxColourItem InsertColour(ushort iColourIndex)
{
ComboboxColourItem ocbItem = ComboboxColourItem.Create(iColourIndex);
bool bAppend = true;
if (Items.Count > 16)
{
// There are other colours, need to find right index
for(int i = 16; i < Items.Count; i++)
{
if(ocbItem.Index < ((ComboboxColourItem)Items[i]).Index)
{
bAppend = false;
Items.Insert(i, ocbItem);
break;
}
}
}
if (bAppend)
Items.Add(ocbItem);
return ocbItem;
}
You can use EditingControlDataGridView to find the DataGridView which owns the editing control. Then you can use CurrentCell property of grid to find the current cell and using ColumnIndex you will find the column index. Then using Columns collection, you can get the column at that index:
var c = this.EditingControlDataGridView
.Columns[this.EditingControlDataGridView.CurrentCell.ColumnIndex]
as DataGridViewComboBoxColumn;
if (c != null)
c.Items.Add("Something");

Searching DataGridViews contained in multiple tab pages

I have one or two datagridviews in seven different tabs. I have a search box that worked fine when just searching the datagridview in the current selected tab, however searching across multiple tabs has proved to be a problem. The first time the search is used, nothing happens. After that, when the substring that's being searched for is found, the correct tab is shown, however the row containing the substring is not highlighted. If I search again without changing tab pages, the correct row will be highlighted... Thank you in advance for the help! Here are my methods:
private void searchBox_KeyDown(object sender, KeyEventArgs e)
{
// Declare DGV
DataGridView DGV = null;
bool isFound = false;
int tabIndex = -1;
// When a key is pressed and it's the enter key...
if (e.KeyCode == Keys.Enter)
{
// Loop through all tab pages
for (int i = 0; i < tabs.TabCount; i++)
{
// Loop through all controls in the selected tab
foreach (Control c in tabs.TabPages[i].Controls)
{
// if the control is a datagridview, cast it as a datagridview,
// and set DGV equal to it
if (c is DataGridView)
{
DGV = (DataGridView)c;
string name = DGV.Name;
// Pass in DGV to Search() to search all cells within it for
// the term in the searchbox
isFound = Search(DGV);
}
if (isFound)
tabIndex = i;
}
}
if (tabIndex >= 0)
{
tabs.SelectTab(tabIndex);
tabs.SelectedTab.Show();
highLightSearchRows();
}
}
}
This is my Search method:
private bool Search(DataGridView dataGrid)
{
int i, j;
bool retval = false;
// Makes sure searchBox contains text before searching
if (searchBox.TextLength <= 0)
return false;
string searchBoxText = searchBox.Text, sub1 = searchBox.Text.Substring(1);
// Doesn't accept an empty string as a valid search parameter
if (searchBoxText == "")
return false;
string searchForText = searchBoxText;
// Starts looping from the bottom of the grid up
// This makes FirstDisplayedScrollingRowIndex show the uppermost match in the grid
for (i = dataGrid.Rows.Count - 1; i >= 0; i--)
{
// If any cells contain the search string, they are highlighted
if (dataGrid.Rows[i].Cells.OfType<DataGridViewCell>()
.Any(cell => ((dynamic)cell.Value).Contains(searchForText)))
retval = true;
// Deselect all rows in all datagrids in order for other rows to
// be programmatically selected
dataGrid.Rows[i].Selected = false;
}
return retval;
}
And the highlight rows method:
private void highLightSearchRows()
{
DataGridView DGV = null;
int rowIndex = -2;
foreach (Control c in tabs.SelectedTab.Controls)
{
// if the control is a datagridview, cast it as a datagridview,
// and set DGV equal to it
if (c is DataGridView)
{
DGV = (DataGridView)c;
string name = DGV.Name;
foreach (DataGridViewRow row in DGV.Rows)
{
// If any cells contain the search string, they are highlighted
if (row.Cells.OfType<DataGridViewCell>()
.Any(cell => ((dynamic)cell.Value).Contains(searchBox.Text)))
{
// Makes selected row the top row in the view
rowIndex = row.Index;
row.Selected = true;
DGV.FirstDisplayedScrollingRowIndex = rowIndex;
}
if (rowIndex >= 0)
{
// Select the matching row
row.Selected = true;
rowIndex = -2;
}
}
}
}
}

How can I loop through the selected listview item

When I double click on my selected listview item I can easily get each value and set them in a textbox by using the following code.
ListViewItem item = listView1.SelectedItems[0];
entry_txtBox.Text = item.Text;
name_txtBox.Text = item.SubItems[1].Text;
But I'd rather loop through the selected item and compare each column name to each textbox tag. If they match set the column value to the textbox.
This is what I have so far.
foreach (Control c in this.Controls)
{
foreach (Control childc in c.Controls)
{
foreach (ColumnHeader header in listView1.Columns) // This should be the selected item.
{
if (childc is TextBox && header == childc.Tag)
{
// Fill Textboxes
}
}
}
}
Again my question is how can I loop through each column header and compare them to a textbox tag.
First you can use good old recursion to build a flat list of all your controls up by traversing the control tree:
var controls = GetControls(parent);
public IEnumerable<Control> GetControls(Control parent)
{
foreach(var control in parent.Controls)
{
yield return control;
var childControls = GetControls(control);
foreach(var child in childControls)
{
yield return child;
}
}
}
Then just do a LINQ to filter:
var textBoxControls = controls.Select(c => c is TextBox && header == TextBox.ID); //Or whatever condition you want to use.

Delete 4 ListBox items by selecting one

I was wondering but I have 4 listboxes and what I was wondering is how would I delete all 4 of the items by just selecting one item?
As you can see here this is the part that deletes the selected item but how would I delete all 4 items in my listbox if I just selected the "seriesName" one.
for (int x = lstb_seriesName.SelectedIndices.Count - 1; x >= 0; x--)
{
int a = lstb_seriesName.SelectedIndices[x];
lstb_seriesName.Items.RemoveAt(a);
}
Here's my code for the delete button.
private void btn_Delete_Click(object sender, EventArgs e)
{
if (lstb_seriesName.SelectedItems.Count <= 0)
{
MessageBox.Show("You need to select an item to delete first!");
}
else
{
for (int x = lstb_seriesName.SelectedIndices.Count - 1; x >= 0; x--)
{
int a = lstb_seriesName.SelectedIndices[x];
lstb_seriesName.Items.RemoveAt(a);
}
System.IO.StreamWriter DeleteFileData = new System.IO.StreamWriter(sPath);
foreach (var item in lstb_seriesName.Items)
{
DeleteFileData.WriteLine(item);
}
foreach (var item in lstb_seriesDay.Items)
{
DeleteFileData.WriteLine(item);
}
foreach (var item in lstb_seriesTime.Items)
{
DeleteFileData.WriteLine(item);
}
foreach (var item in lstb_seriesActive.Items)
{
DeleteFileData.WriteLine(item);
}
DeleteFileData.Close();
MessageBox.Show("Program deleted!");
}
}
The only way to do this is if you can guarantee that they are all in the same order.
In which case you could take the IndexOf(item) and use the index value to delete the other list items by index.
Otherwise, you need some way to link/relate these guys to each other.
Edit Per Request:
private void btn_Delete_Click(object sender, EventArgs e)
{
if (lstb_seriesName.SelectedItems.Count <= 0)
MessageBox.Show("You need to select an item to delete first!");
else
{
var indexesToRemove = lstb_seriesName.SelectedIndices;
foreach(var index in indexesToRemove)
{
lstb_seriesName.Items.RemoveAt(index);
lstb_seriesDay.Items.RemoveAt(index);
lstb_seriesTime.Items.RemoveAt(index);
lstb_seriesActive.Items.RemoveAt(index);
}
MessageBox.Show("Program deleted!");
}
}

Referencing Checkboxes within a Repeater

I have a Repeater control that is creating a dynamic amount of CheckBoxList controls and each list has a different set of ListItems.
I have done this part just fine, but the issue I'm having is how to save the checked states of these dynamically created boxes. I cannot find out how to get the list of these CheckBoxList controls.
Here's some pseudo-code of what I'm trying to do:
foreach (Item i in MyRepeater)
{
if (i.ItemType is CheckBoxList)
{
foreach (ListItem x in i)
{
update table set tiChecked = x.Checked
where table.id = i.id and table.typeid = x.id
}
}
}
I have the ID of the CheckBoxList and the ListItem corresponding to the IDs in the DB.
Edit:
Of course after I ask, I find it out. This seems to be getting me what I want
foreach (RepeaterItem tmp in rptReportList.Items)
{
if (tmp.ItemType == ListItemType.Item)
{
foreach (Control c in tmp.Controls)
{
if (c is CheckBoxList)
{
DisplayMessage(this, c.ID.ToString());
}
}
}
}
You need to look deeper than the RepeaterItem:
// repeater item
foreach (Control cr in MyRepeater.Controls)
{
// controls within repeater item
foreach (Control c in cr.Controls)
{
CheckBoxList chklst = c as CheckBoxList;
if (chklst != null)
{
foreach (ListItem i in chklst.Items)
{
string valueToUpdate = i.Value;
string textToUpdate = i.Text;
bool checkedToUpdate = i.Selected;
// Do update
}
}
}
}

Categories

Resources