Browse Source

PRS MOBILE - DataGrid changes

Nick-PRSDigital@bitbucket.org 2 years ago
parent
commit
4737b30f68

+ 23 - 3
prs.mobile/comal.timesheets/BaseMobileGrid.cs

@@ -1,4 +1,5 @@
-using InABox.Core;
+using InABox.Clients;
+using InABox.Core;
 using Syncfusion.SfDataGrid.XForms;
 using System;
 using System.Collections.Generic;
@@ -6,8 +7,27 @@ using System.Text;
 
 namespace comal.timesheets
 {
-    public interface BaseMobileGrid
+    public static class BaseMobileGrid<TEntity> where TEntity : Entity, IRemotable, IPersistent, new()
     {
-        public void Setup(List<MobileGridDataModelShell> data);
+        public static List<Guid> GetIDs(Filter<TEntity> filter)
+        {
+            var client = new MultiQuery();
+            client.Add(
+                    new QueryDef<TEntity>(
+                        filter,
+                        new Columns<TEntity>(x => x.ID),
+                        null
+                    ),
+                    typeof(TEntity)
+                );
+            var table = client.Get(typeof(TEntity));
+
+            List<Guid> ids = new List<Guid>();
+            foreach (var row in table.Rows)
+            {
+               ids.Add(row.Get<Guid>("ID"));
+            }
+            return ids;
+        }
     }
 }

+ 1 - 18
prs.mobile/comal.timesheets/DataGrid.xaml

@@ -11,28 +11,11 @@
             </Grid.RowDefinitions>
 
             <!-- Header Rows-->
-            <Grid Grid.Row="1">
+            <Grid Grid.Row="1" x:Name="headerGrid">
                 <Grid.RowDefinitions>
                     <RowDefinition Height="40"/>
                     <RowDefinition Height="40"/>
                 </Grid.RowDefinitions>
-                <Grid.ColumnDefinitions>
-                    <ColumnDefinition Width="*"/>
-                    <ColumnDefinition Width="*"/>
-                    <ColumnDefinition Width="*"/>
-                    <ColumnDefinition Width="*"/>
-                </Grid.ColumnDefinitions>
-
-                <timesheets:DataGridHeaderRow Grid.Row="0" Grid.Column="0" x:Name="HeaderRow0"/>
-                <timesheets:DataGridHeaderRow Grid.Row="0" Grid.Column="1" x:Name="HeaderRow1"/>
-                <timesheets:DataGridHeaderRow Grid.Row="0" Grid.Column="2" x:Name="HeaderRow2"/>
-                <timesheets:DataGridHeaderRow Grid.Row="0" Grid.Column="3" x:Name="HeaderRow3"/>
-
-                <timesheets:DataGridSearchEntry Grid.Row="1" Grid.Column="0" x:Name="searchEnt0"/>
-                <timesheets:DataGridSearchEntry Grid.Row="1" Grid.Column="1" x:Name="searchEnt1"/>
-                <timesheets:DataGridSearchEntry Grid.Row="1" Grid.Column="2" x:Name="searchEnt2"/>
-                <timesheets:DataGridSearchEntry Grid.Row="1" Grid.Column="3" x:Name="searchEnt3"/>
-                
             </Grid>
 
             <ListView Grid.Row="2" HasUnevenRows="True" x:Name="listView"/>

+ 114 - 8
prs.mobile/comal.timesheets/DataGrid.xaml.cs

@@ -9,12 +9,118 @@ using Xamarin.Forms.Xaml;
 
 namespace comal.timesheets
 {
-	[XamlCompilation(XamlCompilationOptions.Compile)]
-	public partial class DataGrid : ContentPage
-	{
-		public DataGrid ()
-		{
-			InitializeComponent ();
-		}
-	}
+    [XamlCompilation(XamlCompilationOptions.Compile)]
+    public partial class DataGrid : ContentPage
+    {
+        public List<DataGridViewModelItem> Items { get; set; }
+
+        public DataGrid()
+        {
+            InitializeComponent();
+        }
+
+        public void Setup(List<DataGridViewModelItem> items)
+        {
+            SetupHeadersAndDataTemplate(items.First());
+            Items = items;
+            listView.ItemsSource = Items;
+        }
+
+        public void SetupHeadersAndDataTemplate(DataGridViewModelItem item)
+        {
+            GenerateHeaders(item);
+            GenerateDataTemplate(item);
+        }
+
+        private void GenerateDataTemplate(DataGridViewModelItem item)
+        {
+            var grid = new Grid();
+            int count = 0;
+            foreach (var tuple in item.Data)
+            {
+                grid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1, GridUnitType.Star) });
+                grid.Children.Add(CreateNewListViewLabel(count));
+                count++;
+            }
+            if (item.Image != null)
+            {
+                grid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1, GridUnitType.Star) });
+                grid.Children.Add(CreatNewListViewImage(count, item.Image.Source));
+            }
+            listView.ItemTemplate = new DataTemplate(() =>
+            {
+                return new ViewCell { View = grid };
+            });
+        }
+
+        private View CreatNewListViewImage(int count, ImageSource source)
+        {
+            var img = new Image { Source = source };
+            img.SetBinding(Image.SourceProperty, "Source");
+            return SetGridValues(img, 0, count);
+        }
+
+        private View CreateNewListViewLabel(int count)
+        {
+            var lbl = new Label();
+            lbl.SetBinding(Label.TextProperty, "Col" + count);
+            return SetGridValues(lbl, 0, count);
+        }
+
+        public void GenerateHeaders(DataGridViewModelItem item)
+        {
+            int count = 0;
+            foreach (var tuple in item.Data)
+            {
+                CreateNewHeader(tuple.Item1, count);
+                count++;
+            }
+            if (item.Image != null)
+                CreateNewHeader("Image", count);
+        }
+
+        private void CreateNewHeader(string name, int count)
+        {
+            headerGrid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1, GridUnitType.Star) });
+            var header = new DataGridHeaderRow { ColumnName = name, ColumnNumber = count };
+            header.OnDataGridHeaderFilterTapped += Header_OnDataGridHeaderFilterTapped;
+            header.OnDataGridHeaderTapped += Header_OnDataGridHeaderTapped;
+            headerGrid.Children.Add(SetGridValues(header, 0, count));
+            CreateSearchEntry(name, count);
+        }
+
+        private void CreateSearchEntry(string name, int count)
+        {
+            var searchEnt = new DataGridSearchEntry { ColumnName = name, ColumnNumber = count };
+            searchEnt.OnDataGridSearchEntryChanged += SearchEnt_OnDataGridSearchEntryChanged;
+            searchEnt.IsEnabled = name == "Image" ? false : true;
+            headerGrid.Children.Add(SetGridValues(searchEnt, 1, count));
+        }
+
+        private View SetGridValues(View view, int row, int column)
+        {
+            view.SetValue(Grid.RowProperty, row);
+            view.SetValue(Grid.ColumnProperty, column);
+            return view;
+        }
+
+        #region Events
+        private void SearchEnt_OnDataGridSearchEntryChanged(int columnnumber, string value)
+        {
+
+        }
+
+        private void Header_OnDataGridHeaderTapped(int columnnumber)
+        {
+
+        }
+
+        private void Header_OnDataGridHeaderFilterTapped(int columnnumber, string columnname)
+        {
+
+        }
+        #endregion
+
+    }
+    
 }

+ 25 - 14
prs.mobile/comal.timesheets/DataGridHeaderRow.xaml

@@ -2,18 +2,29 @@
 <ContentView xmlns="http://xamarin.com/schemas/2014/forms" 
              xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
              x:Class="comal.timesheets.DataGridHeaderRow">
-  <ContentView.Content>
-        <Grid>
-            <Grid.ColumnDefinitions>
-                <ColumnDefinition Width="*"/>
-                <ColumnDefinition Width="40"/>
-            </Grid.ColumnDefinitions>
-            <Button Grid.Column="0" x:Name="headerBtn" Clicked="HeaderBtn_Clicked"/>
-            <Image Source="filter.png">
-                <Image.GestureRecognizers>
-                    <TapGestureRecognizer Tapped="Image_tapped"/>
-                </Image.GestureRecognizers>
-            </Image>
-        </Grid>
-  </ContentView.Content>
+    <ContentView.Content>
+        <Frame Margin="0" Padding="0" HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand" BorderColor="DimGray">
+            <Grid>
+                <Grid.RowDefinitions>
+                    <RowDefinition Height="auto"/>
+                    <RowDefinition Height="30"/>
+                </Grid.RowDefinitions>
+
+
+                <Label Grid.Row="0" x:Name="headerBtn" LineBreakMode="WordWrap" MaxLines="2" HorizontalTextAlignment="Center"
+                   HorizontalOptions="Center" Text="placeholder">
+                    <Label.GestureRecognizers>
+                        <TapGestureRecognizer Tapped="HeaderBtn_Clicked"/>
+                    </Label.GestureRecognizers>
+                </Label>
+
+                <Image Grid.Row="1" Source="filter.png" HeightRequest="30" WidthRequest="30" x:Name="filterBtn">
+                    <Image.GestureRecognizers>
+                        <TapGestureRecognizer Tapped="Image_tapped"/>
+                    </Image.GestureRecognizers>
+                </Image>
+
+            </Grid>
+        </Frame>
+    </ContentView.Content>
 </ContentView>

+ 28 - 19
prs.mobile/comal.timesheets/DataGridHeaderRow.xaml.cs

@@ -9,29 +9,38 @@ using Xamarin.Forms.Xaml;
 
 namespace comal.timesheets
 {
-	public delegate void DataGridHeaderTapped(string columnname);
-	public delegate void DataGridHeaderFilterTapped(string columnname);
+    public delegate void DataGridHeaderTapped(int columnnumber);
+    public delegate void DataGridHeaderFilterTapped(int columnnumber, string columnname);
 
-	[XamlCompilation(XamlCompilationOptions.Compile)]
-	public partial class DataGridHeaderRow : ContentView
-	{
-		public event DataGridHeaderTapped OnDataGridHeaderTapped;
-		public event DataGridHeaderFilterTapped OnDataGridHeaderFilterTapped;
-		public string ColumnName { get; set; }
-		public DataGridHeaderRow ()
-		{
-			InitializeComponent ();
-		}
+    [XamlCompilation(XamlCompilationOptions.Compile)]
+    public partial class DataGridHeaderRow : ContentView
+    {
+        public event DataGridHeaderTapped OnDataGridHeaderTapped;
+        public event DataGridHeaderFilterTapped OnDataGridHeaderFilterTapped;
+        public string ColumnName    { get; set; }
 
-		private void HeaderBtn_Clicked(object sender, EventArgs e)
-		{
-			OnDataGridHeaderTapped?.Invoke(ColumnName);
-		}
+        public int ColumnNumber { get; set; }
+        public DataGridHeaderRow()
+        {
+            InitializeComponent();
+        }
+
+        private void HeaderBtn_Clicked(object sender, EventArgs e)
+        {
+            OnDataGridHeaderTapped?.Invoke(ColumnNumber);
+        }
 
-		private void Image_tapped(object sender, EventArgs e)
-		{
-			OnDataGridHeaderFilterTapped?.Invoke(ColumnName);
+        private void Image_tapped(object sender, EventArgs e)
+        {
+            OnDataGridHeaderFilterTapped?.Invoke(ColumnNumber, ColumnName);
+        }
 
+        public void Setup()
+        {
+            headerBtn.Text = ColumnName;
+            if (ColumnName == "Image")
+                filterBtn.IsVisible = false;
+            ForceLayout();
         }
     }
 }

+ 4 - 2
prs.mobile/comal.timesheets/DataGridSearchEntry.cs

@@ -5,19 +5,21 @@ using Xamarin.Forms;
 
 namespace comal.timesheets
 {
-    public delegate void DataGridSearchEntryChanged(string ColumnName, string Value);
+    public delegate void DataGridSearchEntryChanged(int columnnumber, string value);
     public class DataGridSearchEntry : Entry
     {
         public event DataGridSearchEntryChanged OnDataGridSearchEntryChanged;
         public string ColumnName { get; set; }
+        public int ColumnNumber { get; set; }
         public DataGridSearchEntry()
         {
             TextChanged += DataGridSearchEntry_TextChanged;
+            BackgroundColor = Color.Cornsilk;
         }
 
         private void DataGridSearchEntry_TextChanged(object sender, TextChangedEventArgs e)
         {
-            OnDataGridSearchEntryChanged?.Invoke(ColumnName, Text);
+            OnDataGridSearchEntryChanged?.Invoke(ColumnNumber, Text);
         }
     }
 }

+ 57 - 53
prs.mobile/comal.timesheets/Main/MainPage.xaml.cs

@@ -1296,68 +1296,72 @@ namespace comal.timesheets
         {
             await Task.Run(() =>
             {
-                List<EmployeeShell> employeeShells = new List<EmployeeShell>();
-                List<EmployeeShell> teamEmployeeShells = new List<EmployeeShell>();
+                try
+                {
+                    List<EmployeeShell> employeeShells = new List<EmployeeShell>();
+                    List<EmployeeShell> teamEmployeeShells = new List<EmployeeShell>();
 
-                MultiQuery query = new MultiQuery();
+                    MultiQuery query = new MultiQuery();
 
-                query.Add<Employee>(
-                    LookupFactory.DefineFilter<Employee>(),
-                    new Columns<Employee>(x => x.ID)
-                        .Add(x => x.Code)
-                        .Add(x => x.Name),
-                    LookupFactory.DefineSort<Employee>()
-                );
+                    query.Add<Employee>(
+                        LookupFactory.DefineFilter<Employee>(),
+                        new Columns<Employee>(x => x.ID)
+                            .Add(x => x.Code)
+                            .Add(x => x.Name),
+                        LookupFactory.DefineSort<Employee>()
+                    );
 
-                query.Add<Team>(
-                    LookupFactory.DefineFilter<Team>(),
-                    new Columns<Team>(x => x.Name),
-                    new SortOrder<Team>(x => x.Name)
-                );
+                    query.Add<Team>(
+                        LookupFactory.DefineFilter<Team>(),
+                        new Columns<Team>(x => x.Name),
+                        new SortOrder<Team>(x => x.Name)
+                    );
 
-                query.Add<EmployeeTeam>(
-                    LookupFactory.DefineFilter<EmployeeTeam>(),
-                    new Columns<EmployeeTeam>(x => x.EmployeeLink.ID)
-                        .Add(x => x.EmployeeLink.Code)
-                        .Add(x => x.EmployeeLink.Name)
-                        .Add(x => x.TeamLink.Name),
-                    new SortOrder<EmployeeTeam>(x => x.EmployeeLink.Name)
-                );
+                    query.Add<EmployeeTeam>(
+                        LookupFactory.DefineFilter<EmployeeTeam>(),
+                        new Columns<EmployeeTeam>(x => x.EmployeeLink.ID)
+                            .Add(x => x.EmployeeLink.Code)
+                            .Add(x => x.EmployeeLink.Name)
+                            .Add(x => x.TeamLink.Name),
+                        new SortOrder<EmployeeTeam>(x => x.EmployeeLink.Name)
+                    );
 
-                query.Query();
+                    query.Query();
 
-                CoreTable emps = query.Get<Employee>();
-                foreach (var row in emps.Rows)
-                {
-                    employeeShells.Add(
-                        new EmployeeShell()
-                        {
-                            ID = row.Get<Employee, Guid>(x => x.ID),
-                            Code = row.Get<Employee, String>(x => x.Code),
-                            Name = row.Get<Employee, String>(x => x.Name),
-                            TeamName = "All Staff"
-                        }
-                    );
-                }
+                    CoreTable emps = query.Get<Employee>();
+                    foreach (var row in emps.Rows)
+                    {
+                        employeeShells.Add(
+                            new EmployeeShell()
+                            {
+                                ID = row.Get<Employee, Guid>(x => x.ID),
+                                Code = row.Get<Employee, String>(x => x.Code),
+                                Name = row.Get<Employee, String>(x => x.Name),
+                                TeamName = "All Staff"
+                            }
+                        );
+                    }
 
-                GlobalVariables.TeamNames = query.Get<Team>().Rows.Select(r => r.Get<Team, String>(c => c.Name)).ToList();
+                    GlobalVariables.TeamNames = query.Get<Team>().Rows.Select(r => r.Get<Team, String>(c => c.Name)).ToList();
 
-                CoreTable members = query.Get<EmployeeTeam>();
-                foreach (var row in members.Rows)
-                {
-                    teamEmployeeShells.Add(
-                        new EmployeeShell()
-                        {
-                            ID = row.Get<EmployeeTeam, Guid>(x => x.EmployeeLink.ID),
-                            Code = row.Get<EmployeeTeam, String>(x => x.EmployeeLink.Code),
-                            Name = row.Get<EmployeeTeam, String>(x => x.EmployeeLink.Name),
-                            TeamName = row.Get<EmployeeTeam, String>(x => x.TeamLink.Name)
-                        }
-                    );
-                }
+                    CoreTable members = query.Get<EmployeeTeam>();
+                    foreach (var row in members.Rows)
+                    {
+                        teamEmployeeShells.Add(
+                            new EmployeeShell()
+                            {
+                                ID = row.Get<EmployeeTeam, Guid>(x => x.EmployeeLink.ID),
+                                Code = row.Get<EmployeeTeam, String>(x => x.EmployeeLink.Code),
+                                Name = row.Get<EmployeeTeam, String>(x => x.EmployeeLink.Name),
+                                TeamName = row.Get<EmployeeTeam, String>(x => x.TeamLink.Name)
+                            }
+                        );
+                    }
 
-                GlobalVariables.EmployeeShells = employeeShells;
-                GlobalVariables.TeamEmployeeShells = teamEmployeeShells;
+                    GlobalVariables.EmployeeShells = employeeShells;
+                    GlobalVariables.TeamEmployeeShells = teamEmployeeShells;
+                }
+                catch { }
             });
 
         }

+ 67 - 0
prs.mobile/comal.timesheets/MobileDataGrid.xaml

@@ -0,0 +1,67 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ContentView xmlns="http://xamarin.com/schemas/2014/forms" 
+             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
+             x:Class="comal.timesheets.MobileDataGrid">
+    <ContentView.Content>
+        <Grid>
+            <Grid.RowDefinitions>
+                <RowDefinition Height="60"/>
+                <RowDefinition Height="120"/>
+                <RowDefinition Height="*"/>
+                <RowDefinition Height="30"/>
+            </Grid.RowDefinitions>
+
+            <Frame Grid.Row="0" Padding="2" Margin="2" BorderColor="LightGray">
+                <Grid>
+                    <Grid.ColumnDefinitions>
+                        <ColumnDefinition Width="auto"/>
+                        <ColumnDefinition Width="*"/>
+                    </Grid.ColumnDefinitions>
+                    <Label Grid.Column="0" Text="Filters:" VerticalOptions="Center" FontAttributes="Bold"/>
+                    <FlexLayout Grid.Column="1" x:Name="filterLayout" Wrap="Wrap"
+                                    Direction="Row"
+                                    JustifyContent="SpaceEvenly"
+                                    AlignItems="Start"
+                                    AlignContent="Start"/>
+                </Grid>
+            </Frame>
+
+            <!-- Header Rows-->
+            <Frame Grid.Row="1" Margin="0" Padding="0" BackgroundColor="Transparent" VerticalOptions="FillAndExpand">
+                <Grid  x:Name="headerGrid" Margin="0" Padding="2">
+                    <Grid.RowDefinitions>
+                        <RowDefinition Height="70"/>
+                        <RowDefinition Height="40"/>
+                    </Grid.RowDefinitions>
+                </Grid>
+            </Frame>
+
+            <ListView Grid.Row="2" HasUnevenRows="True" x:Name="listView">
+                <ListView.ItemTemplate>
+                    <DataTemplate>
+                        <ViewCell>
+                            <Grid>
+                                <Grid.ColumnDefinitions>
+                                    <ColumnDefinition Width="{Binding ColWidth0}"/>
+                                    <ColumnDefinition Width="{Binding ColWidth1}"/>
+                                    <ColumnDefinition Width="{Binding ColWidth2}"/>
+                                    <ColumnDefinition Width="{Binding ColWidth3}"/>
+                                </Grid.ColumnDefinitions>
+
+                                <Label Grid.Column="0" Text="{Binding Col0}" Margin="5, 0, 5, 0"/>
+                                <Label Grid.Column="1" Text="{Binding Col1}" Margin="5, 0, 5, 0"/>
+                                <Label Grid.Column="2" Text="{Binding Col2}" Margin="5, 0, 5, 0"/>
+                                <Label Grid.Column="3" Text="{Binding Col3}" Margin="5, 0, 5, 0"/>
+                            </Grid>
+                        </ViewCell>
+                    </DataTemplate>
+                </ListView.ItemTemplate>
+            </ListView>
+
+            <Frame Grid.Row="3" BackgroundColor="LightGray" Padding="0">
+                <Label HorizontalOptions="Center" HorizontalTextAlignment="Center" x:Name="countLbl" VerticalOptions="Center"/>
+            </Frame>
+
+        </Grid>
+    </ContentView.Content>
+</ContentView>

+ 312 - 0
prs.mobile/comal.timesheets/MobileDataGrid.xaml.cs

@@ -0,0 +1,312 @@
+using Android.Content;
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Linq;
+using System.Reflection;
+using Xamarin.Forms;
+using Xamarin.Forms.Xaml;
+
+namespace comal.timesheets
+{
+    [XamlCompilation(XamlCompilationOptions.Compile)]
+    public partial class MobileDataGrid : ContentView
+    {
+        ObservableCollection<DataGridFilter> Filters = new ObservableCollection<DataGridFilter>();
+        public List<DataGridViewModelItem> Items { get; set; }
+
+        PropertyInfo[] info = typeof(DataGridViewModelItem).GetProperties();
+
+        Type Type;
+        public MobileDataGrid()
+        {
+            InitializeComponent();
+            Filters.CollectionChanged += Filters_CollectionChanged;
+        }
+
+        public void Setup(List<DataGridViewModelItem> items, Type type)
+        {
+            Type = type;
+            SetupHeadersAndDataTemplate(items.First());
+            Items = items;
+            Refresh(Items);
+        }
+
+        private void Refresh(List<DataGridViewModelItem> items)
+        {
+            listView.ItemsSource = items;
+            countLbl.Text = items.Count + " Records";
+        }
+
+        public void SetupHeadersAndDataTemplate(DataGridViewModelItem item)
+        {
+            GenerateHeaders(item);
+            //GenerateDataTemplate(item);
+        }
+
+        private void GenerateDataTemplate(DataGridViewModelItem item)
+        {
+            var grid = new Grid
+            {
+                HorizontalOptions = LayoutOptions.FillAndExpand,
+                VerticalOptions = LayoutOptions.Center,
+                Margin = new Thickness(0),
+                Padding = new Thickness(2),
+            };
+            grid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(1, GridUnitType.Auto) });
+            int count = 0;
+            foreach (var tuple in item.Data)
+            {
+                grid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1, GridUnitType.Star) });
+                grid.Children.Add(CreateNewListViewLabel(count));
+                count++;
+            }
+            if (item.Image != null)
+            {
+                grid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1, GridUnitType.Star) });
+                grid.Children.Add(CreatNewListViewImage(count, item.Image));
+            }
+            listView.ItemTemplate = new DataTemplate(() =>
+            {
+                return new ViewCell { View = grid };
+            });
+        }
+
+        private View CreatNewListViewImage(int count, Image img)
+        {
+            var newImage = new Image
+            {
+                Source = img.Source,
+                HeightRequest = 30,
+                WidthRequest = 30,
+                HorizontalOptions = LayoutOptions.Center,
+                VerticalOptions = LayoutOptions.Center
+            };
+            newImage.SetBinding(Image.SourceProperty, "Source");
+            return SetGridValues(newImage, 0, count);
+        }
+
+        private View CreateNewListViewLabel(int count)
+        {
+            var lbl = new Label();
+            lbl.SetBinding(Label.TextProperty, new Binding("Col" + count));
+            return SetGridValues(lbl, 0, count);
+        }
+
+        public void GenerateHeaders(DataGridViewModelItem item)
+        {
+            int count = 0;
+            foreach (var tuple in item.Data)
+            {
+                CreateNewHeader(tuple.Item1, count);
+                count++;
+            }
+            //if (item.Image != null)
+            //CreateNewHeader("Image", count);
+        }
+
+        private void CreateNewHeader(string name, int count)
+        {
+            headerGrid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1, GridUnitType.Star) });
+            DataGridHeaderRow header = new DataGridHeaderRow { ColumnName = name, ColumnNumber = count };
+            header.Setup();
+            header.OnDataGridHeaderFilterTapped += Header_OnDataGridHeaderFilterTapped;
+            header.OnDataGridHeaderTapped += Header_OnDataGridHeaderTapped;
+            headerGrid.Children.Add(SetGridValues(header, 0, count));
+            CreateSearchEntry(name, count);
+        }
+
+        private void CreateSearchEntry(string name, int count)
+        {
+            var searchEnt = new DataGridSearchEntry { ColumnName = name, ColumnNumber = count };
+            searchEnt.OnDataGridSearchEntryChanged += SearchEnt_OnDataGridSearchEntryChanged;
+            searchEnt.IsEnabled = name == "Image" ? false : true;
+            headerGrid.Children.Add(SetGridValues(searchEnt, 1, count));
+        }
+
+        private View SetGridValues(View view, int row, int column)
+        {
+            view.SetValue(Grid.RowProperty, row);
+            view.SetValue(Grid.ColumnProperty, column);
+            return view;
+        }
+
+        #region Events
+        private void SearchEnt_OnDataGridSearchEntryChanged(int columnnumber, string value)
+        {
+            if (string.IsNullOrWhiteSpace(value))
+                Filters.Remove(Filters.FirstOrDefault(x => x.ColNumber == "Col" + columnnumber));
+            else
+            {
+                if (Filters.FirstOrDefault(x => x.ColNumber == "Col" + columnnumber) != null)
+                    Filters.Remove(Filters.FirstOrDefault(x => x.ColNumber == "Col" + columnnumber));
+                Filters.Add(new DataGridFilter { ColNumber = "Col" + columnnumber, Value = value, FilterNumber = FindNumber(columnnumber) });
+            }
+        }
+
+        private FilterNumber FindNumber(int columnnumber)
+        {
+            switch (columnnumber)
+            {
+                case 0:
+                    return FilterNumber.Zero;
+                case 1:
+                    return FilterNumber.One;
+                case 2:
+                    return FilterNumber.Two;
+                case 3:
+                    return FilterNumber.Three;
+                default:
+                    return FilterNumber.Zero;
+            }
+        }
+
+        private void DoSearch()
+        {
+
+        }
+
+        bool bSearching = false;
+
+        private void Filters_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
+        {
+            if (bSearching)
+                return;
+
+            bSearching = true;
+
+            List<DataGridViewModelItem> finalList = new List<DataGridViewModelItem>();
+
+            if (Filters.FirstOrDefault(x => x.FilterNumber == FilterNumber.Zero) != null)
+            {
+                var filter = Filters.FirstOrDefault(x => x.FilterNumber == FilterNumber.Zero);
+                var list = Items.Where(x => x.Col0.Contains(filter.Value));
+                foreach (DataGridViewModelItem item in list)
+                    finalList.Add(item);
+            }
+            else
+            {
+                foreach (DataGridViewModelItem item in Items)
+                    finalList.Add(item);
+            }
+
+            if (Filters.FirstOrDefault(x => x.FilterNumber == FilterNumber.One) != null)
+            {
+                List<DataGridViewModelItem> intermediatelist = new List<DataGridViewModelItem>();
+                var filter = Filters.FirstOrDefault(x => x.FilterNumber == FilterNumber.One);
+                var list = finalList.Where(x => x.Col1.Contains(filter.Value));
+                foreach (var item in list)                
+                    intermediatelist.Add(item);
+                if (intermediatelist.Count > 0)
+                    finalList.Clear();
+                foreach (DataGridViewModelItem item in intermediatelist)
+                    finalList.Add(item);
+            }
+            else if (finalList.Count == 0)
+            {
+                foreach (DataGridViewModelItem item in Items)
+                    finalList.Add(item);
+            }
+
+            if (Filters.FirstOrDefault(x => x.FilterNumber == FilterNumber.Two) != null)
+            {
+                List<DataGridViewModelItem> intermediatelist = new List<DataGridViewModelItem>();
+                var filter = Filters.FirstOrDefault(x => x.FilterNumber == FilterNumber.Two);
+                var list = finalList.Where(x => x.Col2.Contains(filter.Value));
+                foreach (var item in list)
+                    intermediatelist.Add(item);
+                if (intermediatelist.Count > 0)
+                    finalList.Clear();
+                foreach (DataGridViewModelItem item in intermediatelist)
+                    finalList.Add(item);
+            }
+            else if (finalList.Count == 0)
+            {
+                foreach (DataGridViewModelItem item in Items)
+                    finalList.Add(item);
+            }
+
+            if (Filters.FirstOrDefault(x => x.FilterNumber == FilterNumber.Three) != null)
+            {
+                List<DataGridViewModelItem> intermediatelist = new List<DataGridViewModelItem>();
+                var filter = Filters.FirstOrDefault(x => x.FilterNumber == FilterNumber.Three);
+                var list = finalList.Where(x => x.Col3.Contains(filter.Value));
+                foreach (var item in list)
+                    intermediatelist.Add(item);
+                if (intermediatelist.Count > 0)
+                    finalList.Clear();
+                foreach (DataGridViewModelItem item in intermediatelist)
+                    finalList.Add(item);
+            }
+
+            Refresh(finalList);
+
+            bSearching = false;
+        }
+
+
+        private void Header_OnDataGridHeaderTapped(int columnnumber)
+        {
+
+        }
+
+        private void Header_OnDataGridHeaderFilterTapped(int columnnumber, string columnname)
+        {
+
+        }
+        #endregion
+
+    }
+
+    public enum FilterNumber
+    {
+        Zero,
+        One,
+        Two,
+        Three
+    }
+
+    public class DataGridFilter
+    {
+        public string ColNumber { get; set; }
+        public string Value { get; set; }
+        public FilterNumber FilterNumber { get; set; }
+    }
+    public class DataGridViewModelItem
+    {
+        public Guid ID { get; set; }
+
+        public List<Tuple<string, string>> Data { get; set; }
+        public string Col0 { get; set; }
+        public string Col1 { get; set; }
+        public string Col2 { get; set; }
+        public string Col3 { get; set; }
+        public Image Image { get; set; }
+        public ImageSource Source
+        {
+            get
+            {
+                return Image.Source;
+            }
+        }
+        public GridLength ColWidth0 { get; set; }
+        public GridLength ColWidth1 { get; set; }
+        public GridLength ColWidth2 { get; set; }
+        public GridLength ColWidth3 { get; set; }
+
+        public DataGridViewModelItem(Guid id, List<Tuple<string, string>> data, Image image = null)
+        {
+            ID = id;
+            Data = data;
+            Image = image;
+            Col0 = data.Count > 0 ? data[0].Item2 : "";
+            Col1 = data.Count > 1 ? data[1].Item2 : "";
+            Col2 = data.Count > 2 ? data[2].Item2 : "";
+            Col3 = data.Count > 3 ? data[3].Item2 : "";
+            ColWidth0 = data.Count > 0 ? new GridLength(1, GridUnitType.Star) : new GridLength(0, GridUnitType.Absolute);
+            ColWidth1 = data.Count > 1 ? new GridLength(1, GridUnitType.Star) : new GridLength(0, GridUnitType.Absolute);
+            ColWidth2 = data.Count > 2 ? new GridLength(1, GridUnitType.Star) : new GridLength(0, GridUnitType.Absolute);
+            ColWidth3 = data.Count > 3 ? new GridLength(1, GridUnitType.Star) : new GridLength(0, GridUnitType.Absolute);
+        }
+    }
+}

+ 5 - 5
prs.mobile/comal.timesheets/ProductsGrid.cs

@@ -9,7 +9,7 @@ using Xamarin.Forms;
 
 namespace comal.timesheets
 {
-    public class ProductsGrid : MobileGrid
+    public class ProductsGrid : MobileDataGrid
     {
         public ProductsGrid()
         {
@@ -23,7 +23,7 @@ namespace comal.timesheets
             if (!table.Rows.Any())
                 return;
 
-            List<MobileGridDataModelShell> shells = new List<MobileGridDataModelShell>();
+            List<DataGridViewModelItem> shells = new List<DataGridViewModelItem>();
             foreach (var row in table.Rows)
             {
                 List<Tuple<string, string>> tuples = new List<Tuple<string, string>>();
@@ -31,15 +31,15 @@ namespace comal.timesheets
                 tuples.Add(new Tuple<string, string>("Name", row.Get<Product, string>(x => x.Name)));
                 tuples.Add(new Tuple<string, string>("Family", row.Get<Product, string>(x => x.Group.Description)));
 
-                shells.Add(new MobileGridDataModelShell
+                shells.Add(new DataGridViewModelItem
                     (
                         row.Get<Product, Guid>(x => x.ID), 
                         tuples,
-                        row.Get<Product, Guid>(x => x.Image.ID) == Guid.Empty? new Image() : new Image { Source = "productimage.png" } 
+                        row.Get<Product, Guid>(x => x.Image.ID) == Guid.Empty? new Image() : new Image { Source = "productimage.png", HeightRequest = 30, WidthRequest = 30} 
                     ));
             }
 
-            Setup(shells);
+            Setup(shells, typeof(Product));
         }
     }
 }

+ 16 - 6
prs.mobile/comal.timesheets/comal.timesheets.projitems

@@ -226,11 +226,15 @@
     <Compile Include="$(MSBuildThisFileDirectory)DigitalForms\DataModels\IDigitalFormHostModel.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)DigitalForms\DataModels\FormPickerQueryLoader.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)DigitalForms\DataModels\IFormPickerQueryLoader.cs" />
-    <Compile Include="$(MSBuildThisFileDirectory)JobDocFilterItem.xaml.cs">
+    <Compile Include="$(MSBuildThisFileDirectory)MobileDataGrid.xaml.cs">
+      <DependentUpon>MobileDataGrid.xaml</DependentUpon>
+      <SubType>Code</SubType>
+    </Compile>
+    <Compile Include="$(MSBuildThisFileDirectory)Site\JobDocFilterItem.xaml.cs">
       <DependentUpon>JobDocFilterItem.xaml</DependentUpon>
       <SubType>Code</SubType>
     </Compile>
-    <Compile Include="$(MSBuildThisFileDirectory)JobDocsFilterPage.xaml.cs">
+    <Compile Include="$(MSBuildThisFileDirectory)Site\JobDocsFilterPage.xaml.cs">
       <DependentUpon>JobDocsFilterPage.xaml</DependentUpon>
       <SubType>Code</SubType>
     </Compile>
@@ -240,7 +244,7 @@
       <DependentUpon>MyDetailsPage.xaml</DependentUpon>
       <SubType>Code</SubType>
     </Compile>
-    <Compile Include="$(MSBuildThisFileDirectory)PopupEditor.xaml.cs">
+    <Compile Include="$(MSBuildThisFileDirectory)DigitalForms\CustomUserControls\PopupEditor.xaml.cs">
       <DependentUpon>PopupEditor.xaml</DependentUpon>
       <SubType>Code</SubType>
     </Compile>
@@ -1018,19 +1022,19 @@
     </EmbeddedResource>
   </ItemGroup>
   <ItemGroup>
-    <EmbeddedResource Include="$(MSBuildThisFileDirectory)JobDocsFilterPage.xaml">
+    <EmbeddedResource Include="$(MSBuildThisFileDirectory)Site\JobDocsFilterPage.xaml">
       <SubType>Designer</SubType>
       <Generator>MSBuild:UpdateDesignTimeXaml</Generator>
     </EmbeddedResource>
   </ItemGroup>
   <ItemGroup>
-    <EmbeddedResource Include="$(MSBuildThisFileDirectory)JobDocFilterItem.xaml">
+    <EmbeddedResource Include="$(MSBuildThisFileDirectory)Site\JobDocFilterItem.xaml">
       <SubType>Designer</SubType>
       <Generator>MSBuild:UpdateDesignTimeXaml</Generator>
     </EmbeddedResource>
   </ItemGroup>
   <ItemGroup>
-    <EmbeddedResource Include="$(MSBuildThisFileDirectory)PopupEditor.xaml">
+    <EmbeddedResource Include="$(MSBuildThisFileDirectory)DigitalForms\CustomUserControls\PopupEditor.xaml">
       <SubType>Designer</SubType>
       <Generator>MSBuild:UpdateDesignTimeXaml</Generator>
     </EmbeddedResource>
@@ -1053,4 +1057,10 @@
       <Generator>MSBuild:UpdateDesignTimeXaml</Generator>
     </EmbeddedResource>
   </ItemGroup>
+  <ItemGroup>
+    <EmbeddedResource Include="$(MSBuildThisFileDirectory)MobileDataGrid.xaml">
+      <SubType>Designer</SubType>
+      <Generator>MSBuild:UpdateDesignTimeXaml</Generator>
+    </EmbeddedResource>
+  </ItemGroup>
 </Project>