How do you deal with DataSet in MVVM?
-
Friday, April 24, 2009 7:50 PMSince DataSet is somehow a first-class binding source, is there a need to wrap the DataTable into an Object Model? DataTable is already a model representation on its own, do you just need the ViewModel?
All Replies
-
Monday, April 27, 2009 7:06 AM
You can convert DataTable (DataSet is constructed by one or more DataTables) into ObservableCollection and then bind ObservableCollection to UI element.
For example:
XAML
<Window x:Class="_temple.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:_temple" xmlns:sys="clr-namespace:System;assembly=mscorlib" Width="892" Height="612"> <Canvas Background="Azure"> <ComboBox Canvas.Left="60" Canvas.Top="12" Height="23" Name="ddl" Width="120" SelectionChanged="ddl_SelectionChanged"> <ComboBox.ItemTemplate> <DataTemplate> <ComboBoxItem> <Binding></Binding> </ComboBoxItem> </DataTemplate> </ComboBox.ItemTemplate> </ComboBox> <ListView Canvas.Left="12" Canvas.Top="46" Height="516" Name="MyListView" Width="846" > <ListView.View> <GridView AllowsColumnReorder="true" > <GridViewColumn Header="Project"> <GridViewColumn.CellTemplate> <DataTemplate> <TextBlock Width="30"> <TextBlock.Text> <Binding Path="Project"></Binding> </TextBlock.Text> </TextBlock> </DataTemplate> </GridViewColumn.CellTemplate> </GridViewColumn> <GridViewColumn Width="720" > <GridViewColumn.HeaderTemplate> <DataTemplate> <StackPanel Name="HeaderContainer" Orientation="Horizontal"> <TextBlock Width="23">1</TextBlock> <TextBlock Width="23">2</TextBlock> <TextBlock Width="23">3</TextBlock> <TextBlock Width="23">4</TextBlock> <TextBlock Width="23">5</TextBlock> <TextBlock Width="23">6</TextBlock> <TextBlock Width="23">7</TextBlock> <TextBlock Width="23">8</TextBlock> <TextBlock Width="23">9</TextBlock> <TextBlock Width="23">10</TextBlock> <TextBlock Width="23">11</TextBlock> <TextBlock Width="23">12</TextBlock> <TextBlock Width="23">13</TextBlock> <TextBlock Width="23">14</TextBlock> <TextBlock Width="23">15</TextBlock> <TextBlock Width="23">16</TextBlock> <TextBlock Width="23">17</TextBlock> <TextBlock Width="23">18</TextBlock> <TextBlock Width="23">19</TextBlock> <TextBlock Width="23">20</TextBlock> <TextBlock Width="23">21</TextBlock> <TextBlock Width="23">22</TextBlock> <TextBlock Width="23">23</TextBlock> <TextBlock Width="23">24</TextBlock> <TextBlock Width="23">25</TextBlock> <TextBlock Width="23">26</TextBlock> <TextBlock Width="23">27</TextBlock> <TextBlock Width="23">28</TextBlock> <TextBlock Width="23">29</TextBlock> <TextBlock Width="23">30</TextBlock> <TextBlock Width="23">31</TextBlock> </StackPanel> </DataTemplate> </GridViewColumn.HeaderTemplate> <GridViewColumn.CellTemplate> <DataTemplate> <StackPanel Loaded="MyStackPanel_Loaded" Name="MyStackPanel" Orientation="Horizontal"> <StackPanel.Tag> <Binding></Binding> </StackPanel.Tag> </StackPanel> </DataTemplate> </GridViewColumn.CellTemplate> </GridViewColumn> <GridViewColumn Header="TotalHours"> <GridViewColumn.CellTemplate> <DataTemplate> <TextBlock Width="60"> <TextBlock.Text> <Binding Path="TotalHours"></Binding> </TextBlock.Text> </TextBlock> </DataTemplate> </GridViewColumn.CellTemplate> </GridViewColumn> </GridView> </ListView.View> </ListView> <Label Canvas.Left="12" Canvas.Top="12" Height="28" Width="42">User:</Label> <Button Canvas.Left="198" Canvas.Top="12" Height="23" Name="btnAddData" Width="75" Click="btnAddData_Click">Add Data</Button> </Canvas> </Window>
C#
using System; using System.Collections.Generic; using System.Windows; using System.Windows.Controls; using System.Windows.Documents; using System.Collections.ObjectModel; using System.Data; using System.Threading; namespace _temple { /// <summary> /// Interaction logic for Window1.xaml /// </summary> public partial class Window1 : Window { public DataTable data = new DataTable(); public DataTable dtBind = new DataTable(); public ObservableCollection<int> UserIDList = new ObservableCollection<int>(); ObservableCollection<ProjectWorkHours> DataList = new ObservableCollection<ProjectWorkHours>(); public Window1() { InitializeComponent(); Display(); } public void Display() { data = new DataTable(); data.Columns.Add("UserID"); data.Columns.Add("ProjectID"); data.Columns.Add("Day"); data.Columns.Add("Number"); //add some data AddData(); //Set Bind dtBind = data.Copy(); ConvertDataTable(dtBind); this.MyListView.ItemsSource = DataList; //Get all users ResetUserList(data); //Bind UserList to ComboBox ddl.ItemsSource = UserIDList; ddl.SelectedIndex =0; } public void AddData() { #region Random r = new Random(); for (int i = 1; i <= 10; i++) { for (int n = 1; n <= 5; n++) { for (int j = 0; j < 30; j++) { Thread.Sleep(1); int randomDay = r.Next(30) + 1; AddRow(i , n, randomDay, 1); } } } #endregion } public void ResetUserList( DataTable dt ) { UserIDList.Clear(); for ( int i = 0 ; i < dt.Rows.Count; i ++ ) { DataRow dr = dt.Rows[i]; int UserID = int.Parse( dr["UserID"].ToString() ); if ( !UserIDList.Contains( UserID ) ) { UserIDList.Add( UserID ); } } } public void AddRow( int _user, int _pro, int _day, int _num ) { DataRow dr = data.NewRow(); dr["UserID"] = _user; dr["ProjectID"] = _pro; dr["Day"] = _day; dr["Number"] = _num; data.Rows.Add(dr); } private void ddl_SelectionChanged(object sender, SelectionChangedEventArgs e) { RefreshData(); } public void RefreshData() { //Change the dtBind using Select string userid = ddl.SelectedItem.ToString(); DataRow[] drC = data.Select("UserID='" + userid + "'"); dtBind.Rows.Clear(); for (int i = 0; i < drC.Length; i++) { DataRow dr = dtBind.NewRow(); DataRow _dr = drC[i]; dr["UserID"] = _dr["UserID"]; dr["ProjectID"] = _dr["ProjectID"]; dr["Day"] = _dr["Day"]; dr["Number"] = _dr["Number"]; dtBind.Rows.Add(dr); } ConvertDataTable(dtBind); MyListView.ItemsSource = DataList; } public void ConvertDataTable( DataTable dt ) { DataList = new ObservableCollection<ProjectWorkHours>(); //Scan and arrange data into ObservableCollection int UserID = 0; if ( dt.Rows.Count >0 ) { UserID = int.Parse( dt.Rows[0]["UserID"].ToString() ); //Distill project id list List<int> ProjectIDList = GetProjectIDList( dt ); for ( int i = 0 ; i < ProjectIDList.Count; i ++ ) { int ProjectID= ProjectIDList[i]; //Get WorkRecord int[] MyWorkRecord = GetWorkRecord(dt, ProjectID); ProjectWorkHours newProjectWorkHours = new ProjectWorkHours(UserID,ProjectID,MyWorkRecord); DataList.Add( newProjectWorkHours); } } } public List<int> GetProjectIDList( DataTable dt ) { List<int> ProjectIDList = new List<int>(); for ( int i = 0 ; i < dt.Rows.Count; i ++ ) { DataRow dr = dt.Rows[i]; int ProjectID = int.Parse( dr["ProjectID"].ToString() ); if ( !ProjectIDList.Contains( ProjectID ) ) { ProjectIDList.Add(ProjectID); } } return ProjectIDList; } public int[] GetWorkRecord( DataTable dt, int ProjectID ) { int[] MyWorkRecord = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; //scan the data DataRow[] drScan = dt.Select( " ProjectID='"+ProjectID+"' " ); for (int i = 0; i < drScan.Length; i++) { DataRow dr = drScan[i]; int day = int.Parse( dr["Day"].ToString() ); int num = int.Parse( dr["Number"].ToString() ); MyWorkRecord[day-1] += num; } return MyWorkRecord; } private void MyStackPanel_Loaded(object sender, RoutedEventArgs e) { StackPanel MyStackPanel = sender as StackPanel; if (MyStackPanel != null) { MyStackPanel.Children.Clear(); for (int i = 1; i <= 31; i++) { TextBox txt = new TextBox(); txt.Width = 23; ProjectWorkHours PW = MyStackPanel.Tag as ProjectWorkHours; if (PW != null) { txt.Text = PW.WorkRecord[i - 1].ToString(); } MyStackPanel.Children.Add(txt); } } } private void btnAddData_Click(object sender, RoutedEventArgs e) { Random r = new Random(); for (int i = 0; i < 4; i++) { int randomPro = r.Next(4) + 1; int randomDay = r.Next(30)+1; AddRow(i+1, randomPro, randomDay, 1); } RefreshData(); } } public class ProjectWorkHours { public int User { set; get; } public int Project {set;get;} public int[] WorkRecord {set;get;} public int TotalHours{set;get;} public ProjectWorkHours( int _user, int _proj, int[] _work ) { User = _user; Project = _proj; WorkRecord = _work; TotalHours = SumTotal( _work ); } public int SumTotal( int[] number ) { int result = 0; for ( int i = 0 ; i < number.Length; i ++ ) { result += number[i]; } return result; } } } -
Monday, April 27, 2009 3:01 PM
Thanks for the sample code. So there seems to be no need for an actual Model, just a View-Model. Is that pretty standard? -
Monday, April 27, 2009 3:36 PMThe DataTable itself is the Model here, isn't it?
-
Monday, April 27, 2009 7:56 PM
It's a rough Model, but it is a Model. I'm just wondering if it's customary to create a wrapper for the DataTable, or if it is by "need" basis.
-
Tuesday, April 28, 2009 7:15 AMBy need. Design patterns are a guide, they aren't set in stone. Besides, M-V-VM is supposed to deal with anything you can think of as a Model, some DataTables from a SQL database is a typical scenario, IMHO.
-
Thursday, July 08, 2010 3:29 PMWhat if you needed to convert that Observable collection back to a dataset so it could be saved?

