Convert dataset to observable collection
I was trying to bind a datas开发者_如何转开发et to a listbox..certainly because i want to display a couple of tables information in a datatemplate..But this seems not possible and i will have to convert it to an observable collection.But how can i do it.My bl returns dataset objects.How can i convert this to observablecollection..? Is there any way so that i can handle this situation in MVVM..? How do people handle datasets in MVVM architecture..?
A DataSet is a .Net representation of a set of tables, and the relationahips between them. It is kind of like an in-memory code-accessible representation of a mini-database. Only a few controls can bind directly to a dataset - those that are coded to analyze the relationships between the datasets tables and represent the various tables' data in some kind of hiearchical display, (like a treeview or a hiearchical grid) Anything that requires a simple list of items, with one or two properties for each item can not be bound directly to a dataste, it can only be bound to one of the contained datatables.
Alternatively, you need to dynamically construct and populate a datatable of your own, constructed from the various tables in the dataset you are using, to properly service the specific control you want to bind it to.
Here is how you convert a datatable to an observable collection:
- You need to create a class which contains properties. Each property represents a column in the datatable. Hence you need to set the types of properties as the types of columns in the datatable.
- Next you create a property in your View model with which you want to bind any control in xaml. This property would be of the type ObservableCollection. You can bind this property to a grid. In the case of Listbox you can make an ObservableCollection of strings and bind it to a listbox.
- You can directly populate you result from DB in Observable collection using LINQ, or alternatively you could manually add items in ObservableCollection from datatable.
There is no built-in function or cast with which you can convert a datatable to an observablecollection
Here is the code from Datatable to ObservabaleColleaction as @Hasan Fahim suggested...
DataTable dtValues = new DataTable();
dtValues.Columns.Add("Value1");
dtValues.Columns.Add("Value2");
dtValues.Columns.Add("Value3");
dtValues.Columns.Add("Value4");
DataRow dr = dtValues.NewRow();
dr["Value1"] = "asad";
dr["Value2"] = "naeeem";
dtValues.Rows.Add(dr);
ObservableCollection Values = new ObservableCollection<MyClass>
(dtValues.AsEnumerable().Select(i => new MyClass
{
Value1 = Convert.ToString(i["Value1"]),
Value2 = Convert.ToString(i["Value2"]),
Value3 = Convert.ToString(i["Value3"]),
Value4 = Convert.ToString(i["Value4"])
}));
I'm still working on it, but how about something like this:
public class cDTObservable<DTType, RowType> : ObservableCollection<RowType>
where DTType : DataTable
where RowType : DataRow
{
private DTType _dt;
public cDTObservable(DTType dt)
: base(dt.Rows.OfType<RowType>())
{
_dt = dt;
}
protected override void ClearItems()
{
_dt.Clear();
base.ClearItems();
}
protected override void InsertItem(int index, RowType item)
{
if (index > _dt.Rows.Count) throw new ArgumentOutOfRangeException("Argument is out of range");
if (index == _dt.Rows.Count)
_dt.Rows.Add(item);
else
_dt.Rows.InsertAt(item, index);
base.InsertItem(index, item);
}
protected override void MoveItem(int oldIndex, int newIndex)
{
if (oldIndex >= _dt.Rows.Count || newIndex >= _dt.Rows.Count)
throw new ArgumentOutOfRangeException("Argument is out of range");
int MyNewIndex = newIndex; //so that I don't override anything that goes to base.MoveItem
if (oldIndex < newIndex)
MyNewIndex--;
RowType dr = (RowType)_dt.Rows[oldIndex];
_dt.Rows.RemoveAt(oldIndex);
if (MyNewIndex == _dt.Rows.Count)
_dt.Rows.Add(dr);
else
_dt.Rows.InsertAt(dr, MyNewIndex);
dr = null;
base.MoveItem(oldIndex, newIndex);
}
protected override void RemoveItem(int index)
{
if (index >= _dt.Rows.Count) throw new ArgumentOutOfRangeException("Argument is out of range");
_dt.Rows[index].Delete(); //Or if you do not need the data to persist in your data store, simply _dt.Rows.RemoveAt(index);
base.RemoveItem(index);
}
protected override void SetItem(int index, RowType item)
{
if (index >= _dt.Rows.Count) throw new ArgumentOutOfRangeException("Argument is out of range");
_dt.Rows.RemoveAt(index);
if (index > _dt.Rows.Count - 1)
_dt.Rows.Add(item);
else
_dt.Rows.InsertAt(item, index);
base.SetItem(index, item);
}
}
The idea is that you inherit from ObservableCollection and rather than manipulating copies of the data you simply manipulate the references to your data. This way, when your Row is updated in the datatable it will be updated in your ObservableCollection as well (though no ObservableCollection events will be fired).
Because of the generics, this also should work for Typed DataTables and provide you access to the DataRow's properties (including DataColumns).
This should also, in theory, allow you to use the ObservableCollection as a proxy to your DataTable for Add/Delete/Modify stuff.
Obviously, since I am still working on this for my project, it is entirely possible that I may have missed something big, but as of this moment, I don't see why this wouldn't work (as I'm pretty sure that Rows[Index].Delete() set the DataRowState property instead of actually Deleting the DataRow object).
精彩评论