Databind multiple Lists to a grid - c#

I need to databind multiple Lists or BindingLists (should make no difference) to one Grid. These Lists all have the same size, but different object types. The properties of the different objects in these lists should be displayed as columns next to each other, as if the first element of list A belongs to the first element of list B and so on.
Until now I copied the data into a DataTable and used this as a datasource, but for various reasons this is not possible anymore.
I know that it's not possible to bind more than one list directly, but I have no clue how to start this. I did read a bit about databinding, but it looks like I have to code a lot for this to work, work with the CurrencyManager and so on.
Is there a simple solution that could help me? Perhaps a wrapper class that does all that?
If not, could someone give me some hints which interfaces must be implemented and what else is to keep in mind?

If you cannot make these disparate objects one object, then this is not a bindable list.
You could do a shallow copy of each of these objects in a brand new object list and create them on-the-fly:
Object MyFirstObject;
Object MySecondObject;
void BindableClass( Object class_1, Object class_2 )
{
MyFirstObject = class_1;
MySecondObject = class_2;
}
public String _firstColumnString { get { return MyFirstObject.FirstColumnString; } }
public String _secondColumnString { get { return MySecondObject.SecondColumnString; } }
Better yet, pull out just the information you need in your BindableClass constructor.
void BindableClass( Object class_1, Object class_2 )
{
_firstColumnString = MyFirstObject.FirstColumnString;
_secondColumnString = MySecondObject.SecondColumnString;
}
(But now you're really just down to one list again!)
You can then create the objects by doing something like:
for (int i = 0; i < TheListSize; i++)
{
ABindableList list = new BindableClass( FirstList[i], SecondList[i] );
}

Related

Unable to get separate references during iteration

I am attempting to iterate through the members of a list which implement a particular interface, called ImplementsGraphics and then call the method GetModels and add the return result to a list.
However, whenever I attempt to iterate through my objects, and perform the casting operation, I appear to be overwriting the same reference during my iteration. I have deduced that my problem is something to do with where, when and how I am instantiating my variables, but I can not decipher exactly what the intended behavior is.
I've tried numerous permutations of the following code:
public List<Model> GetModels()
{
var models = new List<Model>();
foreach (Actor actor in registeredActors.Where(n=>n is ImplementsGraphics))
{
var graphicActor = (ImplementsGraphics)actor;
models.AddRange(graphicActor.GetModels());
}
return models;
}
The problem line is var graphicActor = (ImplementsGraphics)actor; but I don't know how to write it such that declaring graphicsActor does not overwrite the existing instances of it stored in models.
Before my first several rounds of troubleshooting, I had
public List<Model> GetModels()
{
var models = new List<Model>();
foreach (Actor actor in registeredActors)
{
if((ImplementsGraphics)actor != null)
models.AddRange(((ImplementsGraphics)actor).GetModels());
}
return models;
}
Which I expected to work, as I had thought actor was safe across iteration, but apparently not.
Desired Behavior:
Return a list, which is all the return results of GetModels() for ever Actor in RegisteredActors which implements ImplementsGraphics
Actual Behavior:
Returns a list, which is the same return value repeated for each Actor in Registered Actor, which implements ImplementsGraphics.
EDIT:
In the class StaticActor which is a child of Actor and implements ImplementsGraphics its defined as follows:
public List<Model> GetModels()
{
foreach (ModelMesh mesh in model.Meshes)
{
foreach (BasicEffect effect in mesh.Effects)
{
effect.World = this.Transform.WorldMatrix;
}
}
return new List<Model> { Model };
}
Additonally, I have tried two other approaches which also failed. A for loop, which itereated through all of RegisteredActors, and checked if they implemented ImplementsGraphics, explicitly calling them by their index within RegisteredActors
And a LINQ query, which went
var models = RegisteredActors.Where(n=>n is ImplementsGraphics).SelectMany(n=>((ImplementsGraphics)n).GetModels())
EDIT 2:
The deinfitions of my classes are largely irrelevant, if you want a reproducable example of the behaviour I'm having trouble with, here is a far simpler example.
class MyClass
{
MyOtherClass foo = new MyOtherClass();
int bar = 0;
MyOtherClass GetOtherClass()
{
foo.bar = bar;
return foo;
}
}
class MyOtherClass
{
int bar = 0;
}
List<MyClass> MyCollection = new List<MyClass> {new MyClass(bar = 1), new MyClass(bar = 2), new Myclass(bar = 3)};
List<MyOtherClass> MyOtherCollection = new List<MyOtherClass>();
foreach(MyClass member in MyCollection)
{
MyOtherCollection.Add(member.GetOtherClass());
}
If you were to execute the above code, I expect that the value of MyOtherCollection's bar properties would be: 1, 2, 3
However, the actual result is that:
During the first iteration the values are 1
During the second iteration the values are 2, 2
During the third iteration the values are 3, 3, 3
I would appear, since none of the provided code states, only implies, that you are attempting to reuse a reference to single Model instance to draw multiple objects. Then you are adding multiple references of the same instance to the List.
The solution may be as simple as removing the static modifier from all Model variables and/or container objects.
Normally, the solution would be to create a Deep Copy of the object when it is added to the List, however, it is not directly possible to do this in XNA *1. (not that you would want to)
It would be better to allow each Actor, or StaticActor, object to directly pass its own Model(s) through the GetModels() method in the interface implementation, instead of using the additional class MyOtherClass.
*1. XNA does not expose a public constructor for the Model class. It is possible to do this using reflection. In MonoGame, there is a public Constructor available.
I tend to split my derived Classes and subsequent Lists based on properties like "StaticCollidables","DrawableStaticCollidables" and "DrawableMovingCollidables"...
This technique may require more upfront coding(and therefore is not as "elegant"), but, it is more efficient in terms of memory overhead(8 bytes + (4(32 bit) or 8(64 bit) bytes depending on sizeof(Object)) per List) and CPU overhead(no casting or is).
If you are attempting to reuse the same model, but place it in different locations, use the DrawInstancedPrimitives method using the VertexBuffers contained within each Mesh of the model.
Please comment on which of the above solutions worked for you(if any). If I have missed something please let me know, so I can correct the answer.

Querying object without a given name

I have created a list of objects using a C# line like this:
gameObjects.Add(new Object());
I have also made a function that prints on the screen a list of the object types contained within gameObjects.
for(int i = 0; i < gameObjects.Count; i++)
Console.WriteLine(gameObjects[i].GetType());
So far so good. However I'm getting more items printed on the screen than should be present in gameObjects, so I've been trying to work out a way of finding out whether any of the entries are duplicates as I can't find anything in my code that could be creating extra objects in the list. It would be great if I could print out the names of each object in the list, but as I haven't given them names I don't think this is possible. Is there anything else that would differentiate one object in the list from another that I could take advantage of? As it's just debugging, I didn't really want to have to go in and make sure each object is given a name.
Thanks!
Edit:
For those asking for more code, I have a function that adds objects of type staticObject to the gameObjects list:
private void CreateStaticObject(Vector2 v2StaticObjectPosition)
{
Texture2D staticObjectTexture = Content.Load<Texture2D>(#"textures\StaticObject");
GameInfo.gameInfo.gameObjects.Add(new StaticObject(staticObjectTexture, v2StaticObjectPosition, sbSpriteBatch));
}
The list is contained within a class called GameInfo. Each StaticObject inherits from a Sprite class, if that's of importance.
I also add a Player object to the list, which inherits from the StaticObject class:
private void CreatePlayer(Vector2 v2PlayerPosition)
{
Texture2D playerTexture = Content.Load<Texture2D>(#"textures\Player1");
player1 = new Player(playerTexture, v2PlayerPosition, sbSpriteBatch);
}
I'm then printing out the contents of the list with this:
for(int i = 0; i < GameInfo.gameInfo.gameObjects.Count; i++)
{
string sObjectString = string.Format("Game object {0} is a {1}", i, GameInfo.gameInfo.gameObjects[i].GetType());
DrawWithShadow(sObjectString, new Vector2(10, 20 * i + 10));
}
DrawWithShadow() is just a simple method which nicely formats the text on the screen in the desired location. Unfortunately though, for each object that I create by calling the CreateStaticObject() method, I end up with two entries in my list.
Updated because I was dumb, ReferenceEquals checks reference equality.
Have you tried Object.ReferenceEquals()? It will tell you if reference a and reference b point to the same object.
var x = new object();
var y = x;
//This will print "true"
Console.WriteLine(Object.ReferenceEquals(x,y));
If you just want to filter the dupes out of the list, try this:
gameObjects = gameObjects.Distinct().ToList();
You can use GroupBy to find all duplicate objects by using reference equality:
var duplicateGroups = gameObjects.GroupBy(obj => obj).Where(g => g.Count() > 1);
Note that this will use the object's Equals + GetHashCode methods if they are overridden.
Thanks for all the suggestions guys. However I've discovered the source of my problem. I had an old line of code in the constructor for the StaticObject class which adds any created StaticObject to the list. So I was adding each object twice. D'oh! :S

List<T> copied from same object, properties updated in both places

I've done a lot of reading on copying/cloning objects in C# and I was trying to work from this example, but my situation is a little different.
I have a list of question/answer pairs being returned from the database. I want to use that to create two lists for parent and child objects. When I do that, any changes I make to the child are reflected in the parent.
I've tried several permutations of creating new lists, cloning, etc, but always end up with the same result.
List<QuestionVM> questionlist = productRepository.GetQuestions();
parent.Questions = AddQuestions(true, parent, questionlist);
child.Questions = AddQuestions(false, child, questionlist);
private List<QuestionVM> AddQuestions(bool parent, Line line, List<QuestionVM> questions)
{
//shouldn't this create a new object, not just a reference?
List<QuestionVM> qs = new List<QuestionVM>(questions);
if (parent)
{
return qs.Where(w => w.ShowOnParent).ToList();
}
else
{
return qs.ToList();
}
}
Any help is greatly appreciated.
It is not enough to just create copy of the list, because items in both old and new lists will still refer to the same objects.
You need to implement ICloneable interface(or just your own custom method) for your objects and call clone for each original object while creating copy list:
public class QuestionVM: ICloneable
{
public Object Clone()
{
return new QuestionVM(this.prop1, this.prop2);
}
}
...
private List<QuestionVM> AddQuestions(bool parent, Line line, List<QuestionVM> questions)
{
...
return qs
.Where(w => w.ShowOnParent)
.Select(obj => (VMQuestion)obj.Clone())
.ToList();
...
}
P.S.: If VMQuestion contains fields of other complex types then they have to provide Clone method as well.
If anyone else is still interested in this. You can use automapper to make deepcopy of an object.

list property containing two types (string/int)

I need to have a property that will be an array that can hold both ints and strings.
if i set the property to an array of ints it should be ints so when I am searching through this array the search will be fast, and at odd times this property will also contain strings which the search will be slow.
Is there any other way other than the following to have a list that contain native types
two properties one for ints and one for strings
use List< object >
UPDATE:
The use-case is as follow. I have a database field [ReferenceNumber] that holds the values (integers and strings) and another field [SourceID] (used for other things) which can be used to determine if record holds an int or string.
I will be fetching collections of these records based on the source id, of course depending on what the source is, the list either will be integers or strings. Then I will go through this collection looking for certain reference numbers, if they exist not add them or they dont then add them. I will be pre-fetching a lot of records instead of hitting the database over and over.
so for example if i get a list for sourceid =1 that means they are ints and if searching i want the underline list to be int so the search will be fast. and if sourceid say is 2 which means they are strings and very rare its okay if the search is slow because those number of records are not that many and a performance hit on searching through strings is okay.
I will go through this collection looking for certain reference numbers, if they exist not add them or they dont then add them.
It sounds to me like you don't need a List<>, but rather a HashSet<>. Simply use a HashSet<object>, and Add() all the items, and the collection will ignore duplicate items. It will be super-fast, regardless of whether you're dealing with ints or strings.
On my computer, the following code shows that it takes about 50 milliseconds to populate an initial 400,000 unique strings in the hashset, and about 2 milliseconds to add an additional 10,000 random strings:
var sw = new Stopwatch();
var initial= Enumerable.Range(1, 400000).Select(i => i.ToString()).ToList();
sw.Start();
var set = new HashSet<object>(initial);
sw.Stop();
Console.WriteLine(sw.ElapsedMilliseconds);
var random = new Random();
var additional = Enumerable.Range(1, 10000).Select(i => random.Next(1000000).ToString()).ToList();
sw.Restart();
foreach (var item in additional)
{
set.Add(item);
}
sw.Stop();
Console.WriteLine(sw.ElapsedMilliseconds);
Also, in case it's important, HashSet<>s do retain order of insertion.
The only other thing I would suggest is a custom object that implements IComparable
class Multitype: IComparable
{
public int? Number { get; set; }
public string Words {get; set; }
public int CompareTo(object obj)
{
Multitype other = obj as Multitype;
if (Number != null && other != null && other.Number != null)
{
//...
}
else
{
//...
}
}
}
There will be some extra comparison steps between numbers, but not as much as string parsing.
Are you storing a ton of data, is that performance difference really going to matter?
It's possible to use generics if you implement them on the class. Not sure if this solves your problem. Would be interested to hear the real-world example of a property that can have different types.
class Foo<T>
{
public List<T> GenericList { get; set; }
public Foo()
{
this.GenericList = new List<T>();
}
}
If by "use List" you mean the object primitive or provided System.Object, that is an option, but I think it would behoove you to make your own wrapper object -- IntString or similar -- that would handle everything for you. It should implement IComparable, as the other gal mentioned.
You can increase the efficiency of sorting your object in collections by writing a CompareTo method that does exactly what you need it to. Writing a good CompareTo method is a whole can of worms in itself, so you should probably start a new question for that, if that's what you want.
If you're looking for a property that is strongly typed as a List<Int> or List<String> at instantiation, but can change afterwards, then you want an interface. IList exists, but won't help you, since that must also be strongly typed upon declaration. You should probably make something like IIntStringList that can only be one of List<Int> or List<String>.
Sorry this answer doesn't have that many details (I need to leave the office now), but I hope I've set you on the right track.

Store anonymous values in a list and extract each individually

I'm trying to store information in a block of anonymous values
//holds all info
var jobs = new { newJob, numBytes, requiredTime };
then take that information and place it into a list as a single element
//puts above info into a list
joblist.Add(Convert.ToString(jobs));
Console.WriteLine(joblist[0]); //testing purposes
now what I would like to do is be able to call joblist and take the value of example numBytes at position 4.
Is this possible? Or could someone help with an alternate way of doing this? Much thanks!
Create a named class. Then you can have a list of objects of that type and manipulate that list in any way you want.
Using classes is best-practice for what you are trying to do. By default you should consider storing structured data in an object model consisting of custom classes. There is another answer here which is proposing to use dynamic - this is valid and has its place, but it is more of a last resort solution. What you want is to play to the strength of C# which are rich classes and static typing. Anonymous types are also statically typed, but as you cannot name the type you cannot declare a statically typed list to hold them. You also can't use them as return types of methods.
The "normal" thing to do in C# would be to create a class to hold the information that you want to store. For example:
public class Job
{
public string Name { get; set; }
public int NumBytes { get; set; }
public DateTime RequiredTime { get; set; }
}
Then you can add these to a list:
var jobs = new List<Job>();
var aJob = new Job();
aJob.Name = "Job 1";
aJob.NumBytes = 123;
jobs.add(aJob);
Then you can access jobs by its index in the list:
var jobNumBytes = jobs[3].NumBytes;
One thing to note about C#, when you do:
new { newJob, numBytes, requiredTime };
The compiler, at build time, just creates you a strongly typed class (just like the Job class I created above) and generates a random name for it. It infers the property names and types from the variables that you are assigning to it. The created .exe or .dll actually does contain a class definition for this type, you just can't easily get to it from other places in your code. It isn't truly "dynamic". So using that syntax is usually just a lazy way of declaring a class that you just need for a moment. Usually just inside 1 method, then you don't need it any more. Creating a named class is usually what you want to do.
Actually I don't know exactly what you mean with "now what I would like to do is be able to call joblist and remove for example numBytes at position 4."
But I guess you just want to put the objects in a list and query for numBytes and maybe remove some elements.
With dynamics you can handle dynamic objects...
var jobs = new List<dynamic>();
for (int i = 0; i < 100; i++)
{
string newJob = "Job" + i;
int numBytes = i;
TimeSpan requiredTime = new TimeSpan(0,0,i);
//holds all info
var job = new { newJob, numBytes, requiredTime };
jobs.Add(job);
}
jobs.RemoveAll(p => p.numBytes > 50);
Instead of this, I agree with the comments below your question and would create a normal class which holds the properties you need and simply put instances of that into a list. Dynamics should be used only in very rare situations, and yours doesn't sound like it is extremely special.

Categories