Browse Source

Fixed staging panel grids read only functinoality. Performance improvements also to StagingPanel

Kenric Nugteren 1 year ago
parent
commit
ca08220f83

+ 35 - 23
prs.desktop/Panels/Staging/Manufacturing/StagingManufacturingPacketComponentGrid.cs

@@ -12,37 +12,41 @@ using System.Windows;
 
 namespace PRSDesktop
 {
-    public class StagingManufacturingPacketComponentGrid : DynamicDataGrid<StagingManufacturingPacketComponent>
+    public class StagingManufacturingPacketComponentGrid : DynamicDataGrid<StagingManufacturingPacketComponent>, ISpecificGrid
     {
-        private StagingManufacturingPacket _packet = new StagingManufacturingPacket();
-        public StagingManufacturingPacket Packet
+        public StagingManufacturingPacket Packet { get; private set; } = new();
+
+        private CoreTable? _data;
+
+        private bool _readOnly = false;
+        public bool ReadOnly
         {
-            get => _packet;
+            get => _readOnly;
             set
             {
-                _packet = value;
+                _readOnly = value;
                 Reconfigure();
-                Refresh(false, true);
             }
         }
-        
-        // private bool _readOnly = false;
-        // public bool ReadOnly
-        // {
-        //     get => _readOnly;
-        //     set
-        //     {
-        //         _readOnly = value;
-        //         Reconfigure();
-        //     }
-        // }
 
         public StagingManufacturingPacketComponentGrid()
         {
             IsEnabledChanged += (sender, args) => Reconfigure(); 
             HiddenColumns.Add(x=>x.Product.Code);
+            HiddenColumns.Add(x => x.Packet.ID);
             Refresh(true, false);
         }
+
+        public void InitialiseData(StagingManufacturingPacket packet, CoreTable? data)
+        {
+            Packet = packet;
+            _data = new CoreTable();
+            if (data is not null)
+            {
+                _data.LoadColumns(data.Columns);
+                _data.LoadRows(data.Rows.Where(x => x.Get<StagingManufacturingPacketComponent, Guid>(x => x.Packet.ID) == packet.ID));
+            }
+        }
         
         protected override void DoReconfigure(FluentList<DynamicGridOption> options)
         {
@@ -52,7 +56,7 @@ namespace PRSDesktop
                 .Clear()
                 .Add(DynamicGridOption.SelectColumns);
 
-            if ((Packet.ID != Guid.Empty) && IsEnabled)
+            if ((Packet.ID != Guid.Empty) && !ReadOnly)
             {
                 options.Add(DynamicGridOption.AddRows);
                 options.Add(DynamicGridOption.EditRows);
@@ -66,13 +70,21 @@ namespace PRSDesktop
 
         protected override void Reload(Filters<StagingManufacturingPacketComponent> criteria, Columns<StagingManufacturingPacketComponent> columns, ref SortOrder<StagingManufacturingPacketComponent>? sort, Action<CoreTable?, Exception?> action)
         {
-            if (Packet.ID == Guid.Empty)
-                criteria.Add(new Filter<StagingManufacturingPacketComponent>(x => x.ID).IsEqualTo(Guid.Empty));
-
+            if (_data is not null)
+            {
+                action(_data, null);
+                _data = null;
+            }
             else
-                criteria.Add(new Filter<StagingManufacturingPacketComponent>(x => x.Packet.ID).IsEqualTo(Packet.ID));
+            {
+                if (Packet.ID == Guid.Empty)
+                    criteria.Add(new Filter<StagingManufacturingPacketComponent>(x => x.ID).IsEqualTo(Guid.Empty));
+
+                else
+                    criteria.Add(new Filter<StagingManufacturingPacketComponent>(x => x.Packet.ID).IsEqualTo(Packet.ID));
 
-            base.Reload(criteria, columns, ref sort, action);
+                base.Reload(criteria, columns, ref sort, action);
+            }
         }
 
         protected override void OnDragEnd(Type entity, CoreTable table, DragEventArgs e)

+ 8 - 8
prs.desktop/Panels/Staging/Manufacturing/StagingManufacturingPacketList.xaml.cs

@@ -50,7 +50,8 @@ namespace PRSDesktop
                 }
                 else
                 {
-                    var results = Client.Query(
+                    var results = Client.QueryMultiple(StagingManufacturingPacketListItem.GetQueries(value));
+                    /*var results = Client.Query(
                         new Filter<StagingManufacturingPacket>(x => x.StagingSetout.ID).IsEqualTo(value.ID),
                         DynamicGridUtils.LoadEditorColumns(
                             new Columns<StagingManufacturingPacket>(x => x.ID)
@@ -70,16 +71,15 @@ namespace PRSDesktop
                                 .Add(x => x.Group.Watermark)
                                 .Add(x => x.Template.ID)
                                 .Add(x => x.Template.Code)
-                                .Add(x => x.ManufacturingPacket.ID)));
+                                .Add(x => x.ManufacturingPacket.ID)));*/
 
                     ManufacturingPacketList.Children.Clear();
-                    foreach(var packet in results.ToObjects<StagingManufacturingPacket>())
+                    foreach(var packet in results.GetObjects<StagingManufacturingPacket>())
                     {
-                        AddItem(packet);
+                        AddItem(packet, results);
                     }
                     OnCollapsed?.Invoke(Collapsed());
                 }
-
                 Changed?.Invoke(this, EventArgs.Empty);
             }
         }
@@ -104,9 +104,9 @@ namespace PRSDesktop
                 .Select(x => x.Packet);
         }
 
-        private void AddItem(StagingManufacturingPacket packet)
+        private void AddItem(StagingManufacturingPacket packet, QueryMultipleResults? results)
         {
-            var item = new StagingManufacturingPacketListItem(packet, Collapsed())
+            var item = new StagingManufacturingPacketListItem(packet, results, Collapsed())
             {
                 Margin = new Thickness(0, 0, 1, 2.5)
             };
@@ -161,7 +161,7 @@ namespace PRSDesktop
             //if (grid.EditItems(new object[] { newPacket }))
             //{
                 StagingManufacturingPacketListItem.CreateStages(newPacket);
-                AddItem(newPacket);
+                AddItem(newPacket, null);
                 //OnCollapsed?.Invoke(Collapsed());
             //}
         }

+ 3 - 6
prs.desktop/Panels/Staging/Manufacturing/StagingManufacturingPacketListItem.xaml

@@ -329,24 +329,21 @@
                     <local:StagingManufacturingPacketStageGrid
                         x:Name="StagesGrid" 
                         AfterRefresh="DetailGrid_OnAfterRefresh"  
-                        OnChanged="DetailGrid_OnOnChanged"
-                        IsEnabled="{Binding ElementName=Control, Path=IsEditable}"/>
+                        OnChanged="DetailGrid_OnOnChanged"/>
                 </dynamicGrid:DynamicTabItem>
                 
                 <dynamicGrid:DynamicTabItem Header="Components" Background="WhiteSmoke">
                     <local:StagingManufacturingPacketComponentGrid
                         x:Name="ComponentGrid"
                         AfterRefresh="DetailGrid_OnAfterRefresh"
-                        OnChanged="DetailGrid_OnOnChanged"
-                        IsEnabled="{Binding ElementName=Control, Path=IsEditable}"/>
+                        OnChanged="DetailGrid_OnOnChanged"/>
                 </dynamicGrid:DynamicTabItem>
                 
                 <dynamicGrid:DynamicTabItem Header="Treatments" Background="WhiteSmoke">
                     <local:StagingManufacturingPacketTreatmentGrid
                         x:Name="TreatmentGrid"
                         AfterRefresh="DetailGrid_OnAfterRefresh"
-                        OnChanged="DetailGrid_OnOnChanged"
-                        IsEnabled="{Binding ElementName=Control, Path=IsEditable}"/>
+                        OnChanged="DetailGrid_OnOnChanged"/>
                 </dynamicGrid:DynamicTabItem>
                 
             </dynamicGrid:DynamicTabControl>

+ 78 - 7
prs.desktop/Panels/Staging/Manufacturing/StagingManufacturingPacketListItem.xaml.cs

@@ -67,15 +67,26 @@ namespace PRSDesktop
         
         public static readonly DependencyProperty IsEditableProperty = DependencyProperty.Register(
             nameof(IsEditable), typeof(bool), typeof(StagingManufacturingPacketListItem),
-            new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.None));
-        
+            new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.None, new PropertyChangedCallback(IsEditableChanged)));
+
+        private static void IsEditableChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
+        {
+            if(d is StagingManufacturingPacketListItem item)
+            {
+                var editable = (bool)e.NewValue;
+                item.StagesGrid.ReadOnly = !editable;
+                item.TreatmentGrid.ReadOnly = !editable;
+                item.ComponentGrid.ReadOnly = !editable;
+            }
+        }
+
         public bool IsEditable
         {
             get => (bool)GetValue(IsEditableProperty);
             set => SetValue(IsEditableProperty, value);
         }
         
-        public StagingManufacturingPacketListItem(StagingManufacturingPacket packet, bool collapsed)
+        public StagingManufacturingPacketListItem(StagingManufacturingPacket packet, QueryMultipleResults? results, bool collapsed)
         {
             Packet = packet;
             Packet.PropertyChanged += (sender, args) =>
@@ -89,10 +100,18 @@ namespace PRSDesktop
 
             UpdateTemplateButton();
 
-            StagesGrid.Packet = Packet;
-            ComponentGrid.Packet = Packet;
-            TreatmentGrid.Packet = Packet;
-            
+            StagesGrid.Refresh(true, false);
+            ComponentGrid.Refresh(true, false);
+            TreatmentGrid.Refresh(true, false);
+
+            StagesGrid.InitialiseData(packet, results?.Get<StagingManufacturingPacketStage>());
+            ComponentGrid.InitialiseData(packet, results?.Get<StagingManufacturingPacketComponent>());
+            TreatmentGrid.InitialiseData(packet, results?.Get<StagingManufacturingPacketTreatment>());
+
+            StagesGrid.Refresh(false, true);
+            ComponentGrid.Refresh(false, true);
+            TreatmentGrid.Refresh(false, true);
+
             ITPCode.Text = Packet.ITP.Code;
             ITPDescription.Text = Packet.ITP.Description;
             _itpChanged = false;
@@ -104,6 +123,58 @@ namespace PRSDesktop
             IsEditable = packet.ManufacturingPacket.ID == Guid.Empty;
         }
 
+        // TODO: This sucks
+        private static StagingManufacturingPacketComponentGrid? componentColumnsGrid;
+        private static StagingManufacturingPacketTreatmentGrid? treatmentColumnsGrid;
+        private static StagingManufacturingPacketStageGrid? stageColumnsGrid;
+
+        public static IEnumerable<IKeyedQueryDef> GetQueries(StagingSetout setout)
+        {
+            var packetFilter = new Filter<StagingManufacturingPacket>(x => x.StagingSetout.ID).IsEqualTo(setout.ID);
+            yield return new KeyedQueryDef<StagingManufacturingPacket>(
+                packetFilter,
+                DynamicGridUtils.LoadEditorColumns(
+                    new Columns<StagingManufacturingPacket>(x => x.ID)
+                        .Add(x => x.Serial)
+                        .Add(x => x.Title)
+                        .Add(x => x.Quantity)
+                        .Add(x => x.BarcodeQuantity)
+                        .Add(x => x.Watermark)
+                        .Add(x => x.Location)
+                        .Add(x => x.ITP.ID)
+                        .Add(x => x.ITP.Code)
+                        .Add(x => x.ITP.Description)
+                        .Add(x => x.Job.ID)
+                        .Add(x => x.Group.ID)
+                        .Add(x => x.Group.Code)
+                        .Add(x => x.Group.Description)
+                        .Add(x => x.Group.Watermark)
+                        .Add(x => x.Template.ID)
+                        .Add(x => x.Template.Code)
+                        .Add(x => x.ManufacturingPacket.ID)));
+
+            stageColumnsGrid ??= new StagingManufacturingPacketStageGrid();
+            stageColumnsGrid.Refresh(true, false);
+
+            yield return new KeyedQueryDef<StagingManufacturingPacketStage>(
+                new Filter<StagingManufacturingPacketStage>(x => x.Packet.ID).InQuery(packetFilter, x => x.ID),
+                stageColumnsGrid.DataColumns());
+
+            componentColumnsGrid ??= new StagingManufacturingPacketComponentGrid();
+            componentColumnsGrid.Refresh(true, false);
+
+            yield return new KeyedQueryDef<StagingManufacturingPacketComponent>(
+                new Filter<StagingManufacturingPacketComponent>(x => x.Packet.ID).InQuery(packetFilter, x => x.ID),
+                componentColumnsGrid.DataColumns());
+
+            treatmentColumnsGrid ??= new StagingManufacturingPacketTreatmentGrid();
+            treatmentColumnsGrid.Refresh(true, false);
+
+            yield return new KeyedQueryDef<StagingManufacturingPacketTreatment>(
+                new Filter<StagingManufacturingPacketTreatment>(x => x.Packet.ID).InQuery(packetFilter, x => x.ID),
+                treatmentColumnsGrid.DataColumns());
+        }
+
         private void EditButton_Click(object sender, RoutedEventArgs e)
         {
             var grid = DynamicGridUtils.CreateDynamicGrid(typeof(DynamicDataGrid<>), typeof(StagingManufacturingPacket));

+ 32 - 20
prs.desktop/Panels/Staging/Manufacturing/StagingManufacturingPacketStageGrid.cs

@@ -11,37 +11,41 @@ using System.Threading.Tasks;
 
 namespace PRSDesktop
 {
-    public class StagingManufacturingPacketStageGrid : DynamicDataGrid<StagingManufacturingPacketStage>
+    public class StagingManufacturingPacketStageGrid : DynamicDataGrid<StagingManufacturingPacketStage>, ISpecificGrid
     {
-        private StagingManufacturingPacket _packet = new StagingManufacturingPacket();
-        public StagingManufacturingPacket Packet
+        public StagingManufacturingPacket Packet { get; private set; } = new();
+
+        private CoreTable? _data;
+
+        private bool _readOnly = false;
+        public bool ReadOnly
         {
-            get => _packet;
+            get => _readOnly;
             set
             {
-                _packet = value;
+                _readOnly = value;
                 Reconfigure();
-                Refresh(false, true);
             }
         }
 
-        // private bool _readOnly = false;
-        // public bool ReadOnly
-        // {
-        //     get => _readOnly;
-        //     set
-        //     {
-        //         _readOnly = value;
-        //         Reconfigure();
-        //     }
-        // }
-
         public StagingManufacturingPacketStageGrid()
         {
             IsEnabledChanged += (sender, args) => Reconfigure();
+            HiddenColumns.Add(x => x.Packet.ID);
             Refresh(true, false);
         }
 
+        public void InitialiseData(StagingManufacturingPacket packet, CoreTable? data)
+        {
+            Packet = packet;
+            _data = new CoreTable();
+            if(data is not null)
+            {
+                _data.LoadColumns(data.Columns);
+                _data.LoadRows(data.Rows.Where(x => x.Get<StagingManufacturingPacketStage, Guid>(x => x.Packet.ID) == packet.ID));
+            }
+        }
+
         protected override void GenerateColumns(DynamicGridColumns columns)
         {
             columns.Add<StagingManufacturingPacketStage, Guid>(x => x.Section.ID, 0, "Section", "", Alignment.MiddleCenter);
@@ -56,7 +60,7 @@ namespace PRSDesktop
                 .Clear()
                 .Add(DynamicGridOption.SelectColumns);
             
-            if ((Packet.ID != Guid.Empty) && IsEnabled)
+            if ((Packet.ID != Guid.Empty) && !ReadOnly)
             {
                 options.Add(DynamicGridOption.AddRows);
                 options.Add(DynamicGridOption.EditRows);
@@ -77,8 +81,16 @@ namespace PRSDesktop
 
         protected override void Reload(Filters<StagingManufacturingPacketStage> criteria, Columns<StagingManufacturingPacketStage> columns, ref SortOrder<StagingManufacturingPacketStage>? sort, Action<CoreTable?, Exception?> action)
         {
-            criteria.Add(new Filter<StagingManufacturingPacketStage>(x => x.Packet.ID).IsEqualTo(Packet.ID));
-            base.Reload(criteria, columns, ref sort, action);
+            if (_data is not null)
+            {
+                action(_data, null);
+                _data = null;
+            }
+            else
+            {
+                criteria.Add(new Filter<StagingManufacturingPacketStage>(x => x.Packet.ID).IsEqualTo(Packet.ID));
+                base.Reload(criteria, columns, ref sort, action);
+            }
         }
     }
 }

+ 37 - 24
prs.desktop/Panels/Staging/Manufacturing/StagingManufacturingPacketTreatmentGrid.cs

@@ -1,42 +1,47 @@
 using System;
+using System.Linq;
 using Comal.Classes;
 using InABox.Core;
 using InABox.DynamicGrid;
 
 namespace PRSDesktop;
 
-public class StagingManufacturingPacketTreatmentGrid : DynamicDataGrid<StagingManufacturingPacketTreatment>
+public class StagingManufacturingPacketTreatmentGrid : DynamicDataGrid<StagingManufacturingPacketTreatment>, ISpecificGrid
 {
-    private StagingManufacturingPacket _packet = new StagingManufacturingPacket();
-    public StagingManufacturingPacket Packet
+    public StagingManufacturingPacket Packet { get; private set; } = new();
+
+    private CoreTable? _data;
+
+    private bool _readOnly = false;
+    public bool ReadOnly
     {
-        get => _packet;
+        get => _readOnly;
         set
         {
-            _packet = value;
+            _readOnly = value;
             Reconfigure();
-            Refresh(false, true);
         }
     }
-        
-    // private bool _readOnly = false;
-    // public bool ReadOnly
-    // {
-    //     get => _readOnly;
-    //     set
-    //     {
-    //         _readOnly = value;
-    //         Reconfigure();
-    //     }
-    // }
 
     public StagingManufacturingPacketTreatmentGrid()
     {
         IsEnabledChanged += (sender, args) => Reconfigure(); 
         HiddenColumns.Add(x=>x.Product.Code);
+        HiddenColumns.Add(x => x.Packet.ID);
         Refresh(true, false);
     }
-        
+
+    public void InitialiseData(StagingManufacturingPacket packet, CoreTable? data)
+    {
+        Packet = packet;
+        _data = new CoreTable();
+        if (data is not null)
+        {
+            _data.LoadColumns(data.Columns);
+            _data.LoadRows(data.Rows.Where(x => x.Get<StagingManufacturingPacketTreatment, Guid>(x => x.Packet.ID) == packet.ID));
+        }
+    }
+
     protected override void DoReconfigure(FluentList<DynamicGridOption> options)
     {
         base.DoReconfigure(options);
@@ -45,7 +50,7 @@ public class StagingManufacturingPacketTreatmentGrid : DynamicDataGrid<StagingMa
             .Clear()
             .Add(DynamicGridOption.SelectColumns);
 
-        if ((Packet.ID != Guid.Empty) && IsEnabled)
+        if ((Packet.ID != Guid.Empty) && !ReadOnly)
         {
             options.Add(DynamicGridOption.AddRows);
             options.Add(DynamicGridOption.EditRows);
@@ -58,13 +63,21 @@ public class StagingManufacturingPacketTreatmentGrid : DynamicDataGrid<StagingMa
 
     protected override void Reload(Filters<StagingManufacturingPacketTreatment> criteria, Columns<StagingManufacturingPacketTreatment> columns, ref SortOrder<StagingManufacturingPacketTreatment>? sort, Action<CoreTable?, Exception?> action)
     {
-        if (Packet.ID == Guid.Empty)
-            criteria.Add(new Filter<StagingManufacturingPacketTreatment>(x => x.ID).IsEqualTo(Guid.Empty));
-
+        if(_data is not null)
+        {
+            action(_data, null);
+            _data = null;
+        }
         else
-            criteria.Add(new Filter<StagingManufacturingPacketTreatment>(x => x.Packet.ID).IsEqualTo(Packet.ID));
+        {
+            if (Packet.ID == Guid.Empty)
+                criteria.Add(new Filter<StagingManufacturingPacketTreatment>(x => x.ID).IsEqualTo(Guid.Empty));
+
+            else
+                criteria.Add(new Filter<StagingManufacturingPacketTreatment>(x => x.Packet.ID).IsEqualTo(Packet.ID));
 
-        base.Reload(criteria, columns, ref sort, action);
+            base.Reload(criteria, columns, ref sort, action);
+        }
     }
 
     protected override StagingManufacturingPacketTreatment CreateItem()

+ 35 - 30
prs.desktop/Panels/Staging/StagingPanel.xaml.cs

@@ -18,6 +18,7 @@ using System.Collections.Immutable;
 using FastReport.Data;
 using Microsoft.Xaml.Behaviors.Core;
 using StagingManufacturingPacketComponent = Comal.Classes.StagingManufacturingPacketComponent;
+using System.Threading.Tasks;
 
 namespace PRSDesktop
 {
@@ -216,45 +217,45 @@ public class Module
             }
         }
 
-        private StagingSetoutDocument? _document;
-        private StagingSetoutDocument? Document
+        private StagingSetoutDocument? Document { get; set; }
+
+        private byte[]? _documentdata = null;
+
+        private void ClearDocuments()
         {
-            get => _document;
-            set
-            {
-                if(_document != value)
-                {
-                    _document = value;
-                    RenderDocument(value);
-                }
-            }
+            Document = null;
+            RenderDocuments(null);
         }
 
-        private byte[]? _documentdata = null;
-        
-        private void RenderDocument(StagingSetoutDocument? document)
+        private List<byte[]>? GetDocuments(StagingSetoutDocument? document)
         {
-            DocumentViewer.Children.Clear();
-            if (document is null)
+            if(document is null)
             {
-                return;
+                return null;
             }
-
             var table = new Client<Document>().Query(
                 new Filter<Document>(x => x.ID).IsEqualTo(document.DocumentLink.ID),
                 new Columns<Document>(x => x.Data));
             var first = table.Rows.FirstOrDefault();
             if (first is null)
-                return;
+                return null;
             _documentdata = first.Get<Document, byte[]>(x => x.Data);
-            var images = ImageUtils.RenderPDFToImages(_documentdata);
-            foreach (var image in images)
+            return ImageUtils.RenderPDFToImages(_documentdata);
+        }
+        
+        private void RenderDocuments(List<byte[]>? documents)
+        {
+            DocumentViewer.Children.Clear();
+            if(documents is not null)
             {
-                DocumentViewer.Children.Add(new Image
+                foreach (var image in documents)
                 {
-                    Source = ImageUtils.LoadImage(image),
-                    Margin = new Thickness(0, 0, 0, 20)
-                });
+                    DocumentViewer.Children.Add(new Image
+                    {
+                        Source = ImageUtils.LoadImage(image),
+                        Margin = new Thickness(0, 0, 0, 20)
+                    });
+                }
             }
         }
 
@@ -573,7 +574,7 @@ public class Module
                 MessageBox.Show("Success - Task Created for Document " + selectedSetout.Number + " (Task no. " + task.Number + " assigned to " + task.EmployeeLink.Name + ")");
                 selectedSetout = null;
 
-                Document = null;
+                ClearDocuments();
                 stagingSetoutGrid.Refresh(false, true);
             }
             else
@@ -697,7 +698,7 @@ public class Module
             AddPacketButton.IsEnabled = selectedSetout is not null;
             if(selectedSetout is null)
             {
-                Document = null;
+                ClearDocuments();
                 ManufacturingPacketList.Setout = null;
                 CollapsePacketsButton.IsEnabled = false;
                 SetoutComponentGrid.StagingSetout = null;
@@ -717,7 +718,7 @@ public class Module
             if(doc is null)
             {
                 MessageBox.Show("No document found for this setout.");
-                Document = null;
+                ClearDocuments();
                 ManufacturingPacketList.Setout = null;
                 CollapsePacketsButton.IsEnabled = false;
                 SetoutComponentGrid.StagingSetout = null;
@@ -725,6 +726,7 @@ public class Module
             }
 
             Document = doc;
+            var docTask = Task.Run(() => GetDocuments(doc));
             if(CanViewPackets())
             {
                 ManufacturingPacketList.Setout = selectedSetout;
@@ -737,9 +739,12 @@ public class Module
                     selectedSetout.LockedBy.ID == App.EmployeeID ?
                         DocumentMode.Complete :
                         DocumentMode.Locked;
+
+            docTask.Wait();
+            RenderDocuments(docTask.Result);
+
+            ApproveButton.Content = Document!.Approved ? "Unapprove" : "Approve";
             SetMode(mode);
-            ApproveButton.Content = Document.Approved ? "Unapprove" : "Approve";
-            
         }
 
         public bool IsReady { get; set; }