I have a datatable with two columns. I want to store the rows of each column in an array so that I can return rows for each individual column. This way I believe I can populate a list box(the option text as one column and the option value as the other column).
Here is what I started out with:
public object dbAccess2()
{
ArrayList arg = new ArrayList();
DataTable myTable = GenericDataAccess.ExecuteSelectCmd("Vehicle_GetMakes");
foreach (DataRow dRow in myTable.Rows)
{
arg.Add(dRow["VehicleMake"]);
arg.Add(dRow["VehicleMakeId"]);
}
return arg.ToArray();
}
You can make a class to hold each individual row in this case and use a List<T> to hold the data, like this:
public class Vehicle
{
public string Make { get, set };
public string MakeId { get, set };
}
..
List<Vehicle> Vehicles = new List<Vehicle>();
..
foreach (DataRow dRow in myTable.Rows)
{
Vehicles.Add(
new Vehicle {
Make = arg.Add(dRow["VehicleMake"]),
MakeId = arg.Add(dRow["VehicleMakeId"])
});
}
And later, you can easily populate a listbox with this list:
listBox.DataSource = Vehicles;
listBox.DisplayMember = "Make";
But I think you may want to use a ListView probably.
Don't use the ArrayList class, it's practically obsolete. Use arrays or generic lists instead, so that you get a typed result.
You can get the columns into lists like this:
List<string> makes = myTable.Rows.Select(r => (string)r["VehicleMake"]).ToList();
List<int> makeIds = myTable.Rows.Select(r => (int)r["VehicleMakeId"]).ToList();
Or into arrays:
string[] makes = myTable.Rows.Select(r => (string)r["VehicleMake"]).ToArray();
int[] makeIds = myTable.Rows.Select(r => (int)r["VehicleMakeId"]).ToArray();
An alternative to populating a dropdown (as that is what I assume that you mean, as a ListBox doesn't have options) from arrays is to use data binding:
theDropdown.DataTextField = "VehicleMake";
theDropdown.DataValueField = "VehicleMakeId";
theDropdown.DataSource = myTable;
theDropdown.DataBind();
What you're attempting is to manipulate real objects without the benefit of object design, invoking raw data instead. This has very broad and far-reaching problems and is quite far behind current development strategies - to broad to go into here but not least of your problems is building in a brittle coupling between your application and your database.
Step one is to model an actual Vehicle class.
public class Vehicle
{
public string MakeId { get; set; }
public string Make { get; set; }
}
Step two is to build a managing class for your Vehicles ("Fleet" perhaps?) which can abstract the Vehicle collection behind an IEnumerable interface. Internally you will store the Vehicles collection as a concrete generic collection (a List or Dictionary most likely) and avoid at all costs the really-should-be-considered-obsolete ArrayList structure.
public class Fleet
{
private List<Vehicle> _vehicles = new List<Vehicle>();
public IEnumerable<Vehicle> Vehicles { return this._vehicles;}
}
Step three is to internalise to this class (or a class behind this one or behind that one etc, etc) the CRUD operations which will interact with the Database stored data. That's truly an implementation detail, but one you'll apply for all similar classes throughout your architecture.
At this point you'll be able to work with the IEnumerable property directly with standard Databinding methods.
Related
I'm a newbie in the C# and .NET at all.
So, I have a collection that contains objects
private List<object> trains = new List<object>();
...
trains.Add(trains[0]);
trains.Add(trains[1]);
trains.Add(trains[2]);
trains.Add(trains[3]);
trains.Add(trains[4]);
And later in my code I must to input all elements of my collection
I'm trying something like that, but it doesn't work
public void Display()
{
...
for (int i = 0; i<trains.Count; i++)
{
Console.WriteLine(trains[i].Number);
Console.WriteLine(trains[i].Destination);
}
}
Help me please, I'm really dont understand how to input it to the console. I read Microsoft documentation about the "List" but :(
You have a list of objects. And object class doesn't have those members (Number and Destination). If you wanna access them either you need to cast your objects to your type or have a list of Train instead of object.
Currently you are storing your objects in a List<object>, Since your class (probably named) Train inherit from Object, you can store its object in object. You need List<Train> and then you can access each member property like:
private List<Train> trains = new List<Train>();
If you can do that for some reason then you have to explicitly cast your object to Train like:
Console.WriteLine(((Train)(trains[i])).Number);
Assuming this
class Train
{
public int Number { get; set; }
public string Destination { get; set; }
}
And that you are doing something like this:
var t1 = new Train();
t1.Number = 1;
t1.Destination = "somewhere";
var t2 = new Train();
t2.Number = 2;
t2.Destination = "somewhereelse";
trains.Add(t1);
trains.Add(t2);
Than you can output using this:
Train train;
foreach(object t in trains)
{
if ((train = t as Train) != null)
{
Console.WriteLine(t.Number);
Console.WriteLine(t.Destination);
}
}
The advantage of using a list of objects is that you can put "anything" there. Not only "Train". But as pointed by #Chris, foreach do not filter, so you have to filter it yourself.
To access the Train object directly, you will need to cast the generic object to a Train object prior to referencing it's exposed properties. This can be done on the fly, it's not necessary to declare the extra variable myTrain here, however for sake of clarity and readability, I generally do it like this.
public void Display()
{
...
for (int i = 0; i<trains.Count; i++)
{
Train myTrain = (Train)trains[i];
Console.WriteLine(myTrain.Number);
Console.WriteLine(myTrain.Destination);
}
}
Others have mentioned and I would agree, I can think of very few situations where you would NEED to use a:
List<object>();
rather than:
List<Train>();
The only thing that jumps out at me would be if you might be storing non Train objects in the same list with Train objects but I cannot think of a good reason to do something like that off the top of my head.
Exploring WWF I've encountered a difficulty with processing a DataTable. Lets say I have a table and I want to do some calculations based on the data of each of the rows from that table. To do so, I would have added a CodeActivity as the first step in my workflow which will read that table and populate a DataTable(which would be stored as a private field of the workflow) with the data. I thought that afterwards I would use the ReplicatorActivity(as it is suggested by MSDN as a replacement to the foreach loop) for iterating through the data and it would have another CodeActivity that would do all the calculations based on the row's data. The problem is that ReplicatorActivity can iterate only through System.Collections.IList but as we know System.Data.DataTable.Rows is of type DataRowCollection which implements ICollection and IEnumerable through InternalDataCollectionBase, but not IList.
What would you suggest? Should I use a WhileActivity instead of ReplicatorActivity in this case, or some other approach?
Should I do all the calculations in a single long running CodeActivity?
From what you are describing a single CodeActivity can simply take care of the business. Look at the following code and construct something like below:
public sealed class TableManipulationActivity : CodeActivity<DataTable>
{
[Required]
public InArgument<DataTable> TableInArgument { get; set; }
private DataTable _table;
protected override DataTable Execute(CodeActivityContext context)
{
_table = TableInArgument.Get(context);
// play with _table value and do whatever you want [All sorts of CRUD operations]
var result = new DataTable(); // populate this result
// Manipulate result
// ...
// ...
return result;
}
}
Above approach is quite easy and reusable based on your problem description.
I am looking for a way to display data in a DataGrid from types that are unknown at compile-time.
I have the following base class
public abstract class Entity
{
// Some implementation of methods ...
}
In run-time, I load a plug-in DLL and use reflection to get a list of all the types derived from Entity. For example:
public class A : Entity
{
public LocalAddress Address{ get; set; }
}
public class B : Entity
{
public Vendor Vendor { get; set; }
public string Name { get; set; }
}
Then I retreive a list of their instances from DB
public IEnumerable<Entity> Entities { get; set; } // A list of instances of type A for example
Entities is the DataGrid's ItemsSource, But what's the best way I can bind the properties to the DataGrid?
Since the properties can be complex, I also need to be able to bind to a specific path, for example Address.HomeNum ...
Clarifications
I only need to show a one grid of a type's instances at a time. The complete scenario is this:
I get a list of types that derive from Entity from the plug-in DLL through reflection
I show their names in a List. (in this example that list will contain A and B
When the user clicks on a specific item, let's say A, I get a list of A instances from DB - so far so good.
I want to display that list of A's instances in a DataGrid.
When the user selects another item from the list (meaning another type, lets say B), I get a list of B's instances from DB and need to display those in the grid and so on ...
The plug-in DLL is a class library with no xamls (also my users are the ones making this plug-ins and I don't want them to have to write DataTemplates for their entities.
I also can't make predifned DataTemplates as I don't know the types I'll need to display until run-time. Each type can have different types and amount of properties. All I know in complie-time is that they all derived from Entity.
The grid should also be editable.
A DataGrid seems inappropriate in this case. If your list was bound to two separate entities, it would break badly.
A better option would potentially be to use some other ItemsControl and set up a DataTemplate for each type of Entity. This would allow you to build custom editors per entity, and have a "list" of them to edit.
If you know the entities will always be of a single type, I'd instead build the collection of that specific type, and bind to it.
Since you don't know the property names of the Entities beforehand, I think your best option is to keep your DataGrid in Xaml but move the defintion and the Bindings of its DataGridColumns to the code behind.
AddColumnsForProperty(PropertyInfo property, string parentPath = "")
{
var title = property.Name;
var path = parentPath + (parentPath=="" ? "" : ".") + property.Name;
if(property.PropertyType == typeof(string))
{
var column = new DataGridTextColumn();
column.Header = title;
column.Binding = new Binding(path);
dataGrid.Columns.Add(column);
}
else if(property.PropertyType == typeof(bool))
{
//use DataGridCheckBoxColumn and so on
}
else
{
//...
}
var properties = property.GetProperties();
foreach(var item in properties)
{
AddColumnsForProperty(item, path);
}
}
Now if you execute these you'll have your dataGrid columns filled. and by adding all instances of the desired type in an observable collection and bind it to ItemsSource of the DataGrid it should work. selectedItem should be an instance of one the classes derived from Entity. The listbox contains new A() and new B() (or any existing instances of A and B) so selectedItem can be used in the following statement.
var propertyList = selectedItem.GetType().GetProperties();
foreach (var property in propertyList)
AddColumnsForProperty(PropertyInfo property);
how to write DataGridColumnTemplate in code
Edit:
Member can't be used in this scenario because INotifyPropertyChanged should get involved, so I replaced members with properties.
I would use attributes to specify what exactly is bindable (including composite object):
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
public abstract class EntityAttribute : Attribute
{
internal abstract IEnumerable<EntityColumn> GetColumns(object instance, PropertyInfo property);
}
This attribute supports plain properties as well as composite structures. You should simply inherit and implement the method.
EntityColumn represents single value. Simplified version can be implemented like this:
public class EntityColumn
{
private readonly Action<object> _setMethod;
private readonly Func<object> _getMethod;
public string Caption { get; private set; }
public object Value
{
get { return _getMethod(); }
set { _setMethod(value);}
}
internal EntityColumn(string caption, Action<object> setMethod, Func<object> getMethod)
{
_getMethod = getMethod;
_setMethod = setMethod;
Caption = caption;
}
}
Later you can create single DataTemplate for EntityColumn and use it for all properties for all possible entities. Entity Object will contain additional method to return all EntityColumn relevant to it:
public IList<EntityColumn> GetColumns()
{
var objectType = GetType();
var properties = objectType.GetProperties();
return properties.SelectMany(
p => p.GetCustomAttributes<EntityAttribute>().SelectMany(a => a.GetColumns(this, p))).ToList();
}
For collection of Entities you can introduce EntityCollection which will absorb column information and provide structure similar to DataSet.
This implementation gives you flexibility of dynamic structure and keeps almost everything strongly typed. You can even extend attributes and EntityColumn to support validation.
As of displaying object, you'd rather use ItemsControl or even self written control inherited from ItemsControl to take advantage of knowing about Entity and EntityCollection classes.
Here is my situation. I have 2 list of the same type. Imagine the names like these. FullList and ElementsRemoved. So in order to avoid the database roundtrip, anytime I delete an element from the fulllist I added to the list of ElementsRemoved in case of regret's user so he can revert the deletion.
I was thinking to loop inside my ElementsRemoved to insert them again into the FullList from where initially were removed.
There is any way to do this as simple with List Methods.
Something like
FullList.Insert, Add, ..... (x =>
in order to reduce line code and optimized?
Instead of deleting the item from your database consider using a flag in the table.
For example consider this entities table (written in TSQL):
CREATE TABLE Entity
(
Id INT IDENTITY PRIMARY KEY
,Name NVARCHAR(20) NOT NULL
,IsDelete BIT NOT NULL DEFAULT 0
);
This way you can set the IsDelete bit when the user deletes the entity which will prevent the data from being lost. The data can be pruned on a job in the off hours.
The would lead to only needing one list instead of keeping track of two lists.
public class Entity
{
public int Id { get; set; }
public string Name { get; set; }
public bool IsDelete { get; set; }
}
public static void UndoDelete(IEnumerable<Entity> fullList, int[] removedIds)
{
foreach(var entity in fullList.Where(e => removedIds.Contains(e.Id)))
{
entity.IsDelete = false;
}
}
In case you cannot modify your application.
You can simply add the entities back in.
See List(T).AddRange
var entitiesToAdd = new[] { 2, 3, 4 };
var entitiesToInsert = ElementsRemoved.Where(e => entitiesToAdd.Contains(e.Id));
FullList.AddRange(entitiesToInsert);
In your front end make a class that holds a bool and your object:
public class DelPair<T>{
public bool IsDeleted{get;set;}
public T Item{get;set;}
}
Now instead of using a list of objects use a list of DelPair<YourClass> and set IsDeleted=true when deleting.
This pattern will also allow you to track other things, such as IsModified if it comes to that.
Based on OP comment that he's using an ENTITY class and needs it to function as such:
One option is to make your DelPair class inherit ENTITY. Another may be to put implicit casting operator:
...
// not exactly sure about the signature, trial/error should do :)
public static implicit operator T(DelPair<T> pair)
{
return pair.Item;
}
Suppose you have an element having a field id which uniquely identifies it.
class Element{public int id;}
In that case you can do this
FullList.Add(ElementsRemoved.FirstOrDefault(e=>e.id==id));
In case you want to add all elements use AddRange
FullList.AddRange(ElementsRemoved);
You can use the AddRange method
FullList.AddRange(ElementsRemoved);
But consider doing this
public class YourClass
{
public string AnyValue{get;set;}
public bool IsDeleted{get;set;}
}
And you have list like this List < YourClass> FullList. Now whenever user removes any item you just set the
IsDeleted = true
of the item that is removed. This will help you in keeping just one list and adding removing from the list
There is tabular data that is being stored in the database as a delimited data. Not ideal, I know, but that's how the system was designed. I need to pull the data out and parse it into some kind of structure.
In the old days, I'd use a DataTable and call it good. Now, however, that just feels dirty. What is a better, more efficient, and more lightweight structure to store tabular data in my data model?
Here's a lightweight DataTable from one of the Telerik developers:
http://blogs.telerik.com/vladimirenchev/posts/09-04-23/lightweight-datatable-for-your-silverlight-applications.aspx
It supports INotifyCollectionChanged and INotifyPropertyChanged so it works well for data binding.
I wouldn't say it's any less "dirty", but it is an alternative.
Well, just create a class that has all the columns of the database as properties. Then just instantiate an implementation of ICollection (List, Hashset, etc..) and fill it (using LINQ for example).
public class Customer
{
public int Id { get; set;}
public string Name { get; set; }
public Customer(int id, string name)
{
this.Id = id;
this.Name = name;
}
}
And do something like:
List<Customer> customers = new List<Customer>();
using (DbDataReader reader = // instantiate reader)
{
while (reader.Read())
{
Customer customer = new Customer(reader.GetInt32(0), reader.GetString(1));
customers.Add(customer);
}
}
If you are accessing data that is stored in a database you may want to look at LinqToSql or LinqToEntities.
Well use a library i developed it include type to type convert and many more, and datareader to list
https://www.nuget.org/packages/Generic.LightDataTable/