Quellcode durchsuchen

Renamed GlobalConfigurationSettings interface to IGlobalConfigurationSettings
Removed unnecessary CoreTable.ToList()
Added Customer Filtering and Searching to Equipment Grid

Frank van den Bos vor 2 Jahren
Ursprung
Commit
6086c8d59f

+ 1 - 1
prs.classes/Settings/DFLayoutVideoSettings.cs

@@ -7,7 +7,7 @@ using static InABox.Core.DFLayoutVideoFieldProperties;
 
 namespace PRSClasses
 {
-    public class DFLayoutVideoSettings : GlobalConfigurationSettings
+    public class DFLayoutVideoSettings : IGlobalConfigurationSettings
     {
         [IntegerEditor(ToolTip = "Maximum video length (sec)")]
         public int DefaultMaximumVideoLength { get; set; } = 15;

+ 1 - 1
prs.classes/Settings/WebSettings.cs

@@ -4,7 +4,7 @@ using InABox.Core;
 
 namespace PRSClasses
 {
-    public class WebSettings : BaseObject, GlobalConfigurationSettings
+    public class WebSettings : BaseObject, IGlobalConfigurationSettings
     {
         [TextBoxEditor]
         [EditorSequence(1)]

+ 4 - 4
prs.desktop/Dashboards/Common/DigitalFormsDashboard.xaml.cs

@@ -132,7 +132,7 @@ namespace PRSDesktop
                         .Add(x => x.JobNumber)
                         .Add(x => x.Name)));
 
-            DigitalForms = results.Get<DigitalForm>().ToList<DigitalForm>();
+            DigitalForms = results.Get<DigitalForm>().ToObjects<DigitalForm>().ToList();
 
             var categories = new DigitalFormCategoryLookups(null);
             categories.OnAfterGenerateLookups += (sender, entries) => { entries.Insert(0, new LookupEntry("", "Select Category")); };
@@ -142,7 +142,7 @@ namespace PRSDesktop
                 .Cast<KeyValuePair<object, string>>()
                 .ToDictionary(x => (x.Key as string)!, x => x.Value);
 
-            Jobs = results.Get<Job>().ToList<Job>();
+            Jobs = results.Get<Job>().ToObjects<Job>().ToList();
             Jobs.Insert(0, new Job { ID = Guid.Empty, JobNumber = "ALL", Name = "All Jobs" });
 
             SetupHeader();
@@ -1105,8 +1105,8 @@ namespace PRSDesktop
 
             var results = Client.QueryMultiple(queries);
 
-            var questions = results.Get<QAQuestion>().ToList<QAQuestion>();
-            var variables = results.Get<DigitalFormVariable>().ToList<DigitalFormVariable>();
+            var questions = results.Get<QAQuestion>().ToObjects<QAQuestion>().ToList();
+            var variables = results.Get<DigitalFormVariable>().ToObjects<DigitalFormVariable>().ToList();
             var formData = results.Get(formQuery.Key);
 
             LoadDataIntoGrid(

+ 1 - 1
prs.desktop/Dashboards/Equipment/EquipmentSchedulesDashboard.xaml.cs

@@ -208,7 +208,7 @@ namespace PRSDesktop.Dashboards
                             x => x.Name,
                             x => x.Mobile,
                             x => x.Email))
-                    .ToList<Employee>();
+                    .ToObjects<Employee>().ToList();
                 var documents = new Client<Document>()
                     .Query(
                         new Filter<Document>(x => x.ID).InList(employees.Select(x => x.Thumbnail.ID).ToArray()),

+ 3 - 3
prs.desktop/Dashboards/Manufacturing/JobManufacturingSummary.xaml.cs

@@ -171,11 +171,11 @@ namespace PRSDesktop.Dashboards.Manufacturing
                         .Add(x => x.JobNumber)
                         .Add(x => x.Name)
                         .Add(x => x.Color))
-                .ToList<Job>();
+                .ToObjects<Job>().ToList();
 
             Factories = new Client<ManufacturingFactory>()
                 .Query(null, new Columns<ManufacturingFactory>(x => x.ID).Add(x => x.Name), new SortOrder<ManufacturingFactory>(x => x.Sequence))
-                .ToList<ManufacturingFactory>();
+                .ToObjects<ManufacturingFactory>().ToList();
 
             Sections = new Client<ManufacturingSection>()
                 .Query(
@@ -267,7 +267,7 @@ namespace PRSDesktop.Dashboards.Manufacturing
                         .Add(x => x.JobNumber)
                         .Add(x => x.Name)
                         .Add(x => x.Color))
-                .ToList<Job>();
+                .ToObjects<Job>().ToList();
 
             Refresh();
         }

+ 1 - 1
prs.desktop/Dashboards/Projects/JobDocumentStatusChart.xaml.cs

@@ -111,7 +111,7 @@ namespace PRSDesktop
                     new Columns<JobDocumentSetMileStoneType>(x => x.ID)
                         .Add(x => x.Code)
                         .Add(x => x.Description))
-                .ToList<JobDocumentSetMileStoneType>().ToDictionary(x => x.ID, x => x);
+                .ToObjects<JobDocumentSetMileStoneType>().ToDictionary(x => x.ID, x => x);
 
             int i = 0;
             MileStoneColours = MilestoneTypes.ToDictionary(x => x.Key, x => pallete[i++ % pallete.Count]);

+ 1 - 1
prs.desktop/Dashboards/UtilityDashboard.xaml.cs

@@ -72,7 +72,7 @@ namespace PRSDesktop
     //     }
     // }
 
-    public class GlobalUtilityDashboardSettings : GlobalConfigurationSettings
+    public class GlobalUtilityDashboardSettings : IGlobalConfigurationSettings
     {
         public List<DashboardFavourite> Favourites { get; set; }
 

+ 1 - 1
prs.desktop/Forms/Export/ExportGrid.cs

@@ -7,7 +7,7 @@ using InABox.DynamicGrid;
 
 namespace PRSDesktop.Forms.Export
 {
-    internal class ExportColumns : GlobalConfigurationSettings
+    internal class ExportColumns : IGlobalConfigurationSettings
     {
         public List<ExportColumn> Columns { get; set; }
     }

+ 4 - 4
prs.desktop/MainWindow.xaml.cs

@@ -2636,27 +2636,27 @@ namespace PRSDesktop
         }
         private void InitializePanelPropertiesGeneric<TPanel, TProperties>(TPanel panel)
             where TPanel : IPropertiesPanel<TProperties>
-            where TProperties : BaseObject, GlobalConfigurationSettings, new()
+            where TProperties : BaseObject, IGlobalConfigurationSettings, new()
         {
             panel.Properties = LoadPanelProperties<TPanel, TProperties>();
         }
         private TProperties LoadPanelProperties<TPanel, TProperties>()
             where TPanel : IPropertiesPanel<TProperties>
-            where TProperties : BaseObject, GlobalConfigurationSettings, new()
+            where TProperties : BaseObject, IGlobalConfigurationSettings, new()
         {
             var config = new GlobalConfiguration<TProperties>();
             return config.Load();
         }
         private void SavePanelProperties<TPanel, TProperties>(TProperties properties)
             where TPanel : IPropertiesPanel<TProperties>
-            where TProperties : BaseObject, GlobalConfigurationSettings, new()
+            where TProperties : BaseObject, IGlobalConfigurationSettings, new()
         {
             var config = new GlobalConfiguration<TProperties>();
             config.Save(properties);
         }
         private void EditPanelProperties<TPanel, TProperties>()
             where TPanel : IPropertiesPanel<TProperties>
-            where TProperties : BaseObject, GlobalConfigurationSettings, new()
+            where TProperties : BaseObject, IGlobalConfigurationSettings, new()
         {
             var properties = LoadPanelProperties<TPanel, TProperties>();
             var editor = new DynamicEditorForm(typeof(TProperties));

+ 1 - 1
prs.desktop/Panels/DataEntry/ScanGrid.cs

@@ -117,7 +117,7 @@ namespace PRSDesktop
 
         public static List<ScanTag> GetVisibleScanTagList()
         {
-            var tags = new Client<ScanTag>().Query().ToList<ScanTag>();
+            var tags = new Client<ScanTag>().Query().ToObjects<ScanTag>().ToList();
 
             var tagsList = new List<ScanTag>();
             foreach (var tag in tags)

+ 46 - 1
prs.desktop/Panels/Equipment/EquipmentGrid.cs

@@ -19,11 +19,21 @@ namespace PRSDesktop
         private readonly BitmapImage docs = PRSDesktop.Resources.doc_misc.AsBitmapImage();
 
         private readonly BitmapImage specification = PRSDesktop.Resources.doc_pdf.AsBitmapImage();
+        
+        public Guid CustomerID { get; set; }
+        public Guid GroupID { get; set; }
 
         public EquipmentGrid()
         {
+
+            CustomerID = Guid.Empty;
+            GroupID = CoreUtils.FullGuid;
+            
             Options.AddRange(DynamicGridOption.RecordCount, DynamicGridOption.SelectColumns, DynamicGridOption.FilterRows);
 
+            HiddenColumns.Add(x => x.Customer.ID);
+            HiddenColumns.Add(x => x.GroupLink.ID);
+
             ActionColumns.Add(new DynamicImageColumn(SpecificationImage, ShowSpecificationSheet) { Position = DynamicActionColumnPosition.Start });
             //HiddenColumns.Add(x => x.Specification.FileName);
             HiddenColumns.Add(x => x.SpecificationSheet.ID);
@@ -137,7 +147,12 @@ namespace PRSDesktop
         protected override void Reload(Filters<Equipment> criteria, Columns<Equipment> columns, ref SortOrder<Equipment> sort,
             Action<CoreTable, Exception> action)
         {
-            sort = new SortOrder<Equipment>(x => x.Code);
+            if (GroupID != CoreUtils.FullGuid)
+                criteria.Add(new Filter<Equipment>(x => x.GroupLink.ID).IsEqualTo(GroupID));
+            
+            if (CustomerID != CoreUtils.FullGuid)
+                criteria.Add(new Filter<Equipment>(x => x.Customer.ID).IsEqualTo(CustomerID));
+            
             base.Reload(criteria, columns, ref sort, action);
         }
 
@@ -179,5 +194,35 @@ namespace PRSDesktop
             var id = Entity.EntityLinkID<Equipment, ImageDocumentLink>(x => x.SpecificationSheet, arg);
             return id == null ? null : specification;
         }
+
+        public override bool EditItems(Equipment[] items, Func<Type, CoreTable>? PageDataHandler = null, bool PreloadPages = false)
+        {
+            var result = base.EditItems(items, PageDataHandler, PreloadPages);
+            if (result)
+            {
+                var changedcustomers = items.Any(x => x.Customer.ID != CustomerID);
+                var changedgroups = GroupID != CoreUtils.FullGuid
+                    ? items.Cast<Equipment>().Any(x => x.GroupLink.ID != GroupID)
+                    : false;
+                if (changedcustomers || changedgroups)
+                {
+                    Refresh(false, true);
+                    return false;
+                }
+            }
+
+            return result;
+        }
+
+        protected override BaseEditor? GetEditor(object item, DynamicGridColumn column)
+        {
+            if (String.Equals(column.ColumnName, CoreUtils.GetFullPropertyName<Equipment, Guid>(x => x.Customer.ID, ".")))
+            {
+                if (CustomerID == CoreUtils.FullGuid)
+                    return new NullEditor();
+            }
+
+            return base.GetEditor(item, column);
+        }
     }
 }

+ 63 - 3
prs.desktop/Panels/Equipment/EquipmentPanel.xaml

@@ -3,6 +3,7 @@
              xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
              xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
              xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+             xmlns:prsDesktop="clr-namespace:PRSDesktop"
              mc:Ignorable="d"
              d:DesignHeight="450" d:DesignWidth="800">
     <Grid x:Name="Grid">
@@ -10,14 +11,18 @@
             <ColumnDefinition Width="Auto" />
             <ColumnDefinition Width="*" />
         </Grid.ColumnDefinitions>
+        <Grid.RowDefinitions>
+            <RowDefinition Height="Auto"/>
+            <RowDefinition Height="*"/>
+        </Grid.RowDefinitions>
 
-        <ListView Grid.Column="0" Grid.Row="0" x:Name="Groups" SelectionChanged="Groups_SelectionChanged"
-                  Margin="0,0,5,0" BorderBrush="Black" HorizontalAlignment="Stretch">
+        <ListView Grid.Column="0" Grid.Row="0" Grid.RowSpan="2" x:Name="Groups" SelectionChanged="Groups_SelectionChanged"
+                  Margin="0,0,5,0" BorderBrush="Gray" HorizontalAlignment="Stretch" MinWidth="100">
             <ListView.ItemTemplate>
                 <DataTemplate>
                     <Grid Margin="5,10,5,5" HorizontalAlignment="Stretch">
                         <StackPanel Orientation="Vertical" HorizontalAlignment="Stretch">
-                            <Border Width="64" Height="64" CornerRadius="15" BorderBrush="Black" BorderThickness="1"
+                            <Border Width="64" Height="64" CornerRadius="15" BorderBrush="Gray" BorderThickness="0"
                                     VerticalAlignment="Center" HorizontalAlignment="Center">
                                 <Border.Background>
                                     <ImageBrush ImageSource="{Binding Path=Item3}" Stretch="UniformToFill" />
@@ -31,5 +36,60 @@
             </ListView.ItemTemplate>
         </ListView>
 
+        <Border BorderBrush="Gray" BorderThickness="0.75" Background="WhiteSmoke" Grid.Row="0" Grid.Column="1" Padding="5">
+            <DockPanel>
+                <Label 
+                    x:Name="CustomerLabel" 
+                    Content="Customer" 
+                    DockPanel.Dock="Left"/>
+                <TextBox 
+                    x:Name="Customer" 
+                    CharacterCasing="Upper" 
+                    BorderBrush="Gray" 
+                    BorderThickness="0.75,0.75,0,0.75" 
+                    DockPanel.Dock="Left" 
+                    Width="120" 
+                    Background="LightYellow"
+                    VerticalContentAlignment="Center" 
+                    KeyUp="Customer_OnKeyUp"
+                    TextChanged="Customer_OnTextChanged"/>
+                <Button 
+                    x:Name="CustomerSearch" 
+                    BorderBrush="Gray" 
+                    BorderThickness="0.75" 
+                    Content=".." 
+                    Padding="10,0" 
+                    DockPanel.Dock="Left"
+                    Click="CustomerSearch_OnClick"/>
+                <TextBox 
+                    x:Name="CustomerName" 
+                    BorderBrush="Gray" 
+                    BorderThickness="0.75" 
+                    DockPanel.Dock="Left" 
+                    Margin="5,0,0,0" 
+                    Width="250"
+                    Background="Transparent"
+                    VerticalContentAlignment="Center"/>
+                <Label 
+                    Content="Search" 
+                    DockPanel.Dock="Left" />
+                <TextBox 
+                    x:Name="Search" 
+                    BorderBrush="Gray" 
+                    BorderThickness="0.75" 
+                    DockPanel.Dock="Left" 
+                    Background="LightYellow"
+                    VerticalContentAlignment="Center"
+                    KeyUp="Search_OnKeyUp" 
+                    TextChanged="Search_OnTextChanged">
+                    
+                </TextBox>
+
+            </DockPanel>
+            
+        </Border>  
+        
+        
+        <prsDesktop:EquipmentGrid Grid.Row="1" Grid.Column="1" x:Name="_Equipment" OnFilterRecord="_Equipment_OnFilterRecord" Margin="0,2,0,0"/>
     </Grid>
 </UserControl>

+ 226 - 70
prs.desktop/Panels/Equipment/EquipmentPanel.xaml.cs

@@ -1,33 +1,62 @@
 using System;
 using System.Collections.Generic;
 using System.Collections.ObjectModel;
+using System.Diagnostics;
 using System.Linq;
 using System.Windows;
 using System.Windows.Controls;
+using System.Windows.Input;
 using System.Windows.Media.Imaging;
 using Comal.Classes;
 using InABox.Clients;
+using InABox.Configuration;
 using InABox.Core;
+using InABox.DynamicGrid;
 using InABox.WPF;
 
 namespace PRSDesktop
 {
+    
+    
+    public class EquipmentPanelSettings : BaseObject, IGlobalConfigurationSettings
+    {
+        public bool CustomerFilterEnabled { get; set; }
+
+        public EquipmentPanelSettings()
+        {
+            CustomerFilterEnabled = false;
+        }
+    }
+    
     /// <summary>
     ///     Interaction logic for EquipmentPanel.xaml
     /// </summary>
     public partial class EquipmentPanel : UserControl, IPanel<Equipment>
     {
-        public EquipmentGrid _Equipment;
+
+        private EquipmentPanelSettings _settings = null;
+        
+        private String _searchfilter = "";
+        
+        public ObservableCollection<Tuple<string, Guid, BitmapImage>> GroupList { get; private set; }
+
+        public bool IsReady { get; set; }
+
+        private String _customercode = "";
+        private List<Tuple<Guid, String, String>> _customers;
 
         public EquipmentPanel()
         {
+            GroupList = new ObservableCollection<Tuple<string, Guid, BitmapImage>>();
+            
             InitializeComponent();
         }
+        
+        public Type DataType()
+        {
+            return typeof(Equipment);
+        }
 
-        public string CurrentGroup { get; set; }
-        public ObservableCollection<Tuple<string, string, BitmapImage>> GroupList { get; private set; }
-
-        public bool IsReady { get; set; }
 
         public event DataModelUpdateEvent OnUpdateDataModel;
 
@@ -38,64 +67,46 @@ namespace PRSDesktop
 
         public void Setup()
         {
-            _Equipment = new EquipmentGrid
-            {
-                HorizontalAlignment = HorizontalAlignment.Stretch,
-                VerticalAlignment = VerticalAlignment.Stretch
-            };
-            _Equipment.HiddenColumns.Add(x => x.GroupLink.Code);
-            _Equipment.SetValue(Grid.RowProperty, 0);
-            _Equipment.SetValue(Grid.ColumnProperty, 1);
-            _Equipment.OnFilterRecord += _Equipment_OnFilterRecord;
-            Grid.Children.Add(_Equipment);
+            
+            _Equipment.CustomerID = Guid.Empty;
+            _Equipment.GroupID = CoreUtils.FullGuid;
+            
+            _settings = new GlobalConfiguration<EquipmentPanelSettings>().Load();
+            ReconfigurePanel();
+            
             _Equipment.Refresh(true, false);
-
-            CurrentGroup = null;
-            GroupList = new ObservableCollection<Tuple<string, string, BitmapImage>>();
-            GroupList.Add(new Tuple<string, string, BitmapImage>("All Items", null, PRSDesktop.Resources.edit.AsBitmapImage()));
-            var groups = new Client<EquipmentGroup>().Load(
+            
+            GroupList.Add(new Tuple<string, Guid, BitmapImage>("All Items", CoreUtils.FullGuid, PRSDesktop.Resources.edit.AsBitmapImage()));
+            var groups = new Client<EquipmentGroup>().Query(
                 null,
+                new Columns<EquipmentGroup>(x=>x.ID)
+                    .Add(x=>x.Description)
+                    .Add(x=>x.Thumbnail.ID),
                 new SortOrder<EquipmentGroup>(x => x.Code)
             );
-
-            Filter<Document> imageFilter = null;
-            if (groups.Length == 0)
-            {
-                imageFilter = new Filter<Document>().None();
-            }
-            else
-            {
-                foreach (var group in groups)
-                    if (group.Thumbnail.IsValid())
-                    {
-                        var newfilter = new Filter<Document>(x => x.ID).IsEqualTo(group.Thumbnail.ID);
-                        if (imageFilter == null)
-                            imageFilter = newfilter;
-                        else
-                            imageFilter.Ors.Add(newfilter);
-                    }
-            }
-
-            var Images = new Client<Document>().Load(imageFilter);
-
-            foreach (var group in groups)
+                
+            var ids = groups.ExtractValues<EquipmentGroup, Guid>(c => c.Thumbnail.ID).Distinct().Where(x => x != Guid.Empty).ToArray();
+            var Images = ids.Any()
+                ? new Client<Document>().Load(new Filter<Document>(x=>x.ID).InList(ids))
+                : new Document[] { };
+            
+            foreach (var row in groups.Rows)
             {
-                var image = Images.FirstOrDefault(x => x.ID.Equals(group.Thumbnail.ID));
-                //byte[] data = image != null ? image.Data : null;
-                BitmapImage img = null;
-                if (image != null && image.Data != null && image.Data.Length > 0)
-                {
-                    img = new BitmapImage();
-                    img.LoadImage(image.Data);
-                }
-                else
-                {
-                    img = PRSDesktop.Resources.edit.AsBitmapImage();
-                }
+                var image = Images.FirstOrDefault(x => x.ID.Equals(row.Get<EquipmentGroup,Guid>(c=>c.Thumbnail.ID)));
+                BitmapImage img =  (image != null && image.Data != null && image.Data.Length > 0)
+                    ? ImageUtils.LoadImage(image.Data)
+                    : PRSDesktop.Resources.specifications.AsBitmapImage();
 
-                GroupList.Add(new Tuple<string, string, BitmapImage>(group.Description, group.Code, img));
+                GroupList.Add(
+                    new Tuple<string, Guid, BitmapImage>(
+                        row.Get<EquipmentGroup,String>(c=>c.Description), 
+                        row.Get<EquipmentGroup,Guid>(c=>c.ID), 
+                        img
+                    )
+                );
             }
-
+            
+            Groups.Visibility = groups.Rows.Any() ? Visibility.Visible : Visibility.Collapsed;
             Groups.ItemsSource = GroupList;
             Groups.SelectedIndex = 0;
         }
@@ -106,6 +117,54 @@ namespace PRSDesktop
 
         public void CreateToolbarButtons(IPanelHost host)
         {
+            host.CreateSetupAction(new PanelAction() { Caption = "Equipment Settings", Image = PRSDesktop.Resources.specifications, OnExecute = EquipmentSettingsClick });
+        }
+
+        private void EquipmentSettingsClick(PanelAction obj)
+        {
+            var pages = new DynamicEditorPages();
+            var buttons = new DynamicEditorButtons();
+            buttons.Add(
+                "",
+                PRSDesktop.Resources.help.AsBitmapImage(),
+                _settings,
+                (f, i) =>
+                {
+                    Process.Start(new ProcessStartInfo("https://prsdigital.com.au/wiki/index.php/" + typeof(Equipment).Name.SplitCamelCase().Replace(" ", "_"))
+                        { UseShellExecute = true });
+                }
+            );
+            var propertyEditor = new DynamicEditorForm(typeof(EquipmentPanelSettings), pages, buttons);
+
+            propertyEditor.Items = new BaseObject[] { _settings };
+
+            if (propertyEditor.ShowDialog() == true)
+            {
+                new GlobalConfiguration<EquipmentPanelSettings>().Save(_settings);
+                ReconfigurePanel();
+            }
+
+        }
+
+        private void ReconfigurePanel()
+        {
+            CustomerLabel.Visibility = _settings.CustomerFilterEnabled ? Visibility.Visible : Visibility.Collapsed;
+            Customer.Visibility = _settings.CustomerFilterEnabled ? Visibility.Visible : Visibility.Collapsed;
+            CustomerSearch.Visibility = _settings.CustomerFilterEnabled ? Visibility.Visible : Visibility.Collapsed;
+            CustomerName.Visibility = _settings.CustomerFilterEnabled ? Visibility.Visible : Visibility.Collapsed;
+            
+            if (!_settings.CustomerFilterEnabled)
+            {
+                _Equipment.CustomerID = CoreUtils.FullGuid;
+                _customercode = "";
+                Customer.Text = "";
+                CustomerName.Text = "";
+            }
+            else if (_Equipment.CustomerID == CoreUtils.FullGuid)
+                    _Equipment.CustomerID = Guid.Empty;
+            
+            if (IsReady)
+                _Equipment.Refresh(false,true);
         }
 
 
@@ -125,38 +184,135 @@ namespace PRSDesktop
         public void Heartbeat(TimeSpan time)
         {
         }
-
+        
+        
         private bool _Equipment_OnFilterRecord(CoreRow row)
         {
-            if (CurrentGroup == null)
-                return true;
+            if (!String.IsNullOrWhiteSpace(_searchfilter))
+            {
+                for (int i=0; i<row.Table.Columns.Count; i++)
+                {
+                    if ((row.Table.Columns[i].DataType == typeof(String)))
+                    {
+                        string value = row.Values[i] as string;
+                        if (!String.IsNullOrEmpty(value) && value.ToUpper().Contains(_searchfilter.ToUpper()))
+                            return true;
+                    }
+                }
+
+                return false;
+            }
+            
+            return true;
 
-            object group = row.Get<Equipment, string>(x => x.GroupLink.Code);
-            if (group == null)
-                group = "";
-            return CurrentGroup.Equals(group);
         }
 
         private void Groups_SelectionChanged(object sender, SelectionChangedEventArgs e)
         {
-            var sCur = CurrentGroup;
+            var sCur = _Equipment.GroupID;
             if (e.AddedItems.Count == 0 || Groups.SelectedIndex == 0)
             {
-                CurrentGroup = null;
+                _Equipment.GroupID = CoreUtils.FullGuid;
             }
             else
             {
-                var selected = (Tuple<string, string, BitmapImage>)e.AddedItems[0];
-                CurrentGroup = selected.Item2;
+                var selected = (Tuple<string, Guid, BitmapImage>)e.AddedItems[0];
+                _Equipment.GroupID = selected.Item2;
             }
 
-            if (sCur != CurrentGroup)
+            if (sCur != _Equipment.GroupID)
                 _Equipment.Refresh(false, true);
         }
+        
+        private void Search_OnTextChanged(object sender, TextChangedEventArgs e)
+        {
+            if (String.IsNullOrEmpty(Search.Text)  && !String.Equals(Search.Text, _searchfilter))
+            {
+                _searchfilter = "";
+                _Equipment.Refresh(false, false);
+            }
+        }
 
-        public Type DataType()
+        private void Search_OnKeyUp(object sender, KeyEventArgs e)
         {
-            return typeof(Equipment);
+            if (new Key[] { Key.Enter, Key.Return }.Contains(e.Key) && !String.Equals(Search.Text, _searchfilter))
+            {
+                _searchfilter = Search.Text;
+                _Equipment.Refresh(false, false);
+            }
+        }
+
+        private void CheckCustomerCache()
+        {
+            if (_customers == null)
+            {
+                _customers = new Client<Customer>().Query(
+                    null,
+                    new Columns<Customer>(x => x.ID).Add(x => x.Code).Add(x => x.Name),
+                    new SortOrder<Customer>(x => x.Name)
+                ).ToTuples<Customer,Guid,String,String>(x =>x.ID,x=>x.Code,x=>x.Name).ToList();
+            }
+        }
+        
+        private void DoSearchCustomers()
+        {
+            var dlg = new MultiSelectDialog<Customer>(null, new Columns<Customer>(x => x.ID).Add(x => x.Code).Add(x => x.Name), false);
+            if (dlg.ShowDialog("Code",Customer.Text))
+            {
+                var customer = dlg.Items().First();
+                _customercode = customer.Code;
+                Customer.Text = customer.Code;
+                CustomerName.Text = customer.Name;
+                _Equipment.CustomerID = customer.ID;
+            }
+            else
+            {
+                _customercode = "";
+                Customer.Text = "";
+                CustomerName.Text = "";
+                _Equipment.CustomerID = Guid.Empty;
+            }
+
+            _Equipment.Refresh(false, true);
+        }
+        
+        private void CustomerSearch_OnClick(object sender, RoutedEventArgs e)
+        {
+            DoSearchCustomers();
+        }
+
+        
+        private void Customer_OnKeyUp(object sender, KeyEventArgs e)
+        {
+            if (new Key[] { Key.Enter, Key.Return }.Contains(e.Key))
+            {
+
+                if (!String.Equals(Customer.Text, _customercode))
+                {
+                    CheckCustomerCache();
+                    var lookup = _customers.FirstOrDefault(x => String.Equals(x.Item2, Customer.Text));
+                    if (lookup != null)
+                    {
+                        _customercode = lookup.Item2;
+                        CustomerName.Text = lookup.Item3;
+                        _Equipment.CustomerID = lookup.Item1;
+                        _Equipment.Refresh(false, true);
+                    }
+                    else
+                        DoSearchCustomers();
+                }
+            }
+        }
+
+        private void Customer_OnTextChanged(object sender, TextChangedEventArgs e)
+        {
+            if (String.IsNullOrEmpty(Customer.Text)  && !String.Equals(Customer.Text, _customercode))
+            {
+                _Equipment.CustomerID = Guid.Empty;
+                _customercode = "";
+                CustomerName.Text = "";
+                _Equipment.Refresh(false, true);
+            }
         }
     }
 }

+ 1 - 1
prs.desktop/Panels/IPanel.cs

@@ -44,7 +44,7 @@ namespace PRSDesktop
     }
 
     public interface IPropertiesPanel<TProperties>
-        where TProperties : BaseObject, GlobalConfigurationSettings, new()
+        where TProperties : BaseObject, IGlobalConfigurationSettings, new()
     {
         public TProperties Properties { get; set; }
     }

+ 1 - 1
prs.desktop/Panels/Tasks/TaskPanel.xaml.cs

@@ -20,7 +20,7 @@ using System.Drawing;
 
 namespace PRSDesktop
 {
-    public class TaskPanelProperties : BaseObject, GlobalConfigurationSettings
+    public class TaskPanelProperties : BaseObject, IGlobalConfigurationSettings
     {
         [CheckBoxEditor(ToolTip = "Require that all tasks are given a task type.")]
         public bool RequireTaskTypes { get; set; } = false;

+ 1 - 1
prs.desktop/Utils/CustomModuleUtils.cs

@@ -22,7 +22,7 @@ namespace PRSDesktop
                         .And(x => x.Visible).IsEqualTo(true),
                     null,
                     new SortOrder<CustomModule>(x => x.Name))
-                .ToList<CustomModule>();
+                .ToObjects<CustomModule>().ToList();
         }
 
         public static IEnumerable<Tuple<CustomModule, Bitmap>> LoadCustomModuleThumbnails(IList<CustomModule> modules)

+ 1 - 1
prs.shared/DatabaseUpdateScripts.cs

@@ -473,7 +473,7 @@ namespace PRS.Shared
             // Referenced via reflection.
             private static void PurgeEntityType<T>(Deletion deletion) where T : Entity, new()
             {
-                var entities = DbFactory.Provider.QueryDeleted(deletion, null, DeletionData.DeletionColumns<T>()).ToList<T>();
+                var entities = DbFactory.Provider.QueryDeleted(deletion, null, DeletionData.DeletionColumns<T>()).ToObjects<T>().ToList();
 
                 var deletionData = new DeletionData();
                 foreach (var entity in entities)