I have a ListView which gets data directly from the database. I want to use it to search for a record using any of the variables, i.e. name, number, or location. Currently I am able to search but using only one variable.
This is my code:
public void searchlist()
{
if (searchbox.Text != "")
{
for (int i = listView1.Items.Count - 1; i >= 0; i--)
{
var item = listView1.Items[i];
if (item.Text.Contains(searchbox.Text))
{
item.BackColor = SystemColors.Highlight;
item.ForeColor = SystemColors.HighlightText;
}
else
{
listView1.Items.Remove(item);
}
}
if (listView1.SelectedItems.Count == 1)
{
listView1.Focus();
}
}
else
{
loadthelist();
}
}
Looks like you need this:
private class TestClass
{
public int Id
{
get;
set;
}
public string Text
{
get;
set;
}
public string Detail
{
get;
set;
}
}
private void ListViewSearch_Load(object sender, EventArgs e)
{
List<TestClass> source = new List<TestClass>();
source.Add(new TestClass { Id = 1, Text = "one", Detail = "D1" });
source.Add(new TestClass { Id = 2, Text = "two", Detail = "D2" });
source.Add(new TestClass { Id = 3, Text = "three", Detail = "D1" });
source.Add(new TestClass { Id = 4, Text = "four", Detail = "D3" });
source.Add(new TestClass { Id = 5, Text = "five", Detail = "D6" });
source.Add(new TestClass { Id = 6, Text = "5", Detail = "D6" });
listView1.Columns.Add("Id");
listView1.Columns.Add("Text");
listView1.Columns.Add("Detail");
source.ForEach(x =>
{
ListViewItem item = new ListViewItem(x.Id.ToString());
item.UseItemStyleForSubItems = false;
item.SubItems.Add(x.Text);
item.SubItems.Add(x.Detail);
listView1.Items.Add(item);
});
listView1.View = View.Details;
listView1.GridLines = true;
comboBox1.DataSource = listView1.Columns;
comboBox1.DisplayMember = "Text";
comboBox1.ValueMember = "Text";
}
private void textBox1_Leave(object sender, EventArgs e)
{
if (!string.IsNullOrEmpty(textBox1.Text))
{
foreach (ListViewItem item in listView1.Items)
{
for (int subItemIndex = 0; subItemIndex < item.SubItems.Count; subItemIndex++)
{
if (subItemIndex == comboBox1.SelectedIndex && item.SubItems[subItemIndex].Text.Contains(textBox1.Text))
{
item.SubItems[subItemIndex].BackColor = SystemColors.Highlight;
item.SubItems[subItemIndex].ForeColor = SystemColors.HighlightText;
}
else
{
item.SubItems[subItemIndex].BackColor = Color.Transparent;
item.SubItems[subItemIndex].ForeColor = SystemColors.WindowText;
}
}
}
}
}
Related
I've to show user details in DataGridView with pagination and almost done working with it. The problem is when I use skip and Take in LINQ, it doesn't show any data but without it works as follows:
grdUserDetails.DataSource = aUserDetail; //shows list of user details
grdUserDetails.DataSource = aUserDetail.Skip(startRow).Take(pageSize); //Doesn't show anything
This is the code that I've tried so far:
public int pageSize = 1;
public Users()
{
InitializeComponent();
BindDataGridView(1);
}
private void BindDataGridView(int pageIndex)
{
List<UserDetails> aUserDetail = null;
aUserDetail = GetUserDetails();
totalRecordCount = aUserDetail.Count;
int startRow = pageIndex * pageSize;
grdUserDetails.DataSource = aUserDetail.Skip(startRow).Take(pageSize); //Here is the main issue that I am stuck with
BindPager(totalRecordCount, pageIndex);
}
private void BindPager(int recordCount, int currentPage)
{
double getPageCount = (double)((decimal)totalRecordCount / (decimal)pageSize);
int pageCount = (int)Math.Ceiling(getPageCount);
List<ListItem> lstItem = new List<ListItem>();
if (currentPage > 1)
{
lstItem.Add(new ListItem { Text = "First", Value = "1" });
}
if (currentPage > 1)
{
lstItem.Add(new ListItem { Text = "<<", Value = (currentPage - 1).ToString() });
}
for (int i = 1; i <= recordCount; i++)
{
lstItem.Add(new ListItem { Text = i.ToString(), Value = i.ToString(), Selected = i == currentPage });
}
if (currentPage < pageCount)
{
lstItem.Add(new ListItem { Text = ">>", Value = (currentPage + 1).ToString() });
}
if (currentPage != pageCount)
{
lstItem.Add(new ListItem { Text = "Last", Value = pageCount.ToString() });
}
plPager.Controls.Clear();
int count = 0;
foreach (ListItem lst in lstItem)
{
Button btnPage = new Button();
btnPage.Location = new System.Drawing.Point(38 * count, 6);
btnPage.Size = new System.Drawing.Size(36, 20);
btnPage.Name = lst.Value;
btnPage.Text = lst.Text;
btnPage.Enabled = !lst.Selected;
btnPage.Click += new System.EventHandler(this.ListItem_Click);
plPager.Controls.Add(btnPage);
count++;
}
}
private void ListItem_Click(object sender, EventArgs e)
{
Button btnPager = (sender as Button);
this.BindDataGridView(int.Parse(btnPager.Name));
}
I've used two classes for the WinForm project. One is the UserDetails and another is Page to bind controls dynamically with a Panel:
public class ListItem
{
public string Text { get; set; }
public string Value { get; set; }
public bool Selected { get; set; }
}
public class UserDetails
{
public int Id { get; set; }
public string Name { get; set; }
}
public List<UserDetails> GetUserDetails()
{
List<UserDetails> lst = new List<UserDetails>
{
new UserDetails { Id = 1001, Name = "John" },
new UserDetails { Id = 1001, Name = "Jack" }
};
return lst;
}
Finally in the form, I've DataGridView named grdUserDetails and a panel plPager to show user details and the pagination. I am hoping, it would be a silly mistake and missed something doing so.
Two things.
1) startRow needs to be less by one because of zero-based indexing.
2) Your LINQ needs to be converted to a List<>.
So, try it this way:
grdUserDetails.DataSource = aUserDetail.Skip(startRow - 1).Take(pageSize).ToList();
I'm working in c# with Windows form.
I've an item DataGridView named objGridView, used like this :
public partial class dlgDetailsObj : Form
{
public dlgDetailsObj(myInterface item)
{
InitializeComponent();
objGridView.DataSource = new BindingList<dlgItem>();
var t = new Task(() =>
{
List<dlgItem> listElements = new List<dlgItem>();
if (item is List<Person>)
{
List<Person> list = (List<Person>)item;
foreach (Person person in list)
{
listElements.Add(new dlgItem()
{
Name = person.Name,
Forname = person.Forname
});
}
}
else if (item is List<Compagny>)
{
List<Compagny> list = (List<Compagny>)item;
foreach (Compagny compagny in list)
{
listElements.Add(new dlgItem()
{
Compagny = compagny.Name
});
}
}
else
{
return;
}
foreach (dlgItem item in listElements)
{
objGridView.Invoke((MethodInvoker)delegate
{
int sel = objGridView.GetSelectedRowIndex();
((BindingList<dlgItem>)objGridView.DataSource).Add(item);
objGridView.SetSelectedRowIndex(sel);
});
}
});
t.Start();
}
}
internal class dlgItem
{
public string Name { get; set; }
public String Forname { get; set; }
public String Compagny { get; set; }
}
The class dlgDetailsObj is used to display a list of Persons/Companies and probably more object later.
My DataGridView has a DataSource filled of dlgItem. Actually all three fields are displayed, even if I only only one.
How can I define my code to display columns only if binded fields are not null ?
If you want to hide all empty columns you could iterate through the DataSource collection to determine whether the corresponding property has been set for any dlgItem object:
public dlgDetailsObj(myInterface item)
{
InitializeComponent();
objGridView.DataSource = new BindingList<dlgItem>();
var t = new Task(() =>
{
...
});
t.Start();
t.ContinueWith(task =>
{
bool displayNameColumn = false;
bool displayFornameColumn = false;
bool displayCompanyColumn = false;
foreach (dlgItem item in (BindingList<dlgItem>)objGridView.DataSource)
{
if (!string.IsNullOrEmpty(item.Name))
displayNameColumn = true;
if (!string.IsNullOrEmpty(item.Forname))
displayFornameColumn = true;
if (!string.IsNullOrEmpty(item.Compagny))
displayCompanyColumn = true;
}
objGridView.Columns[0].Visible = displayNameColumn;
objGridView.Columns[1].Visible = displayFornameColumn;
objGridView.Columns[2].Visible = displayCompanyColumn;
}, System.Threading.CancellationToken.None, TaskContinuationOptions.None, TaskScheduler.FromCurrentSynchronizationContext());
}
I have a problem which i'd divide in two steps:
Problem1.
Form an observable collection of strings and bind it to a datagrid
ObservableCollection<string[]> octest = new ObservableCollection<string[]>();
var el = new string[6] {"1","2","3", "4", "5", "6" };
octest.Add(el);
octest.Add(el);
octest.Add(el);
dtgResults.ItemsSource = octest;
the problem is that the binding results in the image below:
Problem 2
The same but now with an array of strings but with mixed elements (e.g. 3 strings and 3 doubles)
thank you
--EDIT-- for CBreeze
I have done that:
ObservableCollection<TestModel> t = new ObservableCollection<TestModel>();
var t1 = new TestModel();
t.Add(t1);
t.Add(t1);
t.Add(t1);
dtgResults.ItemsSource = t;
}
}
public class TestModel
{
public TestModel()
{
TestDouble1 = new string[3];
TestDouble1[0] = "A";
TestDouble1[1] = "B";
TestDouble1[2] = "C";
}
public string[] TestDouble1 { get; set; }
}
and the result is:
from
programmatically add column & rows to WPF Datagrid
you can do that:
string[] columnLabels = new string[] { "Column 0", "Column 1", "Column 2", "Column 3", "Column 4", "Column 5" };
foreach (string label in columnLabels)
{
DataGridTextColumn column = new DataGridTextColumn();
column.Header = label;
column.Binding = new Binding(label.Replace(' ', '_'));
dtgResults.Columns.Add(column);
}
int[] ivalues = new int[] { 0, 1, 2, 3 };
string[] svalues = new string[] { "A", "B", "C", "D" };
dynamic row = new ExpandoObject();
for (int i = 0; i < 6; i++)
{
switch (i)
{
case 0:
case 1:
case 2:
string str = columnLabels[i].Replace(' ', '_');
((IDictionary<String, Object>)row)[str] = ivalues[i];
break;
case 3:
case 4:
case 5:
string str2 = columnLabels[i].Replace(' ', '_');
((IDictionary<String, Object>)row)[str2] = svalues[i - 3];
break;
}
}
dtgResults.Items.Add(row);
Bind your ObservableCollection to a Model;
ObservableCollection<TestModel> octest = new ObservableCollection<TestModel>();
Create your TestModel;
public class TestModel
{
public double TestDouble1 { get; set; }
public double TestDouble2 { get; set; }
public double TestDouble3 { get; set; }
public string TestString1 { get; set; }
public string TestString2 { get; set; }
public string TestString3 { get; set; }
}
You then need to actually create a TestModel....
TestModel newTestModel = new TestModel();
Add new values to TestModel.....
newTestModel.TestString1 = "Hello"
newTestModel.TestString2 = "Hello"
newTestModel.TestString3 = "Hello"
Finally add the new TestModel to the ObservableCollection;
octest.Add(newTestModel);
on WPF on c# i have combobox
<ComboBox x:Name="listCombobox" />
and i add it item like
var list = new[]
{
new { Number = 1, Name = "Smith" },
new { Number = 12, Name = "John" } ,
new { Number = 14, Name = "Bon" }
}.ToList();
foreach (var item in list)
{
listCombobox.Items.Add(item.Name);
}
what i want that on the combobox i will see the Name(like now)
but when i selected , on the code behind i will see not the name i selected
i want to see the Number that selected
thanks!
Define a class like this
public class dataObject
{
public int Number { get; set; }
public string Name { get; set; }
}
And fill the data,
List<dataObject> bindingList = new List<dataObject>();
bindingList.Add(new dataObject()
{
Name = "Smith",
Number = 1
});
bindingList.Add(new dataObject()
{
Name = "John",
Number = 12
});
bindingList.Add(new dataObject()
{
Name = "Bon",
Number = 14
});
listCombobox.ItemsSource = bindingList;
listCombobox.DisplayMemberPath = "Name";
On selectionChanged event of the combobox, do this,
private void listCombobox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
dataObject result = (dataObject)listCombobox.SelectedItem;
var selectedNumber = result.Number;
}
I would use a custom ListItem class and assign objects of this type to the ItemSource property of the combobox control like this:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
var list = new List<ListItem>
{
new ListItem{ Value = 1, Text = "Smith" },
new ListItem{ Value = 12, Text = "John" } ,
new ListItem{ Value = 14, Text = "Bon" }
}.ToList();
listCombobox.ItemsSource = list;
listCombobox.DisplayMemberPath = "Text";
listCombobox.SelectedValuePath = "Value";
}
private void listCombobox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
var selectedItem = (sender as ComboBox).SelectedItem as ListItem;
if (selectedItem != null)
{
// do something with the selected item
}
}
}
public class ListItem
{
public string Text { get; set; }
public int Value { get; set; }
}
I would solve it as follows:
...
foreach (var item in list)
listCombobox.Items.Add(new ComboBoxItem() {
Content = item.Name,
Tag = item.Number
});
You can of course retrieve your Data by using
int mytag = listCombobox.Items[3].Tag;
or
int seletected = listCombobox.SelectedItem.Tag;
MSDN Reference for PresentationFramework.dll::System.Windows.Frameworkelement.Tag
Easiest way, I think, is to put these numbers as Tag of every listCombobox item:
foreach (var item in list) {
listCombobox.Items.Add(new ComboBoxItem { Content = item.Name, Tag = item.Number });
}
And access your number (OnSelectedItemchanged, for example):
void Cb_SelectionChanged(object sender, SelectionChangedEventArgs e) {
int number = (int)((ComboBoxItem) listCombobox.SelectedItem).Tag;
}
I have two DataGridViews,
datagridviewDoses All dishes from DB
datagridviewDoseOrder is empty
I would like as soon as I press the button line from datagridviewDoses.
The line will move to datagridviewDoseOrder.
The buttons I added, I can not move the line to -datagridviewDoseOrder.
private void AddColumn()
{
DataGridViewButtonColumn buttonColumn = new DataGridViewButtonColumn();
buttonColumn.HeaderText = "בחר מנה";
buttonColumn.Name = "בחר מנה";
buttonColumn.Text = "בחר מנה";
buttonColumn.UseColumnTextForButtonValue = true;
dataGridViewDoses.Columns.Add(buttonColumn);
dataGridViewDoses.CellClick += new DataGridViewCellEventHandler(dataGridViewDoses_CellClick);
}
void dataGridViewDoses_CellClick(object sender, DataGridViewCellEventArgs e)
{
}
I was able to recreate your problem and solve it as following:
An example class as the data source for each dgview.
public class Example
{
public string Foo { get; set; }
public string Bar { get; set; }
}
The form displaying two DataGridViews.
public Form1()
{
InitializeComponent();
this.First = new BindingList<Example>()
{
new Example() { Foo = "foo1", Bar = "bar1" },
new Example() { Foo = "foo2", Bar = "bar2" }
};
this.Second = new BindingList<Example>();
this.dataGridView1.DataSource = this.First;
this.dataGridView2.DataSource = this.Second;
DataGridViewButtonColumn btnCol = new DataGridViewButtonColumn();
btnCol.HeaderText = "Transfer";
btnCol.Name = "Transfer";
btnCol.Text = "Transfer";
btnCol.UseColumnTextForButtonValue = true;
this.dataGridView1.Columns.Add(btnCol);
this.dataGridView1.CellClick += new DataGridViewCellEventHandler(col_Click);
}
public BindingList<Example> First { get; set; }
public BindingList<Example> Second { get; set; }
public void col_Click(object sender, DataGridViewCellEventArgs e)
{
if (e.ColumnIndex == 0) // The button column somehow is column 0, Foo is 1, and Bar is 2.
{
this.Second.Clear();
this.Second.Add(this.First[e.RowIndex]);
}
}
By clicking on a button, that row's data is moved over to the second DataGridView. I hope this helps.