Delete row from datatable based on condition - c#

In my DataGrid I used a ComboBox in the first column, so it will fetch some data from the database using the DisplayMember and ValueMember concepts. Now I want to remove the value from the ComboBox which is previously selected.
Populating the ComboBox code is given below:
dTable = getDummyTable.GetDummyTble("Dummy", "DNO", "All");
dCmbData = dTable;
cmbDeno.DataSource = dTable;
cmbDeno.DisplayMember = "dyName";
cmbDeno.ValueMember = "dyRemarks";
The next row of selection there should not be a duplicate value in the ComboBox.
How can I achieve this?
Can anyone help me with this?

well try this one out. You have the DataTable which you are using to bind all combos (correct me if I'm wrong). Now all we need to do is that when an item is selected from any combo, we need to remove that item from all the other combos). You will need to declare a class level dictionary to store which combo had what value stored previously:
IDictionary<ComboBox, DataRow> _prevSelection;
//Please don't mind if syntax is wrong worked too long in web
comboBox.OnSelectedIndexChanged += fixItems;
private void fixItems(object sender, EventArgs e)
{
var cbo= sender as ComboBox;
if(cbo==null) return;
var prev = _prevSelection[cbo];
var row=<GET ROW FROM DATATABLE FOR CURRENT SELECTED VALUE>;
_prevSelection[cbo] = row;
UpdateOtherCombos(cbo, prev, cbo.SelectedItem.Value);
}
private void UpdateOtherCombos(ComboBox cbo, DataRow prev, object toRemove)
{
foreach(var gridrow in <YourGrid>.Rows)
{
var c = <FIND COMBO IN ROW>;
if(cbo.Id == c.Id) continue;//combo that triggered this all
var itemToRemove=null;
foreach(var item in c.Items)
{
if(item.Value == toRemove)
{
itemToRemove = item;
break;
}
}
//or you can get index of item and remove using index
c.Items.Remove(itemToRemove);
//Now add the item that was previously selected in this combo (that
//triggered this all)
c.Items.Add(new ComboBoxItem{Value = prev["ValueColumn"],
Text = prev ["TextColumn"]});
}
}
This is just to give you an idea that may help you to find an optimal solution rather than iterating over all combos as it will slow down if you have too many rows in grid or too many items in combos. Still even with this you need to put up some functions/code to make it working. Also please note that I have not worked on WinForms for some time and you need to check if things like ComboBoxItem etc. and any functions called on them exist. :)

Related

Get ListView Item Values of row tapped

Get ListView Item Values of row tapped. I am able to get the item tapped in code behind like so:
private async void Item_Tapped(object sender, ItemTappedEventArgs e)
{
ListView listView = (ListView)sender;
if (listView != null)
{
string pName = e.Item //.PNname; **<<-- This is returning my bound values (4 items) as PName, PNumber... and so on**
}
}
I try to type the .PName it is a sub value to the e.Item list but that is invalid. I really need to grab by name because it appears the return selected row item returns values in a random way? One time PName will be first then next it might be 2nd or 3rd?
Anyway what am I missing to grab the values I need?
I'm doing a lot more visual things here but wanted to keep this code very simple to what I am actually having an issue with getting the individual values in the row.
TIA!
Cheers!
Rick...
e.Item is an object (datatype), if I am not mistaken. You have to cast e.Item to the right data type first:
string pName = (e.Item as Person)?.PName;
(assuming that PName is a property of the class Person)
Try get the itemIndex clicked and get the element in the list or use the AutomationId.

Move rows between two sortable DataGrids that use DataTables as sorces

I know this seems like a common problem but I've been searching for quite a while now and I can't find anything that solves my problem.
I have two DataTables and two DataGrids (each DataTable is an ItemSource for a DataGrid). When I double click on a row in any of the DataGrids, the row moves to the other DataGrid. Here is my code for one of the MouseDoubleClick events:
// Predefined stuff:
DataTable sourceDT;
DataTable targetDT;
// This is called when a DataGridRow in a specific DataGrid is double-clicked
private void WorkerRowSource_MouseDoubleClick(object sender, MouseButtonEventArgs e)
{
var rowView = sender as DataGridRow;
var row = sourceDT.Rows[rowView.GetIndex()];
targetDT.ImportRow(row);
sourceDT.Rows.Remove(row);
}
This doesn't work after I sort DataGrid by a column because the line rowView.GetIndex() returns the index of rowView in the sorted DataGrid, while I need rowView's index in an unsorted DataGrid (or in the ItemSource).
An answer from a thread I found earlier today said that using sourceDT.DefaultView.ToTable() would solve this problem, but if I use this I need to replace my DataTables and the DataGrids' ItemSources (doing this also cancels the sorting of the DataGrid).
Am I missing something? Is there a better way of doing this?
I've figured it out but I don't like this solution. My MouseDoubleClick events now look like this:
// Predefined stuff:
DataTable sourceDT;
DataTable targetDT;
DataGrid sourceDAGRI;
private void WorkerRowSource_MouseDoubleClick(object sender, MouseButtonEventArgs e)
{
var rowView = sender as DataGridRow;
var cellContent = sourceDAGRI.Columns[1].GetCellContent(rowView);
int num = int.Parse((cellContent as TextBlock).Text);
DataRow row = null;
foreach (DataRow dRow in sourceDT.Rows)
if ((int)dRow[_numKey] == num)
{
row = dRow;
break;
}
targetDT.ImportRow(row);
sourceDT.Rows.Remove(row);
}
This gets the value of the cells in the DataGridRow and attempts to find a row that has the same Values in the DataTable (so that I dont rely on DataGridRow.GetIndex()).

Adding data only to a specific Column

I'm trying to find a way to add data from one datagrid to another and for that data to be inserted to only one column at a time in my second datagrid. The specific column is created each time the Add button has been clicked.
My coding so far:
private void btnFeedbackAddSupplier_Click(object sender, RoutedEventArgs e)
{
dgFeedbackSelectSupplier.Items.Clear(); //So that my rows do not stack each other on every add
DataGridTextColumn columnSupplier = new DataGridTextColumn();
columnSupplier.Binding = new Binding("Supplier");
DataGridTextColumn columnFeedbackSupplierItem = new DataGridTextColumn();
//The 'Item' column is binded in XAML
columnSupplier.Header = (cmbFeedbackSelectSupplier.SelectedItem as DisplayItems).Name;
columnSupplier.IsReadOnly = true;
dgFeedbackAddCost.SelectAll(); //Selects all the rows in 1st datagrid
//Casts selected rows to my 'ViewQuoteItemList' class
IList list = dgFeedbackAddCost.SelectedItems as IList;
IEnumerable<ViewQuoteItemList> items = list.Cast<ViewQuoteItemList>();
var collection = (from i in items let a = new ViewQuoteItemList { Item = i.Item, Supplier = i.Cost }
select a).ToList();
//Adds both the column and data to the 2nd datagrid
dgFeedbackSelectSupplier.Columns.Add(columnSupplier);
foreach (var item in collection)
dgFeedbackSelectSupplier.Items.Add(item);
}
My reason for wanting to add the data to only one separate column at a time is because the data is different each time I want to add it to my 2nd datagrid and it overwrites any previous data that was entered in older add's.
EDIT: I Here are some images of what my current problem is
Here I add the first company and it's values. Everything works fine
Here I add the second company with it's new values, but it changes the values entered with the first company. This is my big problem. So you can see how my values are changed from the first to the second image
I think your problem here is that all your columns are bound to the same property: Supplier. Since you're updating that property everytime, all columns are assigned the same value. In the end, there's only one Supplier property for each row, so you can't show a different value for that single property on each column since everytime you change that property's value, the Bindings get notified and update themselves.
Maybe you could try using a OneTime Binding instead of a regular one. That way, the cells would retain the value they had when you first added them to the DataGrid. But for that to work, you should avoid clearing the DataGrid's items list, since re-adding the items would force them to rebind again.
Another option would be having a list of suppliers in your Supplier property, and have each column bind to an index of that list.
private void btnFeedbackAddSupplier_Click(object sender, RoutedEventArgs e)
{
// ...
columnSupplier.Binding = new Binding(string.Format("Supplier[{0}]", supplierColumnIndex));
// ...
var supplierCosts = new List<int>();
// ...
// Fill the list with the Costs of the Suppliers that correspond to each column and item
// ...
var collection = (from i in items let a = new ViewQuoteItemList { Item = i.Item, Supplier = supplierCosts }
select a).ToList();
//Adds both the column and data to the 2nd datagrid
dgFeedbackSelectSupplier.Columns.Add(columnSupplier);
foreach (var item in collection)
dgFeedbackSelectSupplier.Items.Add(item);
}

Combobox returns null when value is typed

Sorry if it has some obvious solution, but I am trying to solve it for hours but could not find a solution.
I use several ComboBoxes in my WindowsFormsApplication to relate ids with names. The problem is that when a user select an item from the combobox list, it works fine, but when he types an item, the SelectedValue property of the combobox is null.
To simulate the problem, I created a from with one button and a combobox.
In my actual application, I populate the comboboxes with data from tables in a sqlserver database, but for simplicity, here I populate it with a list:
public Form1()
{
InitializeComponent();
List<KeyValuePair<short,short>> l = new List<KeyValuePair<short,short>>();
l.Add(new KeyValuePair<short,short>(1,10));
l.Add(new KeyValuePair<short,short>(2,20));
l.Add(new KeyValuePair<short,short>(3,30));
this.comboBox1.DataSource = l;
this.comboBox1.DisplayMember = "Value";
this.comboBox1.ValueMember = "Key";
}
private void button1_Click(object sender, EventArgs e)
{
if (this.comboBox1.SelectedValue == null)
MessageBox.Show("NULL");
else
MessageBox.Show(this.comboBox1.SelectedValue.ToString());
}
For example, when user select the second item (20) from the list and clicks on the button, messagebox shows 2 as it is expected, but if he types the number 20 into the combobox, the SelectedValue is null.
This problem could be solved by changing the style of combobox:
this.comboBox1.DropDownStyle = ComboBoxStyle.DropDownList;
But it prevents user to type into the combobox, so I am forced to use the default ComboBoxStyle.DropDown.
Thats because the combo box does not select the item that you have typed. Add this option
comboBox1.AutoCompleteMode = AutoCompleteMode.Suggest;
Then it will select the item when ever it was able to find it.
By default it is set to AutoCompleteMode.None.
(I think) This is mainly designed for suggestions but it can solve your problem here. also if you want to show the suggestions:
comboBox1.AutoCompleteSource = AutoCompleteSource.ListItems;
by default it is set to AutoCompleteSource.None.
https://msdn.microsoft.com/en-us/library/system.windows.forms.combobox.autocompletemode%28v=vs.110%29.aspx
An option that you have is using the EventHandler on the comboBox1.TextChange event that will allow you to personally handle how the text is translated into the different options.
This can be added to the designer (similar to a button).
this.comboBox1.TextChanged += new System.EventHandler(this.UpdateValue);
Then depending on how want to read the results and see if you have a match you can create a converter, use another key/value, or you can do a boring old tryparse as I will show you. You will need the list as a property that you can reference to see if you have found the proper results.
private void UpdateValue(object sender, EventArgs e)
{
short result;
if (short.TryParse(comboBox1.Text, out result))
{
var matches = from val in l where val.Value == result select val.Key;
{
foreach (short m in matches)
this.comboBox1.SelectedValue = m;
}
}
}
Good luck! Let me know if you need more examples with the event handler. Don't forget to vote.

How do I get the selected row data from a data grid view using SelectedRows?

I have a table that I am displaying in a data grid view control. The user selects a single row from the control and presses a button. I need to retrieve the cells from that row and store them as strings.
Exactly how do I get the data using the SelectedRow method? I've been working on this for several hours and I'm at the end of my rope. Here's an example of something I've tried:
DataGridViewCellCollection selRowData = dataGridView1.SelectedRows[0].Cells;
If I try to access selRowData[x], the return value does not contain my data.
You're close - you need to reference each Cell through its index and return its Value property:
string firstCellValue = dataGridView1.SelectedRows[0].Cells[0].Value;
string secondCellValue = dataGridView1.SelectedRows[0].Cells[1].Value;
etc.
If you want the data and the data is likely bound to an datasource, then might I suggest that you get the key from the selection, and then you can use that to access the data any way you like:
dataGridView.SelectedDataKey.Value;
Try using the Item element of the dgv.
dgvFoo.Item(0, dgvFoo.CurrentRow.Index).Value
That would return the value of the first item. You could put that into a for loop to get them all.
Another option would be to use the SelectedRows collection on the object and iterate through each selected row (or just the one in your case).
Well there is no datagridview Item property..#Jay Riggs solution is better...Following solution also works:
string firstCellValue = dataGridView1[0,dataGridView1.CurrentRow.Index].Value.ToString();
string secondCellValue = dataGridView1[0,dataGridView1.CurrentRow.Index].Value.ToString();
Here 0 is the first column and dataGridView1.CurrentRow.Index is the current Row from where to get value.
Perhaps this is a more suitable solution use the cell values of the row clicked:
private void dataGridView1_CellClick(object sender, DataGridViewCellEventArgs e)
{
if (e.RowIndex > -1)
{
var val = this.dataGridView1[e.ColumnIndex, e.RowIndex].Value.ToString();
}
}

Categories