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;
};
// ...
Related
I created a data model for DataGridView and inside this model there is List<T> property. But DataGridView doesn't display that List<T> property. It displays other properties but it doesn't display List<T> property.
Here is code:
public partial class Form1 : Form
{
List<NotModeli> Notlar;
public Form1()
{
Notlar = new List<NotModeli>()
{
new NotModeli()
{
dersAdi = "Hukuk",
vizeNotu = 78,
araSinav = new List<int>{50},
finalNotu = 98
}
};
InitializeComponent();
veriPaneli.DataSource = Notlar;
}
}
public class NotModeli
{
public string dersAdi { get; set; }
public int vizeNotu { get; set; }
public List<int> araSinav { get; set; }
public int finalNotu { get; set; }
}
If you want to join the elements of the list and display them in one cell, a simple way to go about this would be to create a read-only property that returns the joined elements as string. Your class would look something like this:
public class NotModeli
{
public string dersAdi { get; set; }
public int vizeNotu { get; set; }
public List<int> araSinav { get; set; }
public int finalNotu { get; set; }
[DisplayName("araSinav")]
public string JoinedAraSinav => string.Join(",", araSinav);
}
Now, since we're dealing with numbers, joining them with a comma might not look good. We can use a similar approach to display them in the form of a table (still inside one cell).
First, configure your DataGridView as follows: (you can do that manually using the designer)
veriPaneli.AutoGenerateColumns = false;
var dersAdiCol = new DataGridViewTextBoxColumn()
{
HeaderText = "dersAdi",
DataPropertyName = "dersAdi"
};
var vizeNotuCol = new DataGridViewTextBoxColumn()
{
HeaderText = "vizeNotu",
DataPropertyName = "vizeNotu"
};
var araSinavCol = new DataGridViewTextBoxColumn()
{
HeaderText = "araSinav",
DataPropertyName = "JoinedAraSinav",
Width = 220
};
araSinavCol.DefaultCellStyle.Font =
new Font("Consolas", veriPaneli.Font.Size, veriPaneli.Font.Style);
var finalNotuCol = new DataGridViewTextBoxColumn()
{
HeaderText = "finalNotu",
DataPropertyName = "finalNotu"
};
veriPaneli.Columns.AddRange(dersAdiCol, vizeNotuCol, araSinavCol, finalNotuCol);
Then, change the JoinedAraSinav property to something like the following:
[DisplayName("araSinav")]
public string JoinedAraSinav =>
string.Join(" | ", araSinav.Select(i => i.ToString("00000")));
// ^^^^^
// The number of zeros controls the padding of the displayed numbers.
End result:
I need to set a DataGridView based on two classes, as follows
public class Selection
{
public string Display { get; protected set; }
public int Value { get; protected set; }
public Selection( string d, int v)
{
Display = d; Value = v;
}
}
public class TestData
{
public Selection Selection { get; protected set; }
public int Quantity { get; protected set; }
public TestData( Selection sel, int q)
{
Selection = sel;
Quantity = q;
}
}
The TestData objects are the rows. The user must choose a Selection from a ComboBox column populated from a List or something alike.
But the TestData collection must be a BindingList to allow adding or deleting rows, and as such, is the datagrid DataSource.
Until now, I´m trying to set de grid with the following code
List<Selection> getSelectionList()
{
List<Selection> result = new List<Selection>();
result.Add(new Selection("Zero", 0));
result.Add(new Selection("One", 10));
result.Add(new Selection("Two", 20));
result.Add(new Selection("Three", 30));
result.Add(new Selection("Four", 40));
result.Add(new Selection("Five", 50));
result.Add(new Selection("Six", 60));
return result;
}
List<TestData> getTestDataList(List<Selection> reference)
{
List<TestData> result = new List<TestData>();
result.Add(new TestData(reference[1], 10));
return result;
}
................
DataGridViewComboBoxColumn combo = (DataGridViewComboBoxColumn)dataGridView1.Columns[0];
List<Selection> list = getSelectionList();
combo.DataSource = list;
combo.DisplayMember = "Display";
combo.ValueMember = "Value";
BindingList<TestData> source = new BindingList<TestData>(getTestDataList(list)) { AllowEdit = true, AllowNew = true, AllowRemove = true };
dataGridView1.DataSource = source;
................
but the result is annoying:
a) The grid shows two rows (even if I set only one element in the TestData list)
b) The combo cells have no data in them.
How can I solve this?
TIA
You just need to add two lines:
string key = ((KeyValuePair<string, string>)combo.SelectedItem).Key;
string value = ((KeyValuePair<string, string>)combo.SelectedItem).Value;
I have a Dictionary with multiple values that I want to use to populate a listview.
I get an "ArgumentOutOfRangeException was unhandled" and "invalidArgument=Value of '1' is not valid for 'index'.
here is what I hope is enough of the revelant code:
public partial class frmResultList : Form
{
public class MyLookupCustList
{
public string sEstNum { get; set; }
public string sLName { get; set; }
public string sFName { get; set; }
public string sCity { get; set; }
}
public frmResultList(int iMyCount, Dictionary<string, frmResultList.MyLookupCustList> MyDictList)
{
InitializeComponent();
fillListView(iMyCount, MyDictList);
}
public void fillListView(int iMyCount, Dictionary<string, frmResultList.MyLookupCustList> MyDictList)
{
listView1.Clear();
ListViewItem item;
for (int i = 0; i < iMyCount; i++)
{
listView1.Items.Clear();
var o = MyDictList[i.ToString()];
var myListViewItem = new ListViewItem();
myListViewItem = this.listView1.Items.Add(i.ToString());
myListViewItem.SubItems[1].Text = o.sEstNum;
myListViewItem.SubItems[2].Text = o.sLName;
myListViewItem.SubItems[3].Text = o.sFName;
myListViewItem.SubItems[4].Text = o.sCity;
listView1.Items.Add(myListViewItem);
}
listView1.View = View.Details;
listView1.Show();
listView1.Refresh();
}
I get the exception when I try to insert the first SubItem
Here ===> myListViewItem.SubItems[1].Text = o.sEstNum;
please help, what do I need to fix this?
you are trying to update item with index [1], that item doesn't exist yet, you need to create it first. Same will happen for your sub items that you are trying to access - 2, 3, 4
So you need to have logic to check whether the item exists first, if it does update it, otherwise add it.
I have a list of dates (currently there are 4000 in the selected result)
I am trying to put the results in a chart,
The Class looks like this
public class DisplayObjectDates
{
public int Month { get; set; }
public int Year { get; set; }
public int day { get; set; }
public DateTime fulldatetime { get; set; }
public int CountedDate { get; set; }
}
I have a list of the class
private static List<DisplayObjectDates> SortedDatesDays = new List<DisplayObjectDates>();
and I add to the list like this after calling from EF and getting a returned list
if (SortedDatesDays.Count() == 0)
{
var addDisplayObjectDatesYear = new DisplayObjectDates();
addDisplayObjectDatesYear.Year = contextreturned.change_time.Year;
addDisplayObjectDatesYear.Month = contextreturned.change_time.Month;
addDisplayObjectDatesYear.day = contextreturned.change_time.Day;
addDisplayObjectDatesYear.fulldatetime = contextreturned.change_time;
addDisplayObjectDatesYear.CountedDate = 1;
SortedDatesDays.Add(addDisplayObjectDatesYear);
}
else
{
foreach (var VARIABLE in SortedDatesDays)
{
if (VARIABLE.day == contextreturned.change_time.Day && VARIABLE.Month == contextreturned.change_time.Month && VARIABLE.Year == contextreturned.change_time.Year)
{
VARIABLE.CountedDate = VARIABLE.CountedDate++;
}
else
{
var addDisplayObjectDatesYear = new DisplayObjectDates();
addDisplayObjectDatesYear.Year = contextreturned.change_time.Year;
addDisplayObjectDatesYear.Month = contextreturned.change_time.Month;
addDisplayObjectDatesYear.day = contextreturned.change_time.Day;
addDisplayObjectDatesYear.fulldatetime = contextreturned.change_time;
addDisplayObjectDatesYear.CountedDate = 1;
SortedDatesDays.Add(addDisplayObjectDatesYear);
}
}
}
This gives me an error
Collection was modified; enumeration operation may not execute.
so I change the
foreach (var VARIABLE in SortedDatesDays)
to
foreach (var VARIABLE in SortedDatesDays.ToList())
and now i get out of memory exeption
At the end of the day I need to count how many times an event happened on a certain date
I need to put this into a form that i can then use in a chart (DEVEXPRESS)
I am not sure if i should use linq or the current system.
All out of ideas any help with the corrent way in doing this would be greatly appreciated
thanks
a0011010011
I actually thought that foreach (var VARIABLE in SortedDatesDays.ToArray()) will solve the problem as I use it often.
In that case, try the following.
...
else
{
// create a temporary collection for storing new items
var list = new List<DisplayObjectDates>();
foreach (var VARIABLE in SortedDatesDays)
{
if (...) { ... }
else
{
var addDisplayObjectDatesYear = new DisplayObjectDates();
...
// place it to the new list instead
list.Add(addDisplayObjectDatesYear);
}
}
// merge lists
SortedDatesDays.AddRange(list);
}
While you are assigning FullDateTime DisplayObjectDates object ... I prefer to say you to reconstruct your class it may be something like this ... it also help your program to use less memery ..
public class DisplayObjectDates
{
public int Month { get { return fulldatetime.Month; } }
public int Year { get { return fulldatetime.Year; } }
public int day { get { return fulldatetime.Day; } }
public DateTime fulldatetime { get; set; }
public int CountedDate { get; set; }
}
Then sort your initializing function
if (SortedDatesDays.Count() == 0)
{
var addDisplayObjectDatesYear = new DisplayObjectDates();
addDisplayObjectDatesYear.fulldatetime = contextreturned.change_time;
addDisplayObjectDatesYear.CountedDate = 1;
SortedDatesDays.Add(addDisplayObjectDatesYear);
}
else
{
foreach (var VARIABLE in SortedDatesDays)
{
if (VARIABLE.fulldatetime.Date == contextreturned.change_time.fulldatetime.Date)
{
VARIABLE.CountedDate = VARIABLE.CountedDate++;
}
else
{
var addDisplayObjectDatesYear = new DisplayObjectDates();
addDisplayObjectDatesYear.fulldatetime = contextreturned.change_time;
addDisplayObjectDatesYear.CountedDate = 1;
SortedDatesDays.Add(addDisplayObjectDatesYear);
}
}
}
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; }
}
}