I want to populate my ListBox by a list of objects with properties , and I want to know how to define the listbox to display a certain property within this object which is some text,
and the other is the name of methods to be invoked while the listBox Items are clicked (SelectIndexChanged)
Hope this helps.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
//Create a listbox, with given height/width and top/left
var lstBox = new ListBox
{
Width = 300,
Height = 300,
Top = 10,
Left = 10
};
//Add the listbox to your form
this.Controls.Add(lstBox);
//Create a list of your customclass
var listCustomClass = new List<CustomClass>();
//Populate the list with values
for (int i = 0; i < 50; i++)
{
//create an instanze of your customclass
var customClass = new CustomClass();
//set properties of your class
customClass.Name = "Name " + i;
customClass.Description = "Description " + i;
if (i % 2 == 0)
customClass.MethodName = "CallMeBaby";
else
customClass.MethodName = "CallMeBabyWithParameter";
customClass.RandomProperty1 = "RandomProperty1 " + i;
//add the newly created customclass into your list
listCustomClass.Add(customClass);
}
//set the listbox to display or value what you need
lstBox.DisplayMember = "Description"; //Name of a property inside the class CustomClass
lstBox.ValueMember = "Name"; //Name of a property inside the class CustomClass
//set the datasource
lstBox.DataSource = listCustomClass;
//register the selectedindexchanged event
lstBox.SelectedIndexChanged += lstBox_SelectedIndexChanged;
}
private void lstBox_SelectedIndexChanged(object sender, EventArgs e)
{
//get the listbox from the sender
var lstBox = (sender as ListBox);
if (lstBox != null)
{
//safe cast the selecteditem to your customclass to get full access to any public property with the class definition
var customClass = lstBox.SelectedItem as CustomClass;
if (customClass != null)
{
//do what ever you want with the object and its properties
var name = customClass.Name;
var desription = customClass.Description;
var methodName = customClass.MethodName;
var randomProperty1 = customClass.RandomProperty1;
//call a certain method based on a string within the object
if (methodName == "CallMeBaby")
CallMeBaby();
else if (methodName == "CallMeBabyWithParameter")
CallMeBaby(name);
}
}
}
//declare the methods that are being called
private void CallMeBaby(string value)
{
//Access the parameter and do something
if (value == "HelloWorld!")
{
//Do something...
}
}
//parameterless method to show the possibilities...
private void CallMeBaby()
{
//Do something...
}
//define a public class
public class CustomClass
{
//random properties, can be extended to have what ever your need
public string Name { get; set; }
public string Description { get; set; }
public string MethodName { get; set; }
public string RandomProperty1 { get; set; }
}
}
Related
I am designing a winform in which I have a datagridview with predefined columns, the first column is a combobox and rest 3 columns are textboxes.
I am not binding datagridview to any datasource since the user is going to fill the last column "Qty", all I want to achieve is, when user clicks on the combobox it should show 3 columns from the database table (item code, item name and uom) and when user select any particular "item code" corresponding "item name" and "uom" should be displayed in second column and third column of the datagridview. Likewise the user should be able to enter as many row as he require. After data entry the data will be saved in a table named "purchase requisition".
I have not done any coding so far and have designed only the form.
See if the following will provide base code to roll with. There are several classes to mock up data and a extension method which should be move to own files.
DataGridView was not configured in the designer, just in code.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
namespace UnboundDataGridViewComboBox
{
public partial class Form1 : Form
{
private ComboBox _cbo;
private string _comboColumnName = "ItemCodeColumn";
private List<Item> _items => Mocked.Items;
public Form1()
{
InitializeComponent();
Shown += OnShown;
}
private void OnShown(object sender, EventArgs e)
{
var column1 = new DataGridViewComboBoxColumn
{
DataSource = _items.Select(x => x.ItemCode).ToArray(),
DisplayStyle = DataGridViewComboBoxDisplayStyle.Nothing,
Name = _comboColumnName,
HeaderText = "Item Code",
SortMode = DataGridViewColumnSortMode.NotSortable
};
var column2 = new DataGridViewTextBoxColumn
{
Name = "ItemNameColumn",
HeaderText = "Item Name"
};
var column3 = new DataGridViewTextBoxColumn
{
Name = "UomColumn",
HeaderText = "UOM"
};
var column4 = new DataGridViewTextBoxColumn
{
Name = "QuanityColumn",
HeaderText = "Quanity"
};
ItemsDataGridView.Columns.AddRange(column1, column2, column3, column4);
ItemsDataGridView.EditingControlShowing += DataGridView1OnEditingControlShowing;
}
private void DataGridView1OnEditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e)
{
if (!ItemsDataGridView.CurrentCell.IsComboBoxCell()) return;
if (ItemsDataGridView.Columns[ItemsDataGridView.CurrentCell.ColumnIndex].Name != _comboColumnName) return;
_cbo = e.Control as ComboBox;
_cbo.SelectedIndexChanged -= ItemCodeColumnComboSelectionChanged;
_cbo.SelectedIndexChanged += ItemCodeColumnComboSelectionChanged;
}
private void ItemCodeColumnComboSelectionChanged(object sender, EventArgs e)
{
DataGridViewComboBoxEditingControl control = sender as DataGridViewComboBoxEditingControl;
Item item = _items.FirstOrDefault(x => x.ItemCode == control.EditingControlFormattedValue.ToString());
if (item == null)
{
return;
}
ItemsDataGridView.CurrentRow.Cells[1].Value = item.Name;
ItemsDataGridView.CurrentRow.Cells[2].Value = item.UOM;
}
}
#region Place classes into their own files
public static class Extensions
{
public static bool IsComboBoxCell(this DataGridViewCell sender)
=> sender.EditType != null &&
sender.EditType == typeof(DataGridViewComboBoxEditingControl);
}
// represents a table in a database
public class Item
{
public int Id { get; set; }
public string Name { get; set; }
public string ItemCode { get; set; }
public string UOM { get; set; }
public override string ToString() => ItemCode;
}
class Mocked
{
// simulate data from database
public static List<Item> Items => new List<Item>()
{
new Item() {Id = 1,Name = "P1", ItemCode = "A100", UOM = "Q1"},
new Item() {Id = 2,Name = "P2", ItemCode = "A200", UOM = "W1"},
new Item() {Id = 3,Name = "P3", ItemCode = "A300", UOM = "B1"},
new Item() {Id = 4,Name = "P4", ItemCode = "A400", UOM = "H1"}
};
}
#endregion
}
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 using ObjectListview to display checkboxes for columns but there is a problem.
My model is like this:
public class HocVienLopDTO
{
public HocVienDTO HocVien { get; set; }
public double Diem { get; set; }
public List<NgayHocDTO> DSNgayHoc { get; set; }
}
public class NgayHocDTO
{
public DateTime Ngay { get; set; }
public bool CoHoc { get; set; }
}
I want to create a listview like this: (Diem, DSNgayHoc[0], DSNgayHoc[1], ...). And i want to use checkbox for all the DSNgayHoc column to present value of it's CoHoc property. So i dynamically generate columns like this:
this.lstvDiemDanh.UseSubItemCheckBoxes = true;
List<OLVColumn> colList = new List<OLVColumn>();
for (int i = 0; i < this.lop.DSNgayHoc.Count; i++)
{
OLVColumn col = new OLVColumn();
col.IsHeaderVertical = true;
col.CheckBoxes = true;
col.AspectName = string.Format(string.Format("DSNgayHoc[{0}].CoHoc", i));
col.Text = this.lop.DSNgayHoc[i];
col.Width = 20;
col.IsEditable = true;
colList.Add(col);
}
this.lstvDiemDanh.AllColumns.AddRange(colList);
this.lstvDiemDanh.RebuildColumns();
All the checkbox was displayed fine but their state is not changed when i clicked them. (Always square box). I tried to handle ChangingSubItem event to change the currentValue and newValue but no luck. Please help!
Sorry about my english.
The OLV is using reflection to search for a property with the AspectName name. This won't work in this case, because it does not know that you are accessing a list index.
Instead of using the AspectName
// ...
col.AspectName = string.Format(string.Format("DSNgayHoc[{0}].CoHoc", i));
// ...
you have to use the AspectGetter and AspectPutter callbacks to access the DSNgayHoc list as desired.
// ...
int listIndex = i;
col.AspectGetter = delegate(object rowObject) {
HocVienLopDTO model = rowObject as HocVienLopDTO;
if (model.DSNgayHoc.Count > listIndex)
return model.DSNgayHoc[listIndex].CoHoc;
else
return false;
};
col.AspectPutter = delegate(object rowObject, object value) {
HocVienLopDTO model = rowObject as HocVienLopDTO;
if (model.DSNgayHoc.Count > listIndex)
model.DSNgayHoc[listIndex].CoHoc = (bool)value;
};
// ...
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'm trying to add a person to a list of campers(people). I have bound the ListView(GridView) to the database and it displays all the names, ages, and grades. But now I'm trying to add a new person and add(display) him to the ListView along with everyone else. Any help is greatly appreciated.
Here's what I have: ObservableCollection
class BindingCamper
{ // This class assist in binding campers from listview to the textboxes on the camperspage
public ObservableCollection<Camper> Campers { get; private set; }
public BindingCamper()
{
Campers = new ObservableCollection<Camper>();
}
}
Here is where I add the list of names to the listview:
MainWindow _parentForm;
public ObservableCollection<Camper> Campers { get; private set; }
public CampersPage(MainWindow parent)
{
_parentForm = parent;
InitializeComponent();
var bindMe = new BindingCamper();
for (int i = 0; i < _parentForm.allCampers.Count; i++)
bindMe.Campers.Add(new Camper { Name = "" + _parentForm.allCampers[i].getName(), Ages = _parentForm.allCampers[i].getAge(), SchoolGrade = _parentForm.allCampers[i].getGrade() });
DataContext = bindMe;
Here is where I add a new camper(person) and I'm trying to add him/her to the listview:
String nameMe;
nameMe = txtNewFirstName.Text ;
int age;
int grade;
if (nameMe != "" && IsNumber(txtNewGrade.Text) && IsNumber(txtNewAge.Text))
{
age = Convert.ToInt16(txtNewAge.Text);
grade = Convert.ToInt16(txtNewGrade.Text);
// Create New Camper
Camper person = new Camper(age, grade, nameMe);
_parentForm.allCampers.Add(person);
//_parentForm.camperPage.listViewCampers.Items.Refresh();
var bind = new BindingCamper();
// bind.Campers.Add(new Camper { Name = person.getName(), Ages = person.getAge(), SchoolGrade = person.getGrade() });
// _parentForm.camperPage.Campers.Add(new Camper { Name = person.getName(), Ages = person.getAge(), SchoolGrade = person.getGrade() });
Close();
You shouldn't refresh the database to add camper:
Camper person = new Camper(age, grade, nameMe);
if TryAddToDatabase(person)
{
bindMe.Campers.Add(person);
}
If ListView is bounded to bindMe.Campers it would refresh automatically and show new item. I also would recommend you completely read the WPFTutorial so you won't do any extra work in the future.