Browse Source

Use tool constructor for DI

CPKreuz 4 years ago
parent
commit
b3b5fac8f9

+ 43 - 29
PixiEditor/Helpers/DependencyInjectionHelper.cs

@@ -1,47 +1,61 @@
-using System;
+using Microsoft.Extensions.DependencyInjection;
+using System;
+using System.Collections.Generic;
+using System.Linq;
 using System.Reflection;
 using System.Reflection;
 
 
 namespace PixiEditor.Helpers
 namespace PixiEditor.Helpers
 {
 {
     public static class DependencyInjectionHelper
     public static class DependencyInjectionHelper
     {
     {
-        /// <summary>
-        /// Injects all services from <paramref name="services"/> into the public properties of <paramref name="obj"/>
-        /// </summary>
-        /// <typeparam name="T">The type of the object to inject</typeparam>
-        /// <param name="services">The <see cref="IServiceProvider"/></param>
-        /// <param name="obj">The object that should get injected</param>
-        public static void Inject<T>(this IServiceProvider services, T obj)
-            => Inject(services, obj, BindingFlags.Public | BindingFlags.Instance);
-
-        /// <summary>
-        /// Injects all services from <paramref name="services"/> into the properties of <paramref name="obj"/>
-        /// </summary>
-        /// <typeparam name="T">The type of the object to inject</typeparam>
-        /// <param name="services">The <see cref="IServiceProvider"/></param>
-        /// <param name="obj">The object that should get injected</param>
-        /// <param name="bindingFlags">The binding flags for the properties</param>
-        public static void Inject<T>(this IServiceProvider services, T obj, BindingFlags bindingFlags)
-            => Inject(services, obj, bindingFlags, obj.GetType());
-
-        public static void Inject(this IServiceProvider services, object obj, BindingFlags bindingFlags, Type type)
+        public static T Inject<T>(this IServiceProvider provider)
+            => (T)Inject(provider, typeof(T));
+
+#nullable enable
+
+        public static object Inject(this IServiceProvider provider, Type type)
+        {
+            ConstructorInfo constructor = FindConstructorOrDefault(provider, type);
+
+            List<object?> parameters = new List<object?>();
+
+            foreach (Type argumentType in constructor.GetParameters().Select(x => x.ParameterType))
+            {
+                parameters.Add(provider.GetRequiredService(argumentType));
+            }
+
+            return constructor.Invoke(parameters.ToArray());
+        }
+
+#nullable disable
+
+        private static ConstructorInfo FindConstructorOrDefault(IServiceProvider provider, Type type)
         {
         {
-            foreach (PropertyInfo info in type.GetProperties(bindingFlags))
+            ConstructorInfo foundConstructor = default;
+
+            foreach (ConstructorInfo info in type.GetConstructors())
             {
             {
-                if (!info.CanWrite)
+                if (HasParameters(provider, info.GetParameters()))
                 {
                 {
-                    continue;
+                    foundConstructor = info;
+                    break;
                 }
                 }
+            }
 
 
-                object value = services.GetService(info.PropertyType);
+            return foundConstructor;
+        }
 
 
-                if (value is null)
+        private static bool HasParameters(IServiceProvider provider, IEnumerable<ParameterInfo> parameters)
+        {
+            foreach (ParameterInfo parameter in parameters)
+            {
+                if (provider.GetService(parameter.ParameterType) is null)
                 {
                 {
-                    continue;
+                    return false;
                 }
                 }
-
-                info.SetValue(obj, value);
             }
             }
+
+            return true;
         }
         }
     }
     }
 }
 }

+ 0 - 14
PixiEditor/Models/Tools/Tool.cs

@@ -88,19 +88,5 @@ namespace PixiEditor.Models.Tools
         public virtual void AfterAddedUndo(UndoManager undoManager)
         public virtual void AfterAddedUndo(UndoManager undoManager)
         {
         {
         }
         }
-
-        public virtual void SetupSubTools()
-        {
-        }
-
-        /// <summary>
-        /// Creates a sub tool and injects the services in it. <para/>
-        /// Only use this inside <see cref="SetupSubTools"/>!
-        /// </summary>
-        protected T CreateSubTool<T>()
-            where T : Tool, new()
-        {
-            return ToolBuilder.BuildTool<T>(Services);
-        }
     }
     }
 }
 }

+ 2 - 6
PixiEditor/Models/Tools/ToolBuilder.cs

@@ -31,11 +31,7 @@ namespace PixiEditor.Models.Tools
         /// </summary>
         /// </summary>
         public static Tool BuildTool(Type type, IServiceProvider services)
         public static Tool BuildTool(Type type, IServiceProvider services)
         {
         {
-            Tool tool = (Tool)type.GetConstructor(Type.EmptyTypes).Invoke(null);
-
-            services.Inject(tool, BindingFlags.Public | BindingFlags.Instance, type);
-
-            tool.SetupSubTools();
+            Tool tool = (Tool)services.Inject(type);
 
 
             return tool;
             return tool;
         }
         }
@@ -44,7 +40,7 @@ namespace PixiEditor.Models.Tools
         /// Adds a new tool of type <typeparamref name="T"/> to the building chain.
         /// Adds a new tool of type <typeparamref name="T"/> to the building chain.
         /// </summary>
         /// </summary>
         public ToolBuilder Add<T>()
         public ToolBuilder Add<T>()
-            where T : Tool, new()
+            where T : Tool
             => Add(typeof(T));
             => Add(typeof(T));
 
 
         /// <summary>
         /// <summary>

+ 4 - 7
PixiEditor/Models/Tools/Tools/EraserTool.cs

@@ -1,5 +1,6 @@
 using System.Collections.Generic;
 using System.Collections.Generic;
 using System.Windows.Media;
 using System.Windows.Media;
+using PixiEditor.Models.Controllers;
 using PixiEditor.Models.DataHolders;
 using PixiEditor.Models.DataHolders;
 using PixiEditor.Models.Layers;
 using PixiEditor.Models.Layers;
 using PixiEditor.Models.Position;
 using PixiEditor.Models.Position;
@@ -10,13 +11,14 @@ namespace PixiEditor.Models.Tools.Tools
 {
 {
     public class EraserTool : BitmapOperationTool
     public class EraserTool : BitmapOperationTool
     {
     {
-        private PenTool pen = new PenTool();
+        private readonly PenTool pen;
 
 
-        public EraserTool()
+        public EraserTool(BitmapManager bitmapManager)
         {
         {
             ActionDisplay = "Draw to remove color from a pixel.";
             ActionDisplay = "Draw to remove color from a pixel.";
             Tooltip = "Erasers color from pixel. (E)";
             Tooltip = "Erasers color from pixel. (E)";
             Toolbar = new BasicToolbar();
             Toolbar = new BasicToolbar();
+            pen = new PenTool(bitmapManager);
         }
         }
 
 
         public override LayerChange[] Use(Layer layer, List<Coordinates> coordinates, Color color)
         public override LayerChange[] Use(Layer layer, List<Coordinates> coordinates, Color color)
@@ -30,10 +32,5 @@ namespace PixiEditor.Models.Tools.Tools
             BitmapPixelChanges pixels = pen.Draw(startingCords, coordinates[0], System.Windows.Media.Colors.Transparent, toolSize);
             BitmapPixelChanges pixels = pen.Draw(startingCords, coordinates[0], System.Windows.Media.Colors.Transparent, toolSize);
             return Only(pixels, layer);
             return Only(pixels, layer);
         }
         }
-
-        public override void SetupSubTools()
-        {
-            pen = CreateSubTool<PenTool>();
-        }
     }
     }
 }
 }

+ 3 - 2
PixiEditor/Models/Tools/Tools/FloodFill.cs

@@ -9,12 +9,13 @@ namespace PixiEditor.Models.Tools.Tools
 {
 {
     public class FloodFill : BitmapOperationTool
     public class FloodFill : BitmapOperationTool
     {
     {
-        public BitmapManager BitmapManager { get; set; }
+        private BitmapManager BitmapManager { get; }
 
 
-        public FloodFill()
+        public FloodFill(BitmapManager bitmapManager)
         {
         {
             ActionDisplay = "Press on a area to fill it.";
             ActionDisplay = "Press on a area to fill it.";
             Tooltip = "Fills area with color. (G)";
             Tooltip = "Fills area with color. (G)";
+            BitmapManager = bitmapManager;
         }
         }
 
 
         public override LayerChange[] Use(Layer layer, List<Coordinates> coordinates, Color color)
         public override LayerChange[] Use(Layer layer, List<Coordinates> coordinates, Color color)

+ 2 - 6
PixiEditor/Models/Tools/Tools/LineTool.cs

@@ -13,13 +13,14 @@ namespace PixiEditor.Models.Tools.Tools
 {
 {
     public class LineTool : ShapeTool
     public class LineTool : ShapeTool
     {
     {
-        private CircleTool circleTool;
+        private readonly CircleTool circleTool;
 
 
         public LineTool()
         public LineTool()
         {
         {
             ActionDisplay = "Click and move to draw a line. Hold Shift to draw an even one.";
             ActionDisplay = "Click and move to draw a line. Hold Shift to draw an even one.";
             Tooltip = "Draws line on canvas (L). Hold Shift to draw even line.";
             Tooltip = "Draws line on canvas (L). Hold Shift to draw even line.";
             Toolbar = new BasicToolbar();
             Toolbar = new BasicToolbar();
+            circleTool = new CircleTool();
         }
         }
 
 
         public override void OnKeyDown(KeyEventArgs e)
         public override void OnKeyDown(KeyEventArgs e)
@@ -60,11 +61,6 @@ namespace PixiEditor.Models.Tools.Tools
             return CreateLine(new List<Coordinates>() { end, start }, thickness, startCap, endCap);
             return CreateLine(new List<Coordinates>() { end, start }, thickness, startCap, endCap);
         }
         }
 
 
-        public override void SetupSubTools()
-        {
-            circleTool = CreateSubTool<CircleTool>();
-        }
-
         private IEnumerable<Coordinates> CreateLine(IEnumerable<Coordinates> coordinates, int thickness, CapType startCap, CapType endCap)
         private IEnumerable<Coordinates> CreateLine(IEnumerable<Coordinates> coordinates, int thickness, CapType startCap, CapType endCap)
         {
         {
             Coordinates startingCoordinates = coordinates.Last();
             Coordinates startingCoordinates = coordinates.Last();

+ 5 - 3
PixiEditor/Models/Tools/Tools/MoveTool.cs

@@ -29,7 +29,7 @@ namespace PixiEditor.Models.Tools.Tools
         private Coordinates[] startSelection;
         private Coordinates[] startSelection;
         private bool updateViewModelSelection = true;
         private bool updateViewModelSelection = true;
 
 
-        public MoveTool()
+        public MoveTool(BitmapManager bitmapManager)
         {
         {
             ActionDisplay = "Hold mouse to move selected pixels. Hold Ctrl to move all layers.";
             ActionDisplay = "Hold mouse to move selected pixels. Hold Ctrl to move all layers.";
             Tooltip = "Moves selected pixels (V). Hold Ctrl to move all layers.";
             Tooltip = "Moves selected pixels (V). Hold Ctrl to move all layers.";
@@ -37,11 +37,13 @@ namespace PixiEditor.Models.Tools.Tools
             HideHighlight = true;
             HideHighlight = true;
             RequiresPreviewLayer = true;
             RequiresPreviewLayer = true;
             UseDefaultUndoMethod = true;
             UseDefaultUndoMethod = true;
+
+            BitmapManager = bitmapManager;
         }
         }
 
 
         public bool MoveAll { get; set; } = false;
         public bool MoveAll { get; set; } = false;
 
 
-        public BitmapManager BitmapManager { get; set; }
+        private BitmapManager BitmapManager { get; }
 
 
         public override void OnKeyDown(KeyEventArgs e)
         public override void OnKeyDown(KeyEventArgs e)
         {
         {
@@ -111,7 +113,7 @@ namespace PixiEditor.Models.Tools.Tools
             ResetSelectionValues(startPos);
             ResetSelectionValues(startPos);
 
 
             // Move offset if no selection
             // Move offset if no selection
-            Document doc = ViewModelMain.Current.BitmapManager.ActiveDocument;
+            Document doc = BitmapManager.ActiveDocument;
             Selection selection = doc.ActiveSelection;
             Selection selection = doc.ActiveSelection;
             if (selection != null && selection.SelectedPoints.Count > 0)
             if (selection != null && selection.SelectedPoints.Count > 0)
             {
             {

+ 6 - 3
PixiEditor/Models/Tools/Tools/MoveViewportTool.cs

@@ -11,16 +11,19 @@ namespace PixiEditor.Models.Tools.Tools
     {
     {
         private Point clickPoint;
         private Point clickPoint;
 
 
-        public BitmapManager BitmapManager { get; set; }
+        private BitmapManager BitmapManager { get; }
 
 
-        public ToolsViewModel ToolsViewModel { get; set; }
+        private ToolsViewModel ToolsViewModel { get; }
 
 
-        public MoveViewportTool()
+        public MoveViewportTool(BitmapManager bitmapManager, ToolsViewModel toolsViewModel)
         {
         {
             HideHighlight = true;
             HideHighlight = true;
             Cursor = Cursors.SizeAll;
             Cursor = Cursors.SizeAll;
             ActionDisplay = "Click and move to pan viewport.";
             ActionDisplay = "Click and move to pan viewport.";
             Tooltip = "Move viewport. (H)";
             Tooltip = "Move viewport. (H)";
+
+            BitmapManager = bitmapManager;
+            ToolsViewModel = toolsViewModel;
         }
         }
 
 
         public override void OnMouseDown(MouseEventArgs e)
         public override void OnMouseDown(MouseEventArgs e)

+ 5 - 8
PixiEditor/Models/Tools/Tools/PenTool.cs

@@ -19,13 +19,13 @@ namespace PixiEditor.Models.Tools.Tools
         private readonly SizeSetting toolSizeSetting;
         private readonly SizeSetting toolSizeSetting;
         private readonly BoolSetting pixelPerfectSetting;
         private readonly BoolSetting pixelPerfectSetting;
         private readonly List<Coordinates> confirmedPixels = new List<Coordinates>();
         private readonly List<Coordinates> confirmedPixels = new List<Coordinates>();
-        private LineTool lineTool;
+        private readonly LineTool lineTool;
         private Coordinates[] lastChangedPixels = new Coordinates[3];
         private Coordinates[] lastChangedPixels = new Coordinates[3];
         private byte changedPixelsindex = 0;
         private byte changedPixelsindex = 0;
 
 
-        public BitmapManager BitmapManager { get; set; }
+        private BitmapManager BitmapManager { get; }
 
 
-        public PenTool()
+        public PenTool(BitmapManager bitmapManager)
         {
         {
             Cursor = Cursors.Pen;
             Cursor = Cursors.Pen;
             ActionDisplay = "Click and move to draw.";
             ActionDisplay = "Click and move to draw.";
@@ -35,6 +35,8 @@ namespace PixiEditor.Models.Tools.Tools
             pixelPerfectSetting = Toolbar.GetSetting<BoolSetting>("PixelPerfectEnabled");
             pixelPerfectSetting = Toolbar.GetSetting<BoolSetting>("PixelPerfectEnabled");
             pixelPerfectSetting.ValueChanged += PixelPerfectSettingValueChanged;
             pixelPerfectSetting.ValueChanged += PixelPerfectSettingValueChanged;
             ClearPreviewLayerOnEachIteration = false;
             ClearPreviewLayerOnEachIteration = false;
+            BitmapManager = bitmapManager;
+            lineTool = new LineTool();
         }
         }
 
 
         public override void OnRecordingLeftMouseDown(MouseEventArgs e)
         public override void OnRecordingLeftMouseDown(MouseEventArgs e)
@@ -98,11 +100,6 @@ namespace PixiEditor.Models.Tools.Tools
             return result;
             return result;
         }
         }
 
 
-        public override void SetupSubTools()
-        {
-            lineTool = CreateSubTool<LineTool>();
-        }
-
         private void MovePixelsToCheck(BitmapPixelChanges changes)
         private void MovePixelsToCheck(BitmapPixelChanges changes)
         {
         {
             if (changes.ChangedPixels[lastChangedPixels[1]].A != 0)
             if (changes.ChangedPixels[lastChangedPixels[1]].A != 0)

+ 9 - 5
PixiEditor/Models/Tools/Tools/SelectTool.cs

@@ -19,19 +19,23 @@ namespace PixiEditor.Models.Tools.Tools
 {
 {
     public class SelectTool : ReadonlyTool
     public class SelectTool : ReadonlyTool
     {
     {
-        private readonly RectangleTool rectangleTool = new RectangleTool();
-        private readonly CircleTool circleTool = new CircleTool();
+        private readonly RectangleTool rectangleTool;
+        private readonly CircleTool circleTool;
         private IEnumerable<Coordinates> oldSelectedPoints;
         private IEnumerable<Coordinates> oldSelectedPoints;
 
 
-        public BitmapManager BitmapManager { get; set; }
-
         private static Selection ActiveSelection { get => ViewModelMain.Current.BitmapManager.ActiveDocument.ActiveSelection; }
         private static Selection ActiveSelection { get => ViewModelMain.Current.BitmapManager.ActiveDocument.ActiveSelection; }
 
 
-        public SelectTool()
+        private BitmapManager BitmapManager { get; }
+
+        public SelectTool(BitmapManager bitmapManager)
         {
         {
             ActionDisplay = "Click and move to select an area.";
             ActionDisplay = "Click and move to select an area.";
             Tooltip = "Selects area. (M)";
             Tooltip = "Selects area. (M)";
             Toolbar = new SelectToolToolbar();
             Toolbar = new SelectToolToolbar();
+            BitmapManager = bitmapManager;
+
+            rectangleTool = new RectangleTool();
+            circleTool = new CircleTool();
         }
         }
 
 
         public SelectionType SelectionType { get; set; } = SelectionType.Add;
         public SelectionType SelectionType { get; set; } = SelectionType.Add;

+ 4 - 2
PixiEditor/Models/Tools/Tools/ZoomTool.cs

@@ -16,15 +16,17 @@ namespace PixiEditor.Models.Tools.Tools
         private double workAreaWidth = SystemParameters.WorkArea.Width;
         private double workAreaWidth = SystemParameters.WorkArea.Width;
         private double pixelsPerZoomMultiplier;
         private double pixelsPerZoomMultiplier;
 
 
-        public BitmapManager BitmapManager { get; set; }
+        private BitmapManager BitmapManager { get; }
 
 
-        public ZoomTool()
+        public ZoomTool(BitmapManager bitmapManager)
         {
         {
             HideHighlight = true;
             HideHighlight = true;
             CanStartOutsideCanvas = true;
             CanStartOutsideCanvas = true;
             ActionDisplay = "Click and move to zoom. Click to zoom in, hold alt and click to zoom out.";
             ActionDisplay = "Click and move to zoom. Click to zoom in, hold alt and click to zoom out.";
             Tooltip = "Zooms viewport (Z). Click to zoom in, hold alt and click to zoom out.";
             Tooltip = "Zooms viewport (Z). Click to zoom in, hold alt and click to zoom out.";
             pixelsPerZoomMultiplier = workAreaWidth / ZoomSensitivityMultiplier;
             pixelsPerZoomMultiplier = workAreaWidth / ZoomSensitivityMultiplier;
+
+            BitmapManager = bitmapManager;
         }
         }
 
 
         public override void OnKeyDown(KeyEventArgs e)
         public override void OnKeyDown(KeyEventArgs e)

+ 2 - 2
PixiEditor/ViewModels/SubViewModels/Main/SelectionViewModel.cs

@@ -15,7 +15,7 @@ namespace PixiEditor.ViewModels.SubViewModels.Main
 
 
         public RelayCommand SelectAllCommand { get; set; }
         public RelayCommand SelectAllCommand { get; set; }
 
 
-        private SelectTool selectTool;
+        private readonly SelectTool selectTool;
 
 
         public SelectionViewModel(ViewModelMain owner)
         public SelectionViewModel(ViewModelMain owner)
             : base(owner)
             : base(owner)
@@ -23,7 +23,7 @@ namespace PixiEditor.ViewModels.SubViewModels.Main
             DeselectCommand = new RelayCommand(Deselect, SelectionIsNotEmpty);
             DeselectCommand = new RelayCommand(Deselect, SelectionIsNotEmpty);
             SelectAllCommand = new RelayCommand(SelectAll, CanSelectAll);
             SelectAllCommand = new RelayCommand(SelectAll, CanSelectAll);
 
 
-            selectTool = ToolBuilder.BuildTool<SelectTool>(Owner.Services);
+            selectTool = new SelectTool(Owner.BitmapManager);
         }
         }
 
 
         public void SelectAll(object parameter)
         public void SelectAll(object parameter)