I'm trying to populate a DataTreeListView from ObjectListView library using a list. Unfortunately I am unable to achieve it, there is nothing displayed even though there is a count of item inside the List itself.
Class.cs
public class Class
{
protected string xName;
protected int xId;
protected int xParentId;
protected int happinessStatus;
protected int salaryStatus;
public Class()
{
this.xName = "";
this.xId = 0;
this.xParentId = 0;
this.happinessStatus = 0;
this.salaryStatus = 0;
}
public String Name
{
get { return this.xName; }
set { this.xName = value; }
}
public int Id
{
get { return this.xId; }
set { this.xId = value; }
}
public int ParentId
{
get { return this.xParentId; }
set { this.xParentId = value; }
}
public int HappinessStatus
{
get {return this.happinessStatus; }
set { this.happinessStatus = value; }
}
public int SalaryStatus
{
get { return this.salaryStatus; }
set { this.salaryStatus = value; }
}
public static List<Class> GetList()
{
List<Class> oList = new List<Class>();
Class oClass = new Class();
oClass.Name = "Person A";
oClass.Id = 1;
oClass.ParentId = 0;
oClass.HappinessStatus = 1;
oClass.SalaryStatus = 1000;
oList.Add(oClass);
oClass.Name = "Person B";
oClass.Id = 2;
oClass.ParentId = 1;
oClass.HappinessStatus = 1;
oClass.SalaryStatus = 2000;
oList.Add(oClass);
oClass.Name = "Person C";
oClass.Id = 3;
oClass.ParentId = 1;
oClass.HappinessStatus = 1;
oClass.SalaryStatus = 1000;
oList.Add(oClass);
return oList;
}
On the MainForm's Load Event,
I did the following:
List<Class> list = new List<Class>();
list = Class.GetList();
dataTreeListView1.DataSource = list;
On the designer view, I've also created columns which has got aspect name set to each of the property of the class file except the Id and ParentId.
KeyAspectName : Id
ParentKeyAspectName: ParentId
I did a small messagebox to show the count of the item in the list, its correct but nothing displayed out on the dataTreeListView control.
May I know what is wrong with my coding?
Did you set KeyAspectName, ParentKeyAspectName and RootKeyValue accordingly?
If you did it using the designer, RootKeyValue may be your problem:
Due to the limitations of the Designer in the IDE, RootKeyValue can only be given a string value through the IDE. If your ParentKey is not of type string, you will have to set its value through code.
Since you parent key is of type int use
dataTreeListView1.RootKeyValue = 0;
Note that in contrast to the basic OLV, you don't need to add columns manually. If you want to hide the key columns set ShowKeyColumns = false.
EDIT:
There is another mistake in you code. You add the same instance of the object oClass 3 times. Use oClass = new Class(); before initializing a new person.
Related
I have a rather strange requirement for a Wpf Project I'm working on. I want to be able to build a XamDataGrid with a series of DateTime fields when the user saves the data from another grid. Currently I see the second XamDataGrid with it's fields, but upon execution of the command that saves the data, although I can see in the debugger that my second list (which is bound to the second XamDataGrid) is generated, nothing displays on this second XamDataGrid.
I'll post most of my code so that somebody might help me:
The xaml (for the second datagrid as the first one is working fine):
<igDP:XamDataGrid.FieldLayouts>
<igDP:FieldLayout>
<igDP:Field Label="ID" Name="id" Width="50"></igDP:Field>
<igDP:Field Label="Descripcion" Name="descripcion" Width="400"></igDP:Field>
<igDP:UnboundField Label="Fechas de Pago" Name="cadaPago" Width="400">
</igDP:UnboundField>
<igDP:Field Label="Colores" Name="Colores" Visibility="Collapsed" />
</igDP:FieldLayout>
</igDP:XamDataGrid.FieldLayouts>
</igDP:XamDataGrid>
`
The code in my viewmodel for the second grid:
public List<ClaseFechasPago> ListaFechasPago
{
get { return listaFechasPago; }
set { listaFechasPago = value; notifyChanges("ListaFechasPago"); }
}
public void PintarFechas(List<ClaseFechasPago> f)
{
ListaFechasPago.Clear();
foreach (ClaseFechasPago fecha in f)
{
fecha.cadaPago = new List<DateTime>();
for (int i = 0; i < fecha.numPagos; i++)
{
fecha.cadaPago.Add(new DateTime());
}
ListaFechasPago.Add(fecha);
}
}
public vmCursos_y_Diplomados()
{
Comando = new cmdCursos_y_Diplomados();
Comando.ViewModel = this;
ListaCursosyDiplomados = new List<ClaseCursosyDiplomados>();
ListaFechasPago = new List<ClaseFechasPago>();
this.cargarDatos();
this.PintarFechas(ListaFechasPago);
}
Now on the command I'm doing the following
public void Execute(object parameter)
{
List<CatEntidadesEducacionContinua> cursos = new List<CatEntidadesEducacionContinua>();
List<ClaseFechasPago> fechas = new List<ClaseFechasPago>();
foreach (ClaseCursosyDiplomados C in ViewModel.ListaCursosyDiplomados.Where(t=>t.Colores==1).ToList())
{
cursos.Add(new CatEntidadesEducacionContinua
{
IdEntidadEducacionContinua = C.id, Coordinador=C.coordinador, Descripcion=C.descripcion, FechaUltimoCambio = DateTime.Now,
FechaInicio = C.fechaInicio, FechaTermino=C.fechaTermino, Precio=C.precio, NumeroDePagos=C.numeroDePagos, FechasPagos=C.fechasPagos, Inhabilitado=C.inhabilitado,
});
if (C.numeroDePagos > 1)
{
ClaseFechasPago f = new ClaseFechasPago();
f.numPagos = C.numeroDePagos;
f.descripcion = C.descripcion;
f.id = C.id;
fechas.Add(f);
}
}
System.Windows.MessageBox.Show(new Entidades.MetodoCursos_y_Diplomados().SetEntidadEContinua(cursos), "Entidades de Educación Continua", System.Windows.MessageBoxButton.OK, System.Windows.MessageBoxImage.Information);
//System.Windows.MessageBox.Show(new Entidades.MetodoFechasPago().pintarFechasPago
ViewModel.cargarDatos();
ViewModel.PintarFechas(fechas);
}
But as I said it's not working, the execution results in the following screenshot, where the second grid is not populated:
Oh and I also forgot earlier to show the code for my custom class, out of which the list bound to the XamDataGrid is made of:
public class ClaseFechasPago : Utils.PropertyChange
{
private List<DateTime> _cadaPago;
public List<DateTime> cadaPago
{
get { return _cadaPago; }
set
{
_cadaPago = value;
if (EntroPrimeraVez)
{
Colores = 1;
}
}
}
private int? _numPagos;
public int? numPagos
{
get { return _numPagos; }
set
{
_numPagos = value;
if (EntroPrimeraVez)
{
Colores = 1;
}
}
}
private int _id;
public int id
{
get { return _id; }
set
{
_id = value;
}
}
private string _descripcion;
public string descripcion
{
get { return _descripcion; }
set { _descripcion = value; }
}
private int _Colores;
private bool _EntroPrimeraVez;
public bool EntroPrimeraVez
{
get { return _EntroPrimeraVez; }
set { _EntroPrimeraVez = value; notifyChanges("EntroPrimeraVez"); }
}
public int Colores
{
get { return _Colores; }
set { _Colores = value; notifyChanges("Colores"); }
}
}
It turned out the only thing I needed to do was passing the List explicitly as a list, like so:
ListaFechasPago = ListaFechasPago.ToList()
However, I seemed to have a mistake of concept in the way I was building the date fields. I ended up building as many registries as were needed of the same entry and binding a DateTime field to each, like so:
public static List<ClaseFechasPago> PintarFechas(ClaseFechasPago f)
{
List<ClaseFechasPago> ListaFechasPago = new List<ClaseFechasPago>();
for (int i = 0; i < f.numPagos; i++)
{
ClaseFechasPago fecha = new ClaseFechasPago();
fecha.cuotaInscripcion = 0M;
fecha.Inscripcion = true;
fecha.fechaPago = new DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day);
fecha.id = f.id;
fecha.descripcion = f.descripcion;
fecha.numPagos = f.numPagos;
fecha.Colores = f.Colores;
fecha.EntroPrimeraVez = f.EntroPrimeraVez;
ListaFechasPago.Add(fecha);
}
return ListaFechasPago;
//ListaFechasPago = ListaFechasPago.ToList();
}
Oh and of course initialize the ListaFechasPago List in the class that is set as DataContext for the window:
ListaFechasPago = new List<ClaseFechasPago>();
insde the class vmCursos_y_Diplomados
because I do:
private void UserControl_Loaded(object sender, RoutedEventArgs e)
{
this.DataContext = new vmCursos_y_Diplomados();
}
I know this is probably similar to some other posts, but I'm not quite sure what I'm doing wrong here. As an FYI, I'm new to programming and still trying to learn proper flow.
Here is the code, the exception occurs at "MyFriends[i].Name = friendName".
using System;
using System.Collections;
namespace FriendList
{
class FriendList
{
static public Friend[] MyFriends = new Friend[2];
public static void Main()
{
string friendName;
string friendPhone, friendMonth, friendDay, friendYear;
int intMonth, intDay, intYear;
for (int i = 0; i < 2; ++i)
{
Console.Write("enter name");
friendName = Console.ReadLine();
MyFriends[i].Name = friendName;
Console.Write("phone");
friendPhone = Console.ReadLine();
MyFriends[i].Phone = friendPhone;
Console.WriteLine("Enter Month: ");
friendMonth = Console.ReadLine();
intMonth = Convert.ToInt32(friendMonth);
MyFriends[i].Month = intMonth;
Console.WriteLine("Enter Day: ");
friendDay = Console.ReadLine();
intDay = Convert.ToInt32(friendDay);
MyFriends[i].Day = intDay;
Console.WriteLine("Entery Year: ");
friendYear = Console.ReadLine();
intYear = Convert.ToInt32(friendYear);
MyFriends[i].Year = intYear;
}
for (int i = 0; i < 2; ++i)
{
string information = string.Format("first name: {0}, phone {1}", MyFriends[i].Name, MyFriends[i].Phone);
Console.WriteLine(information);
}
Console.Read();
}
}
class Friend
{
string _Name = string.Empty, _Phone = string.Empty;
int _Day = 0, _Month = 0, _Year = 0;
public string Name
{
get { return _Name; }
set { _Name = value; }
}
public string Phone
{
get { return _Phone; }
set { _Phone = value; }
}
public int Month
{
get { return _Month; }
set { _Month = value; }
}
public int Day
{
get{ return _Day; }
set{ _Day = value ; }
}
public int Year
{
get { return _Year;}
set { _Year = value; }
}
public Friend()
{ }
}
}
Thank you for your guidance!
Your friend array is initialized empty. So MyFriends[i] will hit a null reference, which is another way to say you are trying to access something that doesn't exist.
In other words, you have an Array with slots for two friends, but both slots are empty. You still need to have a friend in each slot before you can use their properties, such as Name, Phone etc.
Simply start the for loop like this:
for (int i = 0; i < 2; ++i)
{
MyFriend[i] = new Friend(); //or pass parameters as required by the constructor
// rest of your code goes here
}
And things will be fine. This way, you are adding a friend to the slot you will be using.
You've created an array with two elements, but you have set the elements to any value. They are both null:
static public Friend[] MyFriends = new Friend[2];
So, when you try to use MyFriends[i] from the array, you're actually getting null.
MyFriends[i].Name = friendName;
That where your NullReferenceException came from.
You'll have to initialize the members of the array. For example:
for (int i = 0; i < MyFriends.Length; i++)
{
// Put a new Friend object in the array.
MyFriends[i] = new Friend();
// ...
When creating collections, they're populated with default values of the target type, and the default value for any reference type if null. So to solve your problem you'd have to initialize items in the array before accessing them:
....
for (int i = 0; i < 2; ++i)
{
MyFriends[i] = new Friend();
...
MyFriends is an array of Friend class.
each element in the array needs to be initialized with a friend constructor so it will be allocated with a memory.
I have the following class:
public class test
{
private int i;
public test(int in)
{
i = in;
}
public int testint;
{
get { return i; }
set { i = testint; }
}
}
And the following code:
test[] data = new test[3];
for(int j = 0; j < 3; j++)
{
data[i] = new test(0);
data[i].testint = int.Parse(Console.ReadLine());
}
Console.WriteLine(test[0].testint);
Console.WriteLine(test[1].testint);
Console.WriteLine(test[2].testint);
When I run this program and type in 1, 2, 3 as the input, the output is 0, 0, 0. I don't understand why the get or set seem to be not working. If I initialize the array elements with a value other than 0, the output will be that. The data[i].testint = int.Parse(Console.ReadLine()); seems to not be working. How would I go about doing something like that?
Change the set method to this:
public int testint
{
get { return i; }
set { i = value; }
}
You setter is incorrect. It should be:
set { i = value; }
You had:
set { i = testint; }
Which only triggers the getter, which gets from i, so in the end your setter was doing i = i .
In a setter, the value keyword contains the new candidate value for the property. value's type equals the property's. I say candidate value because you can validate it and choose to not apply it.
In your case, you were not applying the value.
Update
Also, when defining getters and setters, no semicolon should be used. Code, then, would look like this:
public int testint
{
get { return i; }
set { i = value; }
}
I see two errors in this code:
public int testint;
{
get { return i; }
set { i = testint; }
}
There should be no semicolon after testint at the top. Also, set needs to assign using value, like this:
public int testint
{
get { return i; }
set { i = value; }
}
Change your setter to say:
set { i = value; }
value corresponds to the value you send to set the variable.
Here's simple way.
public int TestInt {get; set;}
Lets image that I have the following classes
public class Master
{
public string MasterName = "Something";
public List<Detail> details = new List<Detail>();
}
public class Detail
{
public string Foo = "Test";
}
And then I want to show the collection of Details objects in a DataGridView, using the code below
DataGridViewTextBoxColumn column = new DataGridViewTextBoxColumn();
column.DataPropertyName = "Details.Foo";
column.HeaderText = "Foo header";
dgv.Columns.Add(column);
The column is shown in the grid, but without value
If you need to be more generic (i.e. using DataPropertyName = "MyProp1.MyProp2.MyProp3") you can use this
private void Grid_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
{
DataGridViewColumn column = Grid.Columns[e.ColumnIndex];
if (column.DataPropertyName.Contains("."))
{
object data = Grid.Rows[e.RowIndex].DataBoundItem;
string[] properties = column.DataPropertyName.Split('.');
for (int i = 0; i < properties.Length && data != null; i++)
data = data.GetType().GetProperty(properties[i]).GetValue(data);
Grid.Rows[e.RowIndex].Cells[e.ColumnIndex].Value = data;
}
}
You can override ToString method in the entity child for example:
public class FormulariosENT {
#region PROPERTIES
public int IdFromulario { get; set; }
public string DescripcionFormulario { get; set; }
#endregion
#region PUBLIC METHODS
public override string ToString() {
return DescripcionFormulario;
}
And later bind the entity child name.
In case you want to use many child elements like this:
class MyClass
{
public int Id;
public MyOtherClass OtherClass;
}
class MyOtherClass
{
public string Name;
public int Number;
}
How about:
1st solution
Set value for each cell in some event (mabye another one is better), manually, after setting datasource, for example:
private void dgv_CellFormatting( object sender, DataGridViewCellFormattingEventArgs e )
{
MyClass data = dgv.Rows[ e.RowIndex ].DataBoundItem as MyClass;
dgv.Rows[ e.RowIndex ].Cells[ "colName" ].Value = data.OtherClass.Name;
dgv.Rows[ e.RowIndex ].Cells[ "colNumber" ].Value = data.OtherClass.Number;
}
2nd solution
What about creating proper DataTable from the data and then just bind it?
I'd be thankful for any opinion ;-)
Just do this:
Mask the property you want to get a childvalue from with [Browsable(false)] so it wont show up in the datagrid.
Then create a NEW property in your class that holds the child object which has only a "get" method showing the childproperty value:
For example:
[Browsable(false)] //Because we use the CreatorUsernameProperty to do this.
public virtual User Creator { get; set; }
[DisplayName("Creator")] //shows like this in the grid
public string CreatorUsername => Creator?.Username;
where is your datasoure? you must lead to source. that it will find it.
you can do this
source :
:
List<Detail> list = new List<Detail>();
for (int i = 0; i < 10; i++)
{
Detail d = new Detail();
d.Foo = "test";
list.Add(d);
}
this.dgv.DataSource = list;
this.dgv.Columns[0].Visible = false;
DataGridViewTextBoxColumn dgvc = new DataGridViewTextBoxColumn();
dgvc.HeaderText = "列标题";
dgvc.DataPropertyName = "foo";
this.dgv.Columns.Add(dgvc);
:
public class Detail
{
private string foo;
public string Foo
{
get { return foo; }
set { foo = value; }
}
}
bubi's answer is great. I added a small tweak that lets the approach work if you're using BindingListView.
Edit: this approach disables sorting on columns located via subproperty. Not sure how to fix this at the moment.
if (column.DataPropertyName.Contains("."))
{
object data = dgv.Rows[e.RowIndex].DataBoundItem;
if (data is ICustomTypeDescriptor ictd) // support BindingListView
data = ictd.GetPropertyOwner(null);
string[] properties = column.DataPropertyName.Split('.');
for (int i = 0; i < properties.Length && data != null; i++)
data = data.GetType().GetProperty(properties[i])?.GetValue(data);
e.Value = data;
}
I have a class called rateTime
class rateTime
{
private List<string> t = new List<string>();
private List<string> s = new List<string>();
public rateTime(string[] time, string[] sender)
{
for (int i = 0; i < time.Length; i++)
{
t.Add(time[i]);
s.Add(sender[i]);
}
}
~rateTime() { }
public List<string> Time
{
get { return t;}
set { t = value; }
}
public List<string> Sender
{
get { return s; }
set { s = value; }
}
}
The DataSource of my combobox is set as follows:
rateTime rt = new rateTime(time, rateSender);
cb_rateTime.DataSource = rt.Time;
cb_rateTime.DisplayMember = "time";
In both lists I have 28 strings. I set items from List t as combobox items. And if I chose an item from the combobox with index, for example 10, I want know how can I get the string from list s with index 10.
try elementAt(index) - http://msdn.microsoft.com/en-us/library/bb299233.aspx
or indexer - yourList[index]
I don't know if I understood well, but:
var index = cb_rateTime.SelectedIndex;
var itemS = rt.Sender.elementAt(index);
or
var selected = cb_rateTime.SelectedText;
var itemS = rt.Sender[selected];
That should resolve.
Access it by index as in
MyRateTime.Sender[10]