Browse Source

Improvements to DynamicSplitPanel
Split DynamicImagePreviewColumn to read-only and updateable versions

Frank van den Bos 2 năm trước cách đây
mục cha
commit
8d9872fc6c

+ 10 - 0
InABox.Core/Column.cs

@@ -152,6 +152,16 @@ namespace InABox.Core
             columns = new List<Column<T>>();
         }
 
+        public int IndexOf(String columnname)
+        {
+            return ColumnNames().ToList().IndexOf(columnname);
+        }
+        
+        public int IndexOf(Expression<Func<T, object>> expression)
+        {
+            return ColumnNames().ToList().IndexOf(CoreUtils.GetFullPropertyName(expression,"."));
+        }
+        
         public Columns(params Expression<Func<T, object?>>[] expressions) : this()
         {
             foreach (var expression in expressions)

+ 21 - 0
InABox.Core/DataTable.cs

@@ -144,6 +144,19 @@ namespace InABox.Core
             return (ToObject(typeof(T)) as T)!;
         }
 
+        public T Get<T>(int col, bool usedefault = true)
+        {
+            if (col < 0 || col >= Values.Count)
+            {
+                if (usedefault)
+                    return CoreUtils.GetDefault<T>();
+                throw new Exception(string.Format("Column [{0}] does not exist!", col));
+            }
+
+            return Values[col] != null ? (T)CoreUtils.ChangeType(Values[col], typeof(T)) : CoreUtils.GetDefault<T>();
+
+        }
+        
         public T Get<T>(string columnname, bool usedefault = true)
         {
             var col = GetColumn(columnname);
@@ -172,6 +185,14 @@ namespace InABox.Core
             Set(colname, value);
         }
 
+        public void Set<T>(int col, T value)
+        {
+            while (Values.Count <= col)
+                Values.Add(Table.Columns[Values.Count].DataType.GetDefault());
+
+            Values[col] = value;
+        }
+        
         public void Set<T>(string columnname, T value)
         {
             var col = GetColumn(columnname);

+ 71 - 56
InABox.DynamicGrid/Columns/DynamicImagePreviewColumn.cs → InABox.DynamicGrid/Columns/DynamicImageManagerColumn.cs

@@ -16,48 +16,34 @@ using Microsoft.Win32;
 
 namespace InABox.DynamicGrid
 {
+
     public class DynamicImagePreviewColumn<T> : DynamicImageColumn
-        where T : Entity, IRemotable, IPersistent, new()
+        where T : BaseObject
     {
+        
         private static readonly BitmapImage _preview = Resources.doc_png.AsBitmapImage();
 
-        private static Expression<Func<T, ImageDocumentLink>> _property;
-
-        private readonly bool _canupdate;
-
-        private readonly IDynamicGrid _parent;
-
-        public DynamicImagePreviewColumn(IDynamicGrid parent, Expression<Func<T, ImageDocumentLink>> property, bool canupdate) : base(PreviewImage)
+        protected static Expression<Func<T, ImageDocumentLink>> Property { get; private set; }
+        
+        protected static string ImageIDProperty => Property != null ? CoreUtils.GetFullPropertyName(Property, ".") + ".ID" : "";
+        
+        public DynamicImagePreviewColumn(Expression<Func<T, ImageDocumentLink>> property) : base(PreviewImage)
         {
-            _parent = parent;
-            _property = property;
-            _canupdate = canupdate;
+            Property = property;
             Image = PreviewImage;
             Filters = new[] { "Image Present", "Blank Image" };
             FilterRecord = DoFilterImages;
-            ContextMenu = CreateImageMenu;
             ToolTip = CreateImageToolTip;
         }
-
-        private static string _imageid => _property != null ? CoreUtils.GetFullPropertyName(_property, ".") + ".ID" : "";
-        private static string _imagefilename => _property != null ? CoreUtils.GetFullPropertyName(_property, ".") + ".FileName" : "";
-
+        
         private static BitmapImage PreviewImage(CoreRow arg)
         {
-            if (arg == null || arg.Get<Guid>(_imageid) == Guid.Empty)
+            if (arg == null || arg.Get<Guid>(ImageIDProperty) == Guid.Empty)
                 return null;
             return _preview;
         }
-
-        private MenuItem CreateMenu(string caption, RoutedEventHandler click)
-        {
-            var item = new MenuItem();
-            item.Header = caption;
-            item.Click += click;
-            return item;
-        }
-
-        private Bitmap LoadBitmapFromDatabase(Guid imageid)
+        
+        protected Bitmap LoadBitmapFromDatabase(Guid imageid)
         {
             if (imageid == Guid.Empty)
                 return null;
@@ -74,7 +60,58 @@ namespace InABox.DynamicGrid
 
             return result;
         }
+        
+        private FrameworkElement CreateImageToolTip(DynamicActionColumn column, CoreRow arg)
+        {
+            FrameworkElement result = null;
+            var imageid = arg.Get<Guid>(ImageIDProperty);
+            if (!imageid.Equals(Guid.Empty))
+                using (new WaitCursor())
+                {
+                    var bmp = LoadBitmapFromDatabase(imageid);
+                    result = ImageToolTip(bmp?.AsBitmapImage(false));
+                }
 
+            return result;
+        }
+        
+        private bool DoFilterImages(CoreRow row, string[] filter)
+        {
+            var hasimage = row.Get<Guid>(ImageIDProperty) != Guid.Empty;
+            if (filter.Contains("Image Present") && hasimage)
+                return true;
+            if (filter.Contains("Blank Image") && !hasimage)
+                return true;
+            return false;
+        }
+    }
+    
+    public class DynamicImageManagerColumn<T> : DynamicImagePreviewColumn<T>
+        where T : Entity, IRemotable, IPersistent, new()
+    {
+
+
+        private readonly bool _canupdate;
+
+        private readonly IDynamicGrid _parent;
+        
+        private static string _imagefilename => Property != null ? CoreUtils.GetFullPropertyName(Property, ".") + ".FileName" : "";
+
+        public DynamicImageManagerColumn(IDynamicGrid parent, Expression<Func<T, ImageDocumentLink>> property, bool canupdate) : base(property)
+        {
+            _parent = parent;
+            _canupdate = canupdate;
+            ContextMenu = CreateImageMenu;
+        }
+        
+        private MenuItem CreateMenu(string caption, RoutedEventHandler click)
+        {
+            var item = new MenuItem();
+            item.Header = caption;
+            item.Click += click;
+            return item;
+        }
+        
         private void SaveBitmapToDatabase(CoreRow row, Guid id, string filename, Bitmap bitmap)
         {
             var docid = id;
@@ -110,12 +147,12 @@ namespace InABox.DynamicGrid
             }
 
             var item = row.ToObject<T>();
-            CoreUtils.SetPropertyValue(item, _imageid, docid);
+            CoreUtils.SetPropertyValue(item, ImageIDProperty, docid);
             CoreUtils.SetPropertyValue(item, _imagefilename, Path.GetFileName(filename));
             new Client<T>().Save(item, "", (p, err) => { });
 
             // False here to prevent Refreshing and losing the selected row record
-            _parent.UpdateRow(row, _imageid, docid, false);
+            _parent.UpdateRow(row, ImageIDProperty, docid, false);
             _parent.UpdateRow(row, _imagefilename, Path.GetFileName(filename));
         }
 
@@ -124,7 +161,7 @@ namespace InABox.DynamicGrid
             if (rows == null || rows.Length != 1)
                 return null;
 
-            var hasimage = rows[0].Get<Guid>(_imageid) != Guid.Empty;
+            var hasimage = rows[0].Get<Guid>(ImageIDProperty) != Guid.Empty;
             var canpaste = (_canupdate && Clipboard.ContainsData("ProductImage")) || Clipboard.ContainsImage();
             var result = new ContextMenu();
 
@@ -170,7 +207,7 @@ namespace InABox.DynamicGrid
 
         private void SaveImage(CoreRow row)
         {
-            var imageid = row.Get<Guid>(_imageid);
+            var imageid = row.Get<Guid>(ImageIDProperty);
             if (imageid == Guid.Empty)
                 return;
             var filename = row.Get<string>(_imagefilename);
@@ -186,9 +223,9 @@ namespace InABox.DynamicGrid
 
         private void CopyImage(CoreRow row)
         {
-            var bmp = LoadBitmapFromDatabase(row.Get<Guid>(_imageid));
+            var bmp = LoadBitmapFromDatabase(row.Get<Guid>(ImageIDProperty));
             var data = new Tuple<Guid, string, Bitmap>(
-                row.Get<Guid>(_imageid),
+                row.Get<Guid>(ImageIDProperty),
                 row.Get<string>(_imagefilename),
                 bmp
             );
@@ -197,7 +234,7 @@ namespace InABox.DynamicGrid
 
         private void PasteImage(CoreRow row)
         {
-            if (row.Get<Guid>(_imageid) != Guid.Empty)
+            if (row.Get<Guid>(ImageIDProperty) != Guid.Empty)
                 if (MessageBox.Show("Are you sure you wish to update the image for the selected items(s)?", "Update Images", MessageBoxButton.YesNo,
                         MessageBoxImage.Question) != MessageBoxResult.Yes)
                     return;
@@ -259,28 +296,6 @@ namespace InABox.DynamicGrid
             //_parent?.Refresh(false, false);
         }
 
-        private bool DoFilterImages(CoreRow row, string[] filter)
-        {
-            var hasimage = row.Get<Guid>(_imageid) != Guid.Empty;
-            if (filter.Contains("Image Present") && hasimage)
-                return true;
-            if (filter.Contains("Blank Image") && !hasimage)
-                return true;
-            return false;
-        }
-
-        private FrameworkElement CreateImageToolTip(DynamicActionColumn column, CoreRow arg)
-        {
-            FrameworkElement result = null;
-            var imageid = arg.Get<Guid>(_imageid);
-            if (!imageid.Equals(Guid.Empty))
-                using (new WaitCursor())
-                {
-                    var bmp = LoadBitmapFromDatabase(imageid);
-                    result = ImageToolTip(bmp?.AsBitmapImage(false));
-                }
 
-            return result;
-        }
     }
 }

+ 114 - 34
InABox.DynamicGrid/DynamicSplitPanel.cs

@@ -1,4 +1,7 @@
 using System;
+using System.Collections.Generic;
+using System.Configuration;
+using System.Linq;
 using System.Windows;
 using System.Windows.Controls;
 using System.Windows.Data;
@@ -8,41 +11,46 @@ using Syncfusion.Windows.Controls.Input;
 
 namespace InABox.DynamicGrid
 {
+    [Flags]
     public enum DynamicSplitPanelView
+    {
+        Master = 1,
+        Detail = 2,
+        Combined = 4
+    }
+
+    public enum DynamicSplitPanelAnchor
     {
         Master,
-        Detail,
-        Combined
+        Detail
     }
 
-    public class DynamicSplitPanelChangedArgs : EventArgs
+    public class DynamicSplitPanelSettings : EventArgs
     {
         public DynamicSplitPanelView View { get; set; }
-        public double MasterWidth { get; set; }
+        public double AnchorWidth { get; set; }
         public double DetailHeight { get; set; }
     }
 
-    public delegate void DynamicSplitPanelChanged(object sender, DynamicSplitPanelChangedArgs e);
+    public delegate void DynamicSplitPanelChanged(object sender, DynamicSplitPanelSettings e);
 
     public class DynamicSplitPanel : Control
     {
+        
+        public static readonly DependencyProperty AllowableViewsProperty = DependencyProperty.Register(
+            nameof(AllowableViews), 
+            typeof(DynamicSplitPanelView),
+            typeof(DynamicSplitPanel), 
+            new UIPropertyMetadata( DynamicSplitPanelView.Master | DynamicSplitPanelView.Combined | DynamicSplitPanelView.Detail ));
+        
         public static readonly DependencyProperty ViewProperty = DependencyProperty.Register("View", typeof(DynamicSplitPanelView),
             typeof(DynamicSplitPanel), new UIPropertyMetadata(DynamicSplitPanelView.Detail));
 
-        //public static readonly DependencyProperty HeaderVisibilityProperty = DependencyProperty.Register("HeaderVisibility", typeof(Visibility), typeof(DynamicSplitPanel), new UIPropertyMetadata(null));
-
-        //public Visibility HeaderVisibility
-        //{
-        //    get { return (Visibility)GetValue(HeaderVisibilityProperty); }
-        //    set
-        //    {
-        //        SetValue(HeaderVisibilityProperty, value);
-        //        ConfigureScreen();
-        //    }
-        //}
-
-        public static readonly DependencyProperty MasterWidthProperty =
-            DependencyProperty.Register("MasterWidth", typeof(double), typeof(DynamicSplitPanel), new UIPropertyMetadata((double)300F));
+        public static readonly DependencyProperty AnchorProperty = DependencyProperty.Register(nameof(Anchor), typeof(DynamicSplitPanelAnchor),
+            typeof(DynamicSplitPanel), new UIPropertyMetadata(DynamicSplitPanelAnchor.Master));
+        
+        public static readonly DependencyProperty AnchorWidthProperty =
+            DependencyProperty.Register(nameof(AnchorWidth), typeof(double), typeof(DynamicSplitPanel), new UIPropertyMetadata((double)300F));
 
         public static readonly DependencyProperty MasterCaptionProperty =
             DependencyProperty.Register("MasterCaption", typeof(string), typeof(DynamicSplitPanel), new UIPropertyMetadata(null));
@@ -86,6 +94,27 @@ namespace InABox.DynamicGrid
         {
             DefaultStyleKeyProperty.OverrideMetadata(typeof(DynamicSplitPanel), new FrameworkPropertyMetadata(typeof(DynamicSplitPanel)));
         }
+        
+        public DynamicSplitPanelView AllowableViews
+        {
+            get => (DynamicSplitPanelView)GetValue(AllowableViewsProperty);
+            set
+            {
+                SetValue(AllowableViewsProperty, value);
+                ConfigureScreen();
+            }
+            
+        }    
+        
+        private bool IsViewAllowed(params DynamicSplitPanelView[] views)
+        {
+            foreach (var view in views)
+            {
+                if ((AllowableViews & view) == view)
+                    return true;
+            }
+            return false;
+        }
 
         public DynamicSplitPanelView View
         {
@@ -97,12 +126,22 @@ namespace InABox.DynamicGrid
             }
         }
 
-        public double MasterWidth
+        public DynamicSplitPanelAnchor Anchor
+        {
+            get => (DynamicSplitPanelAnchor)GetValue(AnchorProperty);
+            set 
+            {
+                SetValue(AnchorProperty, value);
+                ConfigureScreen();
+            }
+        }
+        
+        public double AnchorWidth
         {
-            get => (double)GetValue(MasterWidthProperty);
+            get => (double)GetValue(AnchorWidthProperty);
             set
             {
-                SetValue(MasterWidthProperty, value);
+                SetValue(AnchorWidthProperty, value);
                 ConfigureScreen();
             }
         }
@@ -181,6 +220,8 @@ namespace InABox.DynamicGrid
             Changed();
         }
 
+
+
         private void ConfigureScreen()
         {
             CheckParts();
@@ -188,6 +229,7 @@ namespace InABox.DynamicGrid
             {
                 if (MasterHeader != null)
                     MasterHeader.Content = MasterCaption;
+                
                 if (DetailsHeader != null)
                     DetailsHeader.Content = DetailCaption;
 
@@ -199,22 +241,41 @@ namespace InABox.DynamicGrid
 
                 if (Grid != null)
                 {
-                    Grid.ColumnDefinitions[0].Width = View == DynamicSplitPanelView.Detail && Master != null
+                    Grid.ColumnDefinitions[0].Width = (View == DynamicSplitPanelView.Detail) 
+                                                      && (Master != null) 
+                                                      && (IsViewAllowed(DynamicSplitPanelView.Combined,DynamicSplitPanelView.Master))
                         ? new GridLength(1.0F, GridUnitType.Auto)
                         : new GridLength(0.0F, GridUnitType.Pixel);
-                    Grid.ColumnDefinitions[1].Width = Master == null ? new GridLength(0.0F, GridUnitType.Pixel) :
-                        View == DynamicSplitPanelView.Master ? new GridLength(1.0F, GridUnitType.Star) :
-                        View == DynamicSplitPanelView.Detail ? new GridLength(0.0F, GridUnitType.Pixel) :
-                        new GridLength(MasterWidth, GridUnitType.Pixel);
-                    Grid.ColumnDefinitions[2].Width = View == DynamicSplitPanelView.Combined && Master != null
+                    
+                    Grid.ColumnDefinitions[1].Width = Master == null 
+                        ? new GridLength(0.0F, GridUnitType.Pixel) 
+                        : View switch { 
+                            DynamicSplitPanelView.Master => new GridLength(1.0F, GridUnitType.Star),
+                            DynamicSplitPanelView.Detail => new GridLength(0.0F, GridUnitType.Pixel),
+                            _ => Anchor == DynamicSplitPanelAnchor.Master 
+                                ? new GridLength(AnchorWidth, GridUnitType.Pixel) 
+                                : new GridLength(1.0F, GridUnitType.Star)
+                        };
+                    
+                    Grid.ColumnDefinitions[2].Width = (View == DynamicSplitPanelView.Combined) 
+                                                      && (Master != null)
                         ? new GridLength(1.0F, GridUnitType.Auto)
                         : new GridLength(0.0F, GridUnitType.Pixel);
-                    Grid.ColumnDefinitions[3].Width = View == DynamicSplitPanelView.Master
-                        ? new GridLength(0.0F, GridUnitType.Star)
-                        : new GridLength(1.0F, GridUnitType.Star);
-                    Grid.ColumnDefinitions[4].Width = View == DynamicSplitPanelView.Master
+
+                    Grid.ColumnDefinitions[3].Width = View switch
+                    {
+                        DynamicSplitPanelView.Master => new GridLength(0.0F, GridUnitType.Pixel),
+                        DynamicSplitPanelView.Detail => new GridLength(1.0F, GridUnitType.Star),
+                        _ => Anchor == DynamicSplitPanelAnchor.Detail
+                            ? new GridLength(AnchorWidth, GridUnitType.Pixel)
+                            : new GridLength(1.0F, GridUnitType.Star)
+                    };
+                        
+                    Grid.ColumnDefinitions[4].Width = (View == DynamicSplitPanelView.Master) 
+                                                      && (IsViewAllowed(DynamicSplitPanelView.Combined,DynamicSplitPanelView.Detail))
                         ? new GridLength(1.0F, GridUnitType.Auto)
                         : new GridLength(0.0F, GridUnitType.Pixel);
+                    
                     Grid.RowDefinitions[0].Height =
                         Header == null ? new GridLength(0.0F, GridUnitType.Pixel) : new GridLength(1.0F, GridUnitType.Auto);
                 }
@@ -232,6 +293,22 @@ namespace InABox.DynamicGrid
                         SecondaryDetail == null ? new GridLength(0.0F, GridUnitType.Pixel) : new GridLength(1.0F, GridUnitType.Star);
                     DetailSplitter.IsEnabled = SecondaryDetail != null;
                 }
+
+
+                if (CombinedRight != null)
+                {
+                    CombinedRight.Visibility = (View == DynamicSplitPanelView.Combined) && IsViewAllowed(DynamicSplitPanelView.Master)
+                        ? Visibility.Visible
+                        : Visibility.Collapsed;
+                }
+                
+                if (CombinedLeft != null)
+                {
+                    CombinedLeft.Visibility = (View == DynamicSplitPanelView.Combined) && IsViewAllowed(DynamicSplitPanelView.Detail)
+                        ? Visibility.Visible
+                        : Visibility.Collapsed;
+                }
+
             }
             catch (Exception e)
             {
@@ -241,14 +318,17 @@ namespace InABox.DynamicGrid
 
         private void Splitter_PreviewMouseUp(object sender, MouseButtonEventArgs e)
         {
-            SetValue(MasterWidthProperty, Grid.ColumnDefinitions[1].ActualWidth);
+            if (Anchor == DynamicSplitPanelAnchor.Master)
+                SetValue(AnchorWidthProperty, Grid.ColumnDefinitions[1].ActualWidth);
+            else 
+                SetValue(AnchorWidthProperty, Grid.ColumnDefinitions[3].ActualWidth);
             SetValue(DetailHeightProperty, SecondaryDetail == null ? 0.0F : DetailGrid.RowDefinitions[0].ActualHeight);
             Changed();
         }
 
         private void Changed()
         {
-            OnChanged?.Invoke(this, new DynamicSplitPanelChangedArgs { View = View, MasterWidth = MasterWidth, DetailHeight = DetailHeight });
+            OnChanged?.Invoke(this, new DynamicSplitPanelSettings { View = View, AnchorWidth = AnchorWidth, DetailHeight = DetailHeight });
         }
 
         public override void OnApplyTemplate()

+ 4 - 4
InABox.DynamicGrid/Themes/Generic.xaml

@@ -62,12 +62,12 @@
                         <DockPanel Grid.Row="0" Grid.Column="0" Grid.RowSpan="2" Margin="0,0,2,0">
 
                             <Button DockPanel.Dock="Top" x:Name="PART_DetailsOnly" BorderBrush="Gray"
-                                    BorderThickness="0.75" Margin="0" Background="WhiteSmoke" MinHeight="25"
+                                    BorderThickness="0.75,0.75,0.75,0" Margin="0" Background="WhiteSmoke" MinHeight="25"
                                     MinWidth="25">
                                 <Polygon Points="0,0 8,5, 0,10" Stroke="Gray" Fill="Silver" />
                             </Button>
 
-                            <Border DockPanel.Dock="Top" BorderBrush="Gray" BorderThickness="0.75" Margin="0,2,0,0"
+                            <Border DockPanel.Dock="Top" BorderBrush="Gray" BorderThickness="0.75,0,0.75,0.75" Margin="0,0,0,0"
                                     Background="WhiteSmoke">
                                 <Label x:Name="PART_MasterHeader"
                                        Content="{Binding MasterCaption, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=local:DynamicSplitPanel}}"
@@ -165,12 +165,12 @@
                         <DockPanel Grid.Row="0" Grid.Column="4" Grid.RowSpan="2" Margin="2,0,0,0">
 
                             <Button DockPanel.Dock="Top" x:Name="PART_MasterOnly" BorderBrush="Gray"
-                                    BorderThickness="0.75" Margin="0" Background="WhiteSmoke" MinHeight="25"
+                                    BorderThickness="0.75,0.75,0.75,0" Margin="0" Background="WhiteSmoke" MinHeight="25"
                                     MinWidth="25">
                                 <Polygon Points="8,0 0,5, 8,10" Stroke="Gray" Fill="Silver" />
                             </Button>
 
-                            <Border DockPanel.Dock="Top" BorderBrush="Gray" BorderThickness="0.75" Margin="0,2,0,0"
+                            <Border DockPanel.Dock="Top" BorderBrush="Gray" BorderThickness="0.75,0,0.75,0.75" 
                                     Background="WhiteSmoke">
                                 <Label x:Name="PART_DetailHeader"
                                        Content="{Binding DetailCaption, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=local:DynamicSplitPanel}}"