Remove duplicate values in list box - c#

I have a list box and I bind it to my table Position and display the column Position. I inserted 2 values w/ the same position in my table and my list box displays 2 of the same values that i inserted. So, can you help me display only one of the same value in my list box?
i only have this code so far:
private void listBox1_SelectedIndexChanged(object sender, EventArgs e)
{
try
{
string select;
select = listBox1.SelectedValue.ToString();
dataGridView1.DataSource = this.mAINDATABASEDataSet.tblPosition.Select("Position like '%" + select + "%'");
int numRows = dataGridView1.Rows.Count;
txtCount.Text = Convert.ToString(numRows);
txtSearchCategory.Text = select.ToString();
try
{
MAINDATABASEDataSet.tblCategorizationDataTable GetCategoryCommand1 = GetCategoryData(this.txtSearchCategory.Text.Trim());
MAINDATABASEDataSet.tblCategorizationRow GetCategoryCommand2 = (MAINDATABASEDataSet.tblCategorizationRow)GetCategoryCommand1.Rows[0];
this.txtSG.Text = GetCategoryCommand2.SalaryGrade.ToString();
this.txtMales.Text = GetCategoryCommand2.Male.ToString();
this.txtFemales.Text = GetCategoryCommand2.Female.ToString();
}
catch
{
MessageBox.Show("This Position is not saved yet!", "Information".ToUpper(), MessageBoxButtons.OK, MessageBoxIcon.Information, MessageBoxDefaultButton.Button1);
txtSG.Text = "";
txtMales.Text = "";
txtFemales.Text = "";
}
}
catch
{
return;
}
}

You can do this by selecting distinct in LINQ. Try this for your data source:
dataGridView1.DataSource = this.mAINDATABASEDataSet
.GroupBy(i => i.Position)
.Select(i => i.First())
.Where(i => i.Position.Contains(select));
include using System.Linq; namespace in your project or reference it. Let me know if this works for you.

Related

Multiple combo boxes to query a data table issue

I'm putting together a project that has a form to fill out which then populates a query from a separate data table. It will always only grab one row based on the inputs, which is then used for a price calculation. I have two places in the code using the same setup. The first one uses a single combo box for the query and it works great, but the second part uses two combo boxes to make an "AND" query and I can't figure out why it isn't working, it doesn't seem to recognize the selections and place them into the calculation. Below is the code for that part, any help would be appreciated!
private void plant_AmountTextBox_TextChanged(object sender, TextChangedEventArgs e)
{
try
{
plantamountResult = Convert.ToDecimal(plant_AmountTextBox.Text);
}
catch (Exception)
{
MessageBox.Show("Please enter a valid amount");
}
try
{
DataRowView rowviewpml = material_NameComboBox.SelectedItem as DataRowView;
materialNameSelection = "";
if (rowviewpml != null)
{
materialNameSelection = rowviewpml.Row["Material_Species"] as string;
}
DataRowView rowviewst = stockComboBox.SelectedItem as DataRowView;
stockSelection = "";
if (rowviewst != null)
{
stockSelection = rowviewst.Row["Stock_Type"] as string;
}
string mcSearch = "Material_Species = '" + materialNameSelection + "' AND Stock_Type = '" + stockSelection + "'";
Plant_Material_PricingTableAdapter pmpTA = new Plant_Material_PricingTableAdapter();
DataTable pmpDT = pmpTA.GetData();
DataRow[] pmpRow = pmpDT.Select(mcSearch);
foreach(DataRow row in pmpRow)
{
materialEstCost = Convert.ToDouble(pmpRow[0]["Previous_FY_Quotes"]);
}
plantestCostCalc.Text = "$" + ((decimal)materialEstCost * plantamountResult).ToString();
}
catch
{
plantestCostCalc.Text = "0";
}
}

C# Filter DataGridView with the Values of Array

i want to know how i can search with the BindinSource.Filter. I have my Code like this Suche.Filter = string.Format("{0} = '{1}'", "ID", ergebnis); ergebnis is my Array with all the ID's of my Contacts. Now i want to Show all Contacts with the same ID in the DGV
This is how I solved it:
private void filter(int selectedID) {
DataTable dtFilter = new DataTable();
//speichere GridView zum Filtern
dtFilter = (DataTable)this.grdMDT.DataSource;
try {
dtFilter = dtFilter.Select("ID = " + selectedID).CopyToDataTable();
this.DGV.DataSource = dtFilter;
}
catch (Exception ex) {
MessageBox.Show(ex.Message);
}
}
I simply copy the contents of the DataGridViewto a new DataTable and use Select to get all the results I need. I then set a new DataSource for the GridView.
You may want to store the original contents of the GridView in a seperate DataTable to clear the filter results.
Of course, you'd need to do this outside of the for-loop.
I found a result for my Code, thanks Guys!
try
{
int[] ergebnis = new int[20];
var filterString = new List<string>();
for (int i = 1; i < result.Length; i++)
{
int j = Int32.Parse(result[i][12]);
ergebnis[i] = j;
filterString.Add(string.Format("{0} = '{1}'", "ID", j));
}
Suche.Filter = string.Join(" OR ", filterString);
kitba();
}
catch (IndexOutOfRangeException ex)
{
Debug.WriteLine(ex);
}
You can apply a filter by getting the view and making your array an array of objects
ICollectionView view = CollectionViewSource.GetDefaultView(yourdatagridview);
view.Filter = FilterPerItem;
yourdatagridview.ItemsSource = view;
In FilterPerItem you add the filter logic
private bool FilterPerItem(Contact item)
{
int rightID = 1;
if (item.ID == rightID)
{
return true;
}
else return false;
}

WPF with datagrid to delete selected items

I have a Datagrid that get filled from a SQLite table
Connect();
mAdapter = new SQLiteDataAdapter("SELECT * FROM clients", mConn);
mTable = new DataTable();
mAdapter.Fill(mTable);
dataGrid.ItemsSource = mTable.DefaultView;
mConn.Close();
I can make it delete an selecteditem but how can I make it delete selecteditems based on their id
private void dataGrid_PreviewKeyDown(object sender, System.Windows.Input.KeyEventArgs e)
{
if (e.Key == System.Windows.Input.Key.Delete)
{
if (dataGrid.SelectedItem == null)
return;
DataRowView rowView = (DataRowView)dataGrid.SelectedItem;
Connect();
using (SQLiteCommand mCmd = new SQLiteCommand("DELETE FROM clients WHERE ID=" + rowView["ID"], mConn))
{
mCmd.ExecuteNonQuery();
}
mAdapter.Update(mTable);
mConn.Close();
}
}
Looks like you want to use raw query to delete the items. In this case to access the selected items on the DataGrid, you use the property SelectedItems. You can either delete each one with 1 query or a block of items in 1 query, here is the code to delete each one using 1 query:
if (e.Key == System.Windows.Input.Key.Delete) {
if (dataGrid.SelectedItem == null)
return;
Connect();
foreach(var item in dataGrid.SelectedItems.Cast<DataRowView>()) {
using (var mCmd = new SQLiteCommand("DELETE FROM clients WHERE ID=" + item["ID"], mConn)) {
mCmd.ExecuteNonQuery();
}
}
mAdapter.Update(mTable);
mConn.Close();
}
Here is the code to delete a block of items with 1 query:
if (e.Key == System.Windows.Input.Key.Delete) {
if (dataGrid.SelectedItem == null)
return;
Connect();
const int blockSize = 100;
var inOperands = dataGrid.SelectedItems
.Select((e,i) => new {
row = ((DataRowView) e)["ID"], i
})
.GroupBy(e => e.i / blockSize)
.Select(g => string.Format("({0})",
string.Join(",", g.Select(o => o.row))));
foreach(var inOperand in inOperands) {
using (var mCmd = new SQLiteCommand("DELETE FROM clients WHERE ID IN " + inOperand, mConn)) {
mCmd.ExecuteNonQuery();
}
}
mAdapter.Update(mTable);
mConn.Close();
}
By the way you should use SQLiteParameter rather than concatenate the values manually to avoid query injection.
As user2946329 said your code should work. I think if you need to delete multiple items you need more buttons and you have to set each button to delete through separate variables or you can loop through them via the actual sql data e.g.
string a = select name, from tbl where name = "Ahmed"
string b = select name, from tbl where name = "Ahmed"etc)
then just
SQLiteCommand mCmd = new SQLiteCommand("DELETE FROM clients WHERE ID=" + a + b, mConn))
{
mCmd.ExecuteNonQuery();
}

data not being save with crlf so it's all one line

I am using a varchar(max) in a column of datatable. I am then populating my datagridview with the query.
Everything is going fine getting the data to the dgv. The problem is my crlf are not displaying correctly in the datagridview.
It is displaying all as one line of text.
For example:
Starting GetWebsiteSettings.
Starting GetTokenShowHideSettings.
End GetTokenShowHideSettings.
End GetWebsiteSettings.
Is displaying as
Starting GetWebsiteSettings.Starting GetTokenShowHideSettings.End GetTokenShowHideSettings.End GetWebsiteSettings.
This is how I am populating the dgv:
private void button_Search_Click(object sender, EventArgs e)
{
using (var model = new SuburbanPortalEntities())
{
var qry = from logs in model.Logs
select logs;
Guid corpid;
if (Guid.TryParse(textBox_CorporationGuid.Text, out corpid))
{
qry = qry.Where(x => x.CorporationId == corpid);
}
Guid tokenid;
if (Guid.TryParse(textBox_TokenId.Text, out tokenid))
{
qry = qry.Where(x => x.TokenId == tokenid);
}
if (checkBox_DisplayErrors.Checked)
{
qry = qry.Where(x => x.IsException);
}
if (checkBox_DisplayWarnings.Checked)
{
qry = qry.Where(x => x.IsWarning);
}
qry = qry.OrderBy(x => x.LogDateTime);
dataGridView1.DataSource = qry;
dataGridView1.Columns["LogId"].Visible = false;
dataGridView1.Columns["ClientHeaders"].Visible = false;
dataGridView1.Columns["SourceId"].Visible = false;
}
}
How do I get the datagridview to display the text correctly?
I found this post
dataGridView1.Columns["Message"].DefaultCellStyle.WrapMode =
DataGridViewTriState.True;

How to enable DataGridView sorting when user clicks on the column header?

I have a datagridview on my form and I populate it with this:
dataGridView1.DataSource = students.Select(s => new { ID = s.StudentId, RUDE = s.RUDE, Nombre = s.Name, Apellidos = s.LastNameFather + " " + s.LastNameMother, Nacido = s.DateOfBirth })
.OrderBy(s => s.Apellidos)
.ToList();
Now, I use the s.Apellidos as the default sort, but I'd also like to allow users to sort when clicking on the column header.
This sort will not modify the data in any way, it's just a client side bonus to allow for easier searching for information when scanning the screen with their eyes.
Thanks for the suggestions.
Set all the column's (which can be sortable by users) SortMode property to Automatic
dataGridView1.DataSource = students.Select(s => new { ID = s.StudentId, RUDE = s.RUDE, Nombre = s.Name, Apellidos = s.LastNameFather + " " + s.LastNameMother, Nacido = s.DateOfBirth })
.OrderBy(s => s.Apellidos)
.ToList();
foreach(DataGridViewColumn column in dataGridView1.Columns)
{
column.SortMode = DataGridViewColumnSortMode.Automatic;
}
Edit: As your datagridview is bound with a linq query, it will not be sorted. So please go through this [404 dead link, see next section] which explains how to create a sortable binding list and to then feed it as datasource to datagridview.
Code as recovered from dead link
Link from above is 404-dead. I recovered the code from the Internet Wayback Machine archive of the page.
public Form1()
{
InitializeComponent();
SortableBindingList<person> persons = new SortableBindingList<person>();
persons.Add(new Person(1, "timvw", new DateTime(1980, 04, 30)));
persons.Add(new Person(2, "John Doe", DateTime.Now));
this.dataGridView1.AutoGenerateColumns = false;
this.ColumnId.DataPropertyName = "Id";
this.ColumnName.DataPropertyName = "Name";
this.ColumnBirthday.DataPropertyName = "Birthday";
this.dataGridView1.DataSource = persons;
}
As Niraj suggested, use a SortableBindingList. I've used this very successfully with the DataGridView.
Here's a link to the updated code I used - Presenting the SortableBindingList - Take Two - archive
Just add the two source files to your project, and you'll be in business.
Source is in SortableBindingList.zip - 404 dead link
One more way to do this is using "System.Linq.Dynamic" library. You can get this library from Nuget. No need of any custom implementations or sortable List :)
using System.Linq.Dynamic;
private bool sortAscending = false;
private void dataGridView_ColumnHeaderMouseClick ( object sender, DataGridViewCellMouseEventArgs e )
{
if ( sortAscending )
dataGridView.DataSource = list.OrderBy ( dataGridView.Columns [ e.ColumnIndex ].DataPropertyName ).ToList ( );
else
dataGridView.DataSource = list.OrderBy ( dataGridView.Columns [ e.ColumnIndex ].DataPropertyName ).Reverse ( ).ToList ( );
sortAscending = !sortAscending;
}
You don't need to create a binding datasource. If you want to apply sorting for all of your columns, here is a more generic solution of mine;
private int _previousIndex;
private bool _sortDirection;
private void gridView_ColumnHeaderMouseClick(object sender, DataGridViewCellMouseEventArgs e)
{
if (e.ColumnIndex == _previousIndex)
_sortDirection ^= true; // toggle direction
gridView.DataSource = SortData(
(List<MainGridViewModel>)gridReview.DataSource, gridReview.Columns[e.ColumnIndex].Name, _sortDirection);
_previousIndex = e.ColumnIndex;
}
public List<MainGridViewModel> SortData(List<MainGridViewModel> list, string column, bool ascending)
{
return ascending ?
list.OrderBy(_ => _.GetType().GetProperty(column).GetValue(_)).ToList() :
list.OrderByDescending(_ => _.GetType().GetProperty(column).GetValue(_)).ToList();
}
Make sure you subscribe your data grid to the event ColumnHeaderMouseClick. When the user clicks on the column it will sort by descending. If the same column header is clicked again, sorting will be applied by ascending.
your data grid needs to be bound to a sortable list in the first place.
Create this event handler:
void MakeColumnsSortable_DataBindingComplete(object sender, DataGridViewBindingCompleteEventArgs e)
{
//Add this as an event on DataBindingComplete
DataGridView dataGridView = sender as DataGridView;
if (dataGridView == null)
{
var ex = new InvalidOperationException("This event is for a DataGridView type senders only.");
ex.Data.Add("Sender type", sender.GetType().Name);
throw ex;
}
foreach (DataGridViewColumn column in dataGridView.Columns)
column.SortMode = DataGridViewColumnSortMode.Automatic;
}
And initialize the event of each of your datragrids like this:
dataGridView1.DataBindingComplete += MakeColumnsSortable_DataBindingComplete;
You can use DataGridViewColoumnHeaderMouseClick event like this :
Private string order = String.Empty;
private void dgvDepartment_ColumnHeaderMouseClick(object sender, DataGridViewCellMouseEventArgs e)
{
if (order == "d")
{
order = "a";
dataGridView1.DataSource = students.Select(s => new { ID = s.StudentId, RUDE = s.RUDE, Nombre = s.Name, Apellidos = s.LastNameFather + " " + s.LastNameMother, Nacido = s.DateOfBirth }) .OrderBy(s => s.Apellidos).ToList();
}
else
{
order = "d";
dataGridView1.DataSource = students.Select(s => new { ID = s.StudentId, RUDE = s.RUDE, Nombre = s.Name, Apellidos = s.LastNameFather + " " + s.LastNameMother, Nacido = s.DateOfBirth }.OrderByDescending(s => s.Apellidos) .ToList()
}
}
there is quite simply solution when using Entity Framework (version 6 in this case). I'm not sure but it seems to ObservableCollectionExtensions.ToBindingList<T> method returns implementation of sortable binding list. I haven't found source code to confirm this supposition but object returning from this method works with DataGridView very well especially when sorting columns by clicking on its headers.
The code is very simply and relies only on .net and entity framework classes:
using System.Data.Entity;
IEnumerable<Item> items = MethodCreatingItems();
var observableItems = new System.Collections.ObjectModel.ObservableCollection<Item>(items);
System.ComponentModel.BindingList<Item> source = observableItems.ToBindingList();
MyDataGridView.DataSource = source;
put this line in your windows form (on load or better in a public method like "binddata" ):
//
// bind the data and make the grid sortable
//
this.datagridview1.MakeSortable( myenumerablecollection );
Put this code in a file called DataGridViewExtensions.cs (or similar)
// MakeSortable extension.
// this will make any enumerable collection sortable on a datagrid view.
//
// BEGIN MAKESORTABLE - Mark A. Lloyd
//
// Enables sort on all cols of a DatagridView
//
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
public static class DataGridViewExtensions
{
public static void MakeSortable<T>(
this DataGridView dataGridView,
IEnumerable<T> dataSource,
SortOrder defaultSort = SortOrder.Ascending,
SortOrder initialSort = SortOrder.None)
{
var sortProviderDictionary = new Dictionary<int, Func<SortOrder, IEnumerable<T>>>();
var previousSortOrderDictionary = new Dictionary<int, SortOrder>();
var itemType = typeof(T);
dataGridView.DataSource = dataSource;
foreach (DataGridViewColumn c in dataGridView.Columns)
{
object Provider(T info) => itemType.GetProperty(c.Name)?.GetValue(info);
sortProviderDictionary[c.Index] = so => so != defaultSort ?
dataSource.OrderByDescending<T, object>(Provider) :
dataSource.OrderBy<T,object>(Provider);
previousSortOrderDictionary[c.Index] = initialSort;
}
async Task DoSort(int index)
{
switch (previousSortOrderDictionary[index])
{
case SortOrder.Ascending:
previousSortOrderDictionary[index] = SortOrder.Descending;
break;
case SortOrder.None:
case SortOrder.Descending:
previousSortOrderDictionary[index] = SortOrder.Ascending;
break;
default:
throw new ArgumentOutOfRangeException();
}
IEnumerable<T> sorted = null;
dataGridView.Cursor = Cursors.WaitCursor;
dataGridView.Enabled = false;
await Task.Run(() => sorted = sortProviderDictionary[index](previousSortOrderDictionary[index]).ToList());
dataGridView.DataSource = sorted;
dataGridView.Enabled = true;
dataGridView.Cursor = Cursors.Default;
}
dataGridView.ColumnHeaderMouseClick+= (object sender, DataGridViewCellMouseEventArgs e) => DoSort(index: e.ColumnIndex);
}
}
KISS : Keep it simple, stupid
Way A:
Implement an own SortableBindingList class when like to use DataBinding and sorting.
Way B:
Use a List<string> sorting works also but does not work with DataBinding.
I suggest using a DataTable.DefaultView as a DataSource. Then the line below.
foreach (DataGridViewColumn column in gridview.Columns)
{
column.SortMode = DataGridViewColumnSortMode.Automatic;
}
After that the gridview itself will manage sorting(Ascending or Descending is supported.)
If you get an error message like
An unhandled exception of type 'System.NullReferenceException'
occurred in System.Windows.Forms.dll
if you work with SortableBindingList, your code probably uses some loops over DataGridView rows and also try to access the empty last row! (BindingSource = null)
If you don't need to allow the user to add new rows directly in the DataGridView this line of code easily solve the issue:
InitializeComponent();
m_dataGridView.AllowUserToAddRows = false; // after components initialized
...
Create a class which contains all properties you need, and populate them in the constructor
class Student
{
int _StudentId;
public int StudentId {get;}
string _Name;
public string Name {get;}
...
public Student(int studentId, string name ...)
{ _StudentId = studentId; _Name = name; ... }
}
Create an IComparer < Student > class, to be able to sort
class StudentSorter : IComparer<Student>
{
public enum SField {StudentId, Name ... }
SField _sField; SortOrder _sortOrder;
public StudentSorder(SField field, SortOrder order)
{ _sField = field; _sortOrder = order;}
public int Compare(Student x, Student y)
{
if (_SortOrder == SortOrder.Descending)
{
Student tmp = x;
x = y;
y = tmp;
}
if (x == null || y == null)
return 0;
int result = 0;
switch (_sField)
{
case SField.StudentId:
result = x.StudentId.CompareTo(y.StudentId);
break;
case SField.Name:
result = x.Name.CompareTo(y.Name);
break;
...
}
return result;
}
}
Within the form containing the datagrid add
ListDictionary sortOrderLD = new ListDictionary(); //if less than 10 columns
private SortOrder SetOrderDirection(string column)
{
if (sortOrderLD.Contains(column))
{
sortOrderLD[column] = (SortOrder)sortOrderLD[column] == SortOrder.Ascending ? SortOrder.Descending : SortOrder.Ascending;
}
else
{
sortOrderLD.Add(column, SortOrder.Ascending);
}
return (SortOrder)sortOrderLD[column];
}
Within datagridview_ColumnHeaderMouseClick event handler do something like this
private void dgv_ColumnHeaderMouseClick(object sender, DataGridViewCellMouseEventArgs e)
{
StudentSorter sorter = null;
string column = dGV.Columns[e.ColumnIndex].DataPropertyName; //Use column name if you set it
if (column == "StudentId")
{
sorter = new StudentSorter(StudentSorter.SField.StudentId, SetOrderDirection(column));
}
else if (column == "Name")
{
sorter = new StudentSorter(StudentSorter.SField.Name, SetOrderDirection(column));
}
...
List<Student> lstFD = datagridview.DataSource as List<Student>;
lstFD.Sort(sorter);
datagridview.DataSource = lstFD;
datagridview.Refresh();
}
Hope this helps
Just in case somebody still looks for it, I did it on VS 2008 C#.
On the Event ColumnHeaderMouseClick, add a databinding for the gridview, and send the order by field like a parameter. You can get the clicked field as follows:
dgView.Columns[e.ColumnIndex].Name
In my case the header's names are similar to view field names.
I have a BindingList<> object bind as a data source to dataGridView.
BindingList x1;
x1 = new BindingList<sourceObject>();
BindingSource bsx1 = new BindingSource();
bsx1.DataSource = x1;
dataGridView1.DataSource = bsx1;
When I clicked the column header, no sorting takes place.
I used the SortableBindingList answer provided by Tom Bushell.
Having included two source files into my project
SortableBindingList.cs
PropertyComparer.cs
Then this change is made to my code:
Be.Timvw.Framework.ComponentModel.SortableBindingList x1; // 1
x1 = new Be.Timvw.Framework.ComponentModel.SortableBindingList<sourceObject>(); // 2
BindingSource bsx1 = new BindingSource();
bsx1.DataSource = x1;
dataGridView1.DataSource = bsx1;
After these changes I performed a build on my program. I am now able to sort by clicking the column headers. Only two lines need changing, they are highlighted in the code snippet above by trailing comments.
In my case, the problem was that I had set my DataSource as an object, which is why it didn't get sorted. After changing from object to a DataTable it workd well without any code complement.
If using a DataTable: dgv.DataSource = (DataTable)table
You can automatically enable Sorting for objects that contain the IComparable Interface. After creating the DataTable, when adding the columns be sure to set the type also to at least object:
table.Columns.Add("ColumnName", typeof(object))
Otherwise, if you do Not specifically give it a type, it converts the object to a string.
I spent a fair amount of time creating a dgv_ColumnHeaderMouseClick() event because it was Not sorting the DataGridView correctly, then to find that all you need to do is specify the type for the column name, and it sorts properly. And the reason it was not sorting correctly previously was because without specifying the type for DataTable columns, it will convert objects to strings.
Just instead of passing a list to the datagrid, you store the search result as a datatable.
dataGridView1.DataSource = students
.Select(s => new {
ID = s.StudentId,
RUDE = s.RUDE,
Nombre = s.Name,
Apellidos = s.LastNameFather + " " + s.LastNameMother,
Nacido = s.DateOfBirth })
.OrderBy(s => s.Apellidos)
.ToDataTable();

Categories

Resources