Bläddra i källkod

Merge pull request #213 from PixiEditor/convertersMarkupExtension

Made all converters a markup extension
Krzysztof Krysiński 4 år sedan
förälder
incheckning
16e91fedb2
51 ändrade filer med 298 tillägg och 551 borttagningar
  1. 3 12
      PixiEditor/Helpers/Converters/BoolToBrushConverter.cs
  2. 4 4
      PixiEditor/Helpers/Converters/BoolToIntConverter.cs
  3. 7 26
      PixiEditor/Helpers/Converters/BrushTuple.cs
  4. 4 9
      PixiEditor/Helpers/Converters/DoubleToIntConverter.cs
  5. 7 15
      PixiEditor/Helpers/Converters/EmptyStringToVisibilityConverter.cs
  6. 3 8
      PixiEditor/Helpers/Converters/EqualityBoolToVisibilityConverter.cs
  7. 5 7
      PixiEditor/Helpers/Converters/FileExtensionToColorConverter.cs
  8. 12 32
      PixiEditor/Helpers/Converters/FinalIsVisibleToVisiblityConverter.cs
  9. 3 4
      PixiEditor/Helpers/Converters/FloorConverter.cs
  10. 13 33
      PixiEditor/Helpers/Converters/FormattedColorConverter.cs
  11. 4 7
      PixiEditor/Helpers/Converters/IndentConverter.cs
  12. 11 16
      PixiEditor/Helpers/Converters/IndexOfConverter.cs
  13. 4 4
      PixiEditor/Helpers/Converters/IntToPickerTypeConverter.cs
  14. 6 13
      PixiEditor/Helpers/Converters/IntToViewportRectConverter.cs
  15. 6 13
      PixiEditor/Helpers/Converters/InverseBooleanConverter.cs
  16. 3 7
      PixiEditor/Helpers/Converters/IsSpecifiedTypeConverter.cs
  17. 3 12
      PixiEditor/Helpers/Converters/KeyToStringConverter.cs
  18. 6 10
      PixiEditor/Helpers/Converters/LayerStructureToGroupsConverter.cs
  19. 7 20
      PixiEditor/Helpers/Converters/LayerToFinalOpacityConverter.cs
  20. 7 3
      PixiEditor/Helpers/Converters/LayersToStructuredLayersConverter.cs
  21. 26 0
      PixiEditor/Helpers/Converters/MarkupConverter.cs
  22. 19 0
      PixiEditor/Helpers/Converters/MultiValueMarkupConverter.cs
  23. 6 9
      PixiEditor/Helpers/Converters/NotNullToBoolConverter.cs
  24. 4 8
      PixiEditor/Helpers/Converters/NotNullToVisibilityConverter.cs
  25. 4 24
      PixiEditor/Helpers/Converters/NullToVisibilityConverter.cs
  26. 6 10
      PixiEditor/Helpers/Converters/OppositeVisibilityConverter.cs
  27. 23 0
      PixiEditor/Helpers/Converters/SingleInstanceConverter.cs
  28. 20 0
      PixiEditor/Helpers/Converters/SingleInstanceMultiValueConverter.cs
  29. 6 12
      PixiEditor/Helpers/Converters/ThresholdVisibilityConverter.cs
  30. 5 4
      PixiEditor/Helpers/Converters/ToolSizeToIntConverter.cs
  31. 3 7
      PixiEditor/Helpers/Converters/ZoomToViewportConverter.cs
  32. 2 5
      PixiEditor/Views/Dialogs/HelloTherePopup.xaml
  33. 0 4
      PixiEditor/Views/Dialogs/ImportFilePopup.xaml
  34. 0 4
      PixiEditor/Views/Dialogs/NewFilePopup.xaml
  35. 0 5
      PixiEditor/Views/Dialogs/ResizeCanvasPopup.xaml
  36. 0 5
      PixiEditor/Views/Dialogs/ResizeDocumentPopup.xaml
  37. 2 6
      PixiEditor/Views/Dialogs/SaveFilePopup.xaml
  38. 3 4
      PixiEditor/Views/Dialogs/SettingsWindow.xaml
  39. 2 3
      PixiEditor/Views/Dialogs/ShortcutPopup.xaml
  40. 9 15
      PixiEditor/Views/MainWindow.xaml
  41. 0 41
      PixiEditor/Views/UserControls/AvalonDockWindows/ReferenceLayerWindow.xaml
  42. 0 82
      PixiEditor/Views/UserControls/AvalonDockWindows/ReferenceLayerWindow.xaml.cs
  43. 8 9
      PixiEditor/Views/UserControls/DiscordRPPreview.xaml
  44. 1 4
      PixiEditor/Views/UserControls/EditableTextBlock.xaml
  45. 6 2
      PixiEditor/Views/UserControls/Layers/LayerGroupControl.xaml
  46. 1 4
      PixiEditor/Views/UserControls/Layers/LayersManager.xaml
  47. 1 4
      PixiEditor/Views/UserControls/Layers/RawLayersViewer.xaml
  48. 16 10
      PixiEditor/Views/UserControls/Layers/ReferenceLayer.xaml
  49. 1 2
      PixiEditor/Views/UserControls/PreviewWindow.xaml
  50. 2 5
      PixiEditor/Views/UserControls/SizeInput.xaml
  51. 4 8
      PixiEditor/Views/UserControls/SmallColorPicker.xaml

+ 3 - 12
PixiEditor/Helpers/Converters/BoolToBrushConverter.cs

@@ -1,24 +1,15 @@
 using System;
-using System.Collections.Generic;
 using System.Globalization;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using System.Windows.Data;
 
 namespace PixiEditor.Helpers.Converters
 {
-    public class BoolToBrushConverter : IValueConverter
+    public class BoolToBrushConverter
+        : SingleInstanceConverter<BoolToBrushConverter>
     {
-        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
+        public override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
         {
             BrushTuple tuple = (BrushTuple)parameter;
             return (bool)value ? tuple.FirstBrush : tuple.SecondBrush;
         }
-
-        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
-        {
-            throw new NotImplementedException();
-        }
     }
 }

+ 4 - 4
PixiEditor/Helpers/Converters/BoolToIntConverter.cs

@@ -1,17 +1,17 @@
 using System;
 using System.Globalization;
-using System.Windows.Data;
 
 namespace PixiEditor.Helpers.Converters
 {
-    public class BoolToIntConverter : IValueConverter
+    public class BoolToIntConverter
+        : SingleInstanceConverter<BoolToIntConverter>
     {
-        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
+        public override object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
         {
             return value.ToString() == "0";
         }
 
-        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
+        public override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
         {
             if (value is bool boolean)
             {

+ 7 - 26
PixiEditor/Helpers/Converters/BrushTuple.cs

@@ -1,39 +1,24 @@
 using System;
-using System.Collections.Generic;
-using System.ComponentModel;
-using System.Linq;
 using System.Runtime.CompilerServices;
-using System.Text;
-using System.Threading.Tasks;
 using System.Windows.Media;
 
 namespace PixiEditor.Helpers.Converters
 {
     public class BrushTuple : NotifyableObject, ITuple
     {
-        public object this[int index]
+        public object this[int index] => index switch
         {
-            get
-            {
-                return index switch
-                {
-                    0 => FirstBrush,
-                    1 => SecondBrush,
-                    _ => throw new IndexOutOfRangeException("Index was out of range")
-                };
-            }
-        }
+            0 => FirstBrush,
+            1 => SecondBrush,
+            _ => throw new ArgumentOutOfRangeException(nameof(index))
+        };
 
         private Brush item1;
 
         public Brush FirstBrush
         {
             get => item1;
-            set
-            {
-                item1 = value;
-                RaisePropertyChanged(nameof(FirstBrush));
-            }
+            set => SetProperty(ref item1, value);
         }
 
         private Brush item2;
@@ -41,11 +26,7 @@ namespace PixiEditor.Helpers.Converters
         public Brush SecondBrush
         {
             get => item2;
-            set
-            {
-                item2 = value;
-                RaisePropertyChanged(nameof(SecondBrush));
-            }
+            set => SetProperty(ref item2, value);
         }
 
         public int Length => 2;

+ 4 - 9
PixiEditor/Helpers/Converters/DoubleToIntConverter.cs

@@ -1,14 +1,14 @@
 using System;
 using System.Globalization;
-using System.Windows.Data;
 
 namespace PixiEditor.Helpers.Converters
 {
-    public class DoubleToIntConverter : IValueConverter
+    public class DoubleToIntConverter :
+        SingleInstanceConverter<DoubleToIntConverter>
     {
-        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
+        public override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
         {
-            if (value is double || value is float)
+            if (value is double or float)
             {
                 double val = (double)value;
                 return (int)val;
@@ -16,10 +16,5 @@ namespace PixiEditor.Helpers.Converters
 
             return value;
         }
-
-        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
-        {
-            throw new NotImplementedException();
-        }
     }
 }

+ 7 - 15
PixiEditor/Helpers/Converters/EmptyStringToVisibilityConverter.cs

@@ -1,26 +1,18 @@
 using System;
-using System.Collections.Generic;
 using System.Globalization;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
 using System.Windows;
-using System.Windows.Data;
 
 namespace PixiEditor.Helpers.Converters
 {
-    public class EmptyStringToVisibilityConverter : IValueConverter
+    public class EmptyStringToVisibilityConverter :
+        SingleInstanceConverter<EmptyStringToVisibilityConverter>
     {
-        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
+        public override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
         {
-            string s = (string)value;
-
-            return !string.IsNullOrEmpty(s) ? Visibility.Visible : Visibility.Collapsed;
-        }
-
-        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
-        {
-            throw new NotImplementedException();
+            return
+                string.IsNullOrEmpty((string)value)
+                ? Visibility.Collapsed
+                : Visibility.Visible;
         }
     }
 }

+ 3 - 8
PixiEditor/Helpers/Converters/EqualityBoolToVisibilityConverter.cs

@@ -1,20 +1,15 @@
 using System;
 using System.Globalization;
 using System.Windows;
-using System.Windows.Data;
 
 namespace PixiEditor.Helpers.Converters
 {
-    public class EqualityBoolToVisibilityConverter : IValueConverter
+    public class EqualityBoolToVisibilityConverter :
+        SingleInstanceConverter<EqualityBoolToVisibilityConverter>
     {
-        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
+        public override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
         {
             return value.Equals(parameter) ? Visibility.Visible : Visibility.Collapsed;
         }
-
-        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
-        {
-            throw new NotImplementedException();
-        }
     }
 }

+ 5 - 7
PixiEditor/Helpers/Converters/FileExtensionToColorConverter.cs

@@ -1,11 +1,11 @@
 using System;
 using System.Globalization;
-using System.Windows.Data;
 using System.Windows.Media;
 
 namespace PixiEditor.Helpers.Converters
 {
-    public class FileExtensionToColorConverter : IValueConverter
+    public class FileExtensionToColorConverter :
+        SingleInstanceConverter<FileExtensionToColorConverter>
     {
         private static readonly SolidColorBrush PixiBrush = ColorBrush(226, 1, 45);
 
@@ -15,7 +15,7 @@ namespace PixiEditor.Helpers.Converters
 
         private static readonly SolidColorBrush UnknownBrush = ColorBrush(100, 100, 100);
 
-        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
+        public override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
         {
             string extension = (string)value;
 
@@ -35,11 +35,9 @@ namespace PixiEditor.Helpers.Converters
             return UnknownBrush;
         }
 
-        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
+        private static SolidColorBrush ColorBrush(byte r, byte g, byte b)
         {
-            throw new NotImplementedException();
+            return new SolidColorBrush(Color.FromRgb(r, g, b));
         }
-
-        private static SolidColorBrush ColorBrush(byte r, byte g, byte b) => new SolidColorBrush(Color.FromRgb(r, g, b));
     }
 }

+ 12 - 32
PixiEditor/Helpers/Converters/FinalIsVisibleToVisiblityConverter.cs

@@ -1,47 +1,27 @@
-using PixiEditor.Models.Layers;
+using PixiEditor.Models.Controllers;
+using PixiEditor.Models.Layers;
 using PixiEditor.ViewModels;
 using System;
-using System.Collections.Generic;
 using System.Globalization;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
 using System.Windows;
 using System.Windows.Data;
 using System.Windows.Markup;
 
 namespace PixiEditor.Helpers.Converters
 {
-    public class FinalIsVisibleToVisiblityConverter : MarkupExtension, IMultiValueConverter
+    public class FinalIsVisibleToVisiblityConverter
+        : SingleInstanceMultiValueConverter<FinalIsVisibleToVisiblityConverter>
     {
-        private static FinalIsVisibleToVisiblityConverter converter = null;
-
-        public override object ProvideValue(IServiceProvider serviceProvider)
-        {
-            if (converter == null)
-            {
-                converter = new FinalIsVisibleToVisiblityConverter();
-            }
-
-            return converter;
-        }
-
-        public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
+        public override object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
         {
-            if (values[0] is Layer layer)
-            {
-                if (ViewModelMain.Current?.BitmapManager?.ActiveDocument != null)
-                {
-                    return ViewModelMain.Current.BitmapManager.ActiveDocument.GetFinalLayerIsVisible(layer) ? Visibility.Visible : Visibility.Collapsed;
-                }
-            }
-
-            return Visibility.Visible;
-        }
+            BitmapManager bitmapManager = ViewModelMain.Current?.BitmapManager;
 
-        public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
-        {
-            throw new NotImplementedException();
+            return
+                (values[0] is not Layer layer ||
+                bitmapManager.ActiveDocument is null ||
+                bitmapManager.ActiveDocument.GetFinalLayerIsVisible(layer))
+                    ? Visibility.Visible
+                    : (object)Visibility.Collapsed;
         }
     }
 }

+ 3 - 4
PixiEditor/Helpers/Converters/FloorConverter.cs

@@ -1,17 +1,16 @@
 using System;
 using System.Globalization;
-using System.Windows.Data;
 
 namespace PixiEditor.Helpers.Converters
 {
-    class FloorConverter : IValueConverter
+    public class FloorConverter : SingleInstanceConverter<FloorConverter>
     {
-        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
+        public override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
         {
             return Math.Floor((double)value);
         }
 
-        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
+        public override object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
         {
             return value;
         }

+ 13 - 33
PixiEditor/Helpers/Converters/FormattedColorConverter.cs

@@ -1,48 +1,28 @@
 using System;
-using System.Collections.Generic;
 using System.Globalization;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using System.Windows.Data;
-using System.Windows.Markup;
 using System.Windows.Media;
 
 namespace PixiEditor.Helpers.Converters
 {
-    public class FormattedColorConverter : MarkupExtension, IMultiValueConverter
+    public class FormattedColorConverter
+        : SingleInstanceMultiValueConverter<FormattedColorConverter>
     {
-        private static FormattedColorConverter converter;
-        public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
+        public override object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
         {
-            if(values != null && values.Length > 1 && values[0] is Color color && values[1] is string format)
+            if (values == null ||
+                values.Length <= 1 ||
+                values[0] is not Color color ||
+                values[1] is not string format)
             {
-                switch (format.ToLower())
-                {
-                    case "hex":
-                        return color.ToString();
-                    case "rgba":
-                        return $"({color.R}, {color.G}, {color.B}, {color.A})";
-                    default:
-                        break;
-                }
+                return "";
             }
 
-            return "";
-        }
-
-        public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
-        {
-            throw new NotImplementedException();
-        }
-
-        public override object ProvideValue(IServiceProvider serviceProvider)
-        {
-            if(converter == null)
+            return format.ToLowerInvariant() switch
             {
-                converter = new FormattedColorConverter();
-            }
-            return converter;
+                "hex" => color.ToString(),
+                "rgba" => $"({color.R}, {color.G}, {color.B}, {color.A})",
+                _ => "",
+            };
         }
     }
 }

+ 4 - 7
PixiEditor/Helpers/Converters/IndentConverter.cs

@@ -1,24 +1,21 @@
 using System;
-using System.Collections.Generic;
 using System.Globalization;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
 using System.Windows;
 using System.Windows.Data;
 
 namespace PixiEditor.Helpers.Converters
 {
-    public class IndentConverter : IValueConverter
+    public class IndentConverter
+        : SingleInstanceConverter<IndentConverter>
     {
         private const int IndentSize = 20;
 
-        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
+        public override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
         {
             return new GridLength(((GridLength)value).Value + IndentSize);
         }
 
-        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
+        public override object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
         {
             return Binding.DoNothing;
         }

+ 11 - 16
PixiEditor/Helpers/Converters/IndexOfConverter.cs

@@ -1,27 +1,22 @@
-using System;
-using System.Globalization;
-using System.Linq;
-using System.Windows.Data;
+using PixiEditor.Models.Controllers;
 using PixiEditor.Models.Layers;
 using PixiEditor.ViewModels;
+using System;
+using System.Globalization;
+using System.Windows.Data;
 
 namespace PixiEditor.Helpers.Converters
 {
-    public class IndexOfConverter : IValueConverter
+    public class IndexOfConverter
+        : SingleInstanceConverter<IndexOfConverter>
     {
-        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
+        public override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
         {
-            if (value is Layer layer && ViewModelMain.Current.BitmapManager.ActiveDocument != null)
-            {
-                return ViewModelMain.Current.BitmapManager.ActiveDocument.Layers.IndexOf(layer);
-            }
+            BitmapManager bitmapManager = ViewModelMain.Current.BitmapManager;
 
-            return Binding.DoNothing;
-        }
-
-        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
-        {
-            throw new NotImplementedException();
+            return value is Layer layer && bitmapManager.ActiveDocument != null
+                   ? bitmapManager.ActiveDocument.Layers.IndexOf(layer)
+                   : Binding.DoNothing;
         }
     }
 }

+ 4 - 4
PixiEditor/Helpers/Converters/IntToPickerTypeConverter.cs

@@ -1,18 +1,18 @@
 using ColorPicker.Models;
 using System;
 using System.Globalization;
-using System.Windows.Data;
 
 namespace PixiEditor.Helpers.Converters
 {
-    public class IntToPickerTypeConverter : IValueConverter
+    public class IntToPickerTypeConverter
+        : SingleInstanceConverter<IntToPickerTypeConverter>
     {
-        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
+        public override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
         {
             return (PickerType)value;
         }
 
-        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
+        public override object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
         {
             return (int)value;
         }

+ 6 - 13
PixiEditor/Helpers/Converters/IntToViewportRectConverter.cs

@@ -5,21 +5,14 @@ using System.Windows.Data;
 
 namespace PixiEditor.Helpers.Converters
 {
-    public class IntToViewportRectConverter : IValueConverter
+    public class IntToViewportRectConverter
+        : SingleInstanceConverter<IntToViewportRectConverter>
     {
-        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
+        public override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
         {
-            if (parameter is string and "vertical")
-            {
-                return new Rect(0, 0, 1d / (int)value, 1d);
-            }
-
-            return new Rect(0, 0, 1d, 1d / (int)value);
-        }
-
-        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
-        {
-            throw new NotImplementedException();
+            return parameter is string and "vertical"
+                   ? new Rect(0, 0, 1d / (int)value, 1d)
+                   : (object)new Rect(0, 0, 1d, 1d / (int)value);
         }
     }
 }

+ 6 - 13
PixiEditor/Helpers/Converters/InverseBooleanConverter.cs

@@ -4,21 +4,14 @@ using System.Windows.Data;
 namespace PixiEditor.Helpers.Converters
 {
     [ValueConversion(typeof(bool), typeof(bool))]
-    public class InverseBooleanConverter : IValueConverter
+    public class InverseBooleanConverter
+        : SingleInstanceConverter<InverseBooleanConverter>
     {
-        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
+        public override object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
         {
-            if (targetType != typeof(bool))
-            {
-                throw new InvalidOperationException("The target must be a boolean");
-            }
-
-            return !(bool)value;
-        }
-
-        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
-        {
-            throw new NotSupportedException();
+            return targetType != typeof(bool)
+                   ? throw new InvalidOperationException("The target must be a boolean")
+                   : !(bool)value;
         }
     }
 }

+ 3 - 7
PixiEditor/Helpers/Converters/IsSpecifiedTypeConverter.cs

@@ -5,17 +5,13 @@ using System.Windows.Data;
 namespace PixiEditor.Helpers.Converters
 {
     [ValueConversion(typeof(object), typeof(bool))]
-    public class IsSpecifiedTypeConverter : IValueConverter
+    public class IsSpecifiedTypeConverter : MarkupConverter
     {
         public Type SpecifiedType { get; set; }
-        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
-        {
-            return value != null && value.GetType() == SpecifiedType;
-        }
 
-        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
+        public override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
         {
-            throw new NotImplementedException();
+            return value != null && value.GetType() == SpecifiedType;
         }
     }
 }

+ 3 - 12
PixiEditor/Helpers/Converters/KeyToStringConverter.cs

@@ -1,17 +1,13 @@
 using System;
-using System.Collections.Generic;
 using System.Globalization;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using System.Windows.Data;
 using System.Windows.Input;
 
 namespace PixiEditor.Helpers.Converters
 {
-    public class KeyToStringConverter : IValueConverter
+    public class KeyToStringConverter
+        : SingleInstanceConverter<KeyToStringConverter>
     {
-        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
+        public override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
         {
             if (value is Key key)
             {
@@ -26,10 +22,5 @@ namespace PixiEditor.Helpers.Converters
                 return string.Empty;
             }
         }
-
-        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
-        {
-            throw new NotImplementedException();
-        }
     }
 }

+ 6 - 10
PixiEditor/Helpers/Converters/LayerStructureToGroupsConverter.cs

@@ -9,21 +9,17 @@ using System.Windows.Data;
 
 namespace PixiEditor.Helpers.Converters
 {
-    public class LayerStructureToGroupsConverter : IMultiValueConverter
+    public class LayerStructureToGroupsConverter
+        : SingleInstanceMultiValueConverter<LayerStructureToGroupsConverter>
     {
-        public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
+        public override object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
         {
-            if (values[0] is LayerStructure structure)
+            if (values[0] is not LayerStructure structure)
             {
-                return GetSubGroups(structure.Groups);
+                return Binding.DoNothing;
             }
 
-            return Binding.DoNothing;
-        }
-
-        public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
-        {
-            throw new NotImplementedException();
+            return GetSubGroups(structure.Groups);
         }
 
         private ObservableCollection<GuidStructureItem> GetSubGroups(IEnumerable<GuidStructureItem> groups)

+ 7 - 20
PixiEditor/Helpers/Converters/LayerToFinalOpacityConverter.cs

@@ -1,18 +1,15 @@
-using System;
-using System.Globalization;
-using System.Windows.Data;
-using System.Windows.Markup;
-using PixiEditor.Models.Layers;
+using PixiEditor.Models.Layers;
 using PixiEditor.Models.Layers.Utils;
 using PixiEditor.ViewModels;
+using System;
+using System.Globalization;
 
 namespace PixiEditor.Helpers.Converters
 {
-    public class LayerToFinalOpacityConverter : MarkupExtension, IMultiValueConverter
+    public class LayerToFinalOpacityConverter
+        : SingleInstanceMultiValueConverter<LayerToFinalOpacityConverter>
     {
-        private static LayerToFinalOpacityConverter converter;
-
-        public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
+        public override object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
         {
             if (values.Length > 0 && values[0] is Layer layer && ViewModelMain.Current?.BitmapManager?.ActiveDocument != null)
             {
@@ -22,19 +19,9 @@ namespace PixiEditor.Helpers.Converters
             return null;
         }
 
-        public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
+        public override object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
         {
             return null;
         }
-
-        public override object ProvideValue(IServiceProvider serviceProvider)
-        {
-            if(converter == null)
-            {
-                converter = new LayerToFinalOpacityConverter();
-            }
-
-            return converter;
-        }
     }
 }

+ 7 - 3
PixiEditor/Helpers/Converters/LayersToStructuredLayersConverter.cs

@@ -9,13 +9,14 @@ using System.Windows.Data;
 namespace PixiEditor.Helpers.Converters
 {
     // TODO: Implement rebuilding only changed items instead whole tree
-    public class LayersToStructuredLayersConverter : IMultiValueConverter
+    public class LayersToStructuredLayersConverter
+        : MultiValueMarkupConverter
     {
         private static StructuredLayerTree cachedTree;
         private List<Guid> lastLayers = new List<Guid>();
         private ObservableCollection<GuidStructureItem> lastStructure = new ObservableCollection<GuidStructureItem>();
 
-        public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
+        public override object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
         {
             if (values[0] is ObservableCollection<Layer> layers && values[1] is LayerStructure structure)
             {
@@ -37,15 +38,18 @@ namespace PixiEditor.Helpers.Converters
 
             return new StructuredLayerTree(null, null);
         }
-        public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
+
+        public override object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
         {
             throw new ArgumentException("Value is not a StructuredLayerTree");
         }
+
         private bool LayerOrderIsDifferent(IList<Layer> layers)
         {
             var guids = layers.Select(x => x.LayerGuid).ToArray();
             return !guids.SequenceEqual(lastLayers);
         }
+
         private bool TryFindStructureDifferences(LayerStructure structure)
         {
             bool structureModified = false;

+ 26 - 0
PixiEditor/Helpers/Converters/MarkupConverter.cs

@@ -0,0 +1,26 @@
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows.Data;
+using System.Windows.Markup;
+
+namespace PixiEditor.Helpers.Converters
+{
+    public abstract class MarkupConverter : MarkupExtension, IValueConverter
+    {
+        public abstract object Convert(object value, Type targetType, object parameter, CultureInfo culture);
+
+        public virtual object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
+        {
+            throw new NotImplementedException();
+        }
+
+        public override object ProvideValue(IServiceProvider serviceProvider)
+        {
+            return this;
+        }
+    }
+}

+ 19 - 0
PixiEditor/Helpers/Converters/MultiValueMarkupConverter.cs

@@ -0,0 +1,19 @@
+using System;
+using System.Globalization;
+using System.Windows.Data;
+using System.Windows.Markup;
+
+namespace PixiEditor.Helpers.Converters
+{
+    public abstract class MultiValueMarkupConverter : MarkupExtension, IMultiValueConverter
+    {
+        public abstract object Convert(object[] values, Type targetType, object parameter, CultureInfo culture);
+
+        public virtual object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
+        {
+            throw new NotImplementedException();
+        }
+
+        public override object ProvideValue(IServiceProvider serviceProvider) => this;
+    }
+}

+ 6 - 9
PixiEditor/Helpers/Converters/NotNullToBoolConverter.cs

@@ -5,20 +5,17 @@ using System.Windows.Data;
 namespace PixiEditor.Helpers.Converters
 {
     [ValueConversion(typeof(object), typeof(bool))]
-    public class NotNullToBoolConverter : IValueConverter
+    public class NotNullToBoolConverter
+        : SingleInstanceConverter<NotNullToBoolConverter>
     {
-        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
+        public override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
         {
-            bool result = value != null;
-            if (parameter != null)
-            {
-                return !result;
-            }
+            bool result = value is not null;
 
-            return result;
+            return parameter is null ? result : !result;
         }
 
-        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
+        public override object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
         {
             return value;
         }

+ 4 - 8
PixiEditor/Helpers/Converters/NotNullToVisibilityConverter.cs

@@ -6,13 +6,14 @@ using System.Windows.Data;
 namespace PixiEditor.Helpers.Converters
 {
     [ValueConversion(typeof(object), typeof(Visibility))]
-    public class NotNullToVisibilityConverter : IValueConverter
+    public class NotNullToVisibilityConverter
+        : MarkupConverter
     {
         public bool Inverted { get; set; }
 
-        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
+        public override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
         {
-            bool isNull = value != null;
+            bool isNull = value is not null;
 
             if (Inverted)
             {
@@ -21,10 +22,5 @@ namespace PixiEditor.Helpers.Converters
 
             return isNull ? Visibility.Visible : Visibility.Collapsed;
         }
-
-        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
-        {
-            throw new NotImplementedException();
-        }
     }
 }

+ 4 - 24
PixiEditor/Helpers/Converters/NullToVisibilityConverter.cs

@@ -1,35 +1,15 @@
 using System;
-using System.Collections.Generic;
 using System.Globalization;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
 using System.Windows;
-using System.Windows.Data;
-using System.Windows.Markup;
 
 namespace PixiEditor.Helpers.Converters
 {
-    public class NullToVisibilityConverter : MarkupExtension, IValueConverter
+    public class NullToVisibilityConverter
+        : SingleInstanceConverter<NullToVisibilityConverter>
     {
-        private static NullToVisibilityConverter converter;
-        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
+        public override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
         {
-            return value != null ? Visibility.Collapsed : Visibility.Visible;
-        }
-
-        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
-        {
-            throw new NotImplementedException();
-        }
-
-        public override object ProvideValue(IServiceProvider serviceProvider)
-        {
-            if(converter == null)
-            {
-                converter = new NullToVisibilityConverter();
-            }
-            return converter;
+            return value is null ? Visibility.Visible : Visibility.Collapsed;
         }
     }
 }

+ 6 - 10
PixiEditor/Helpers/Converters/OppositeVisibilityConverter.cs

@@ -5,9 +5,10 @@ using System.Windows.Data;
 
 namespace PixiEditor.Helpers.Converters
 {
-    public class OppositeVisibilityConverter : IValueConverter
+    public class OppositeVisibilityConverter
+        : SingleInstanceConverter<OppositeVisibilityConverter>
     {
-        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
+        public override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
         {
             if (value.ToString().ToLower() == "visible")
             {
@@ -17,16 +18,11 @@ namespace PixiEditor.Helpers.Converters
             return Visibility.Visible;
         }
 
-        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
+        public override object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
         {
-            if (value is Visibility)
+            if (value is Visibility visibility)
             {
-                if ((Visibility)value == Visibility.Visible)
-                {
-                    return "Hidden";
-                }
-
-                return "Visible";
+                return visibility == Visibility.Visible ? "Hidden" : "Visible";
             }
 
             return null;

+ 23 - 0
PixiEditor/Helpers/Converters/SingleInstanceConverter.cs

@@ -0,0 +1,23 @@
+using System;
+
+namespace PixiEditor.Helpers.Converters
+{
+    /// <summary>
+    /// Use this if you want to share the same converter over the whole application. <para/> Do not use this if your converter has properties.
+    /// </summary>
+    public abstract class SingleInstanceConverter<TThis> : MarkupConverter
+        where TThis : SingleInstanceConverter<TThis>
+    {
+        private static SingleInstanceConverter<TThis> instance;
+
+        public override object ProvideValue(IServiceProvider serviceProvider)
+        {
+            if (instance is null)
+            {
+                instance = this;
+            }
+
+            return instance;
+        }
+    }
+}

+ 20 - 0
PixiEditor/Helpers/Converters/SingleInstanceMultiValueConverter.cs

@@ -0,0 +1,20 @@
+using System;
+
+namespace PixiEditor.Helpers.Converters
+{
+    public abstract class SingleInstanceMultiValueConverter<TThis> : MultiValueMarkupConverter
+        where TThis : SingleInstanceMultiValueConverter<TThis>
+    {
+        private static SingleInstanceMultiValueConverter<TThis> instance;
+
+        public override object ProvideValue(IServiceProvider serviceProvider)
+        {
+            if (instance is null)
+            {
+                instance = this;
+            }
+
+            return instance;
+        }
+    }
+}

+ 6 - 12
PixiEditor/Helpers/Converters/ThresholdVisibilityConverter.cs

@@ -1,26 +1,20 @@
 using System;
 using System.Globalization;
 using System.Windows;
-using System.Windows.Data;
 
 namespace PixiEditor.Helpers.Converters
 {
-    class ThresholdVisibilityConverter : IValueConverter
+    public class ThresholdVisibilityConverter
+        : MarkupConverter
     {
         public double Threshold { get; set; } = 100;
         public bool CheckIfLess { get; set; } = false;
 
-        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
+        public override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
         {
-            if (CheckIfLess)
-                return (double)value < Threshold ? Visibility.Visible : Visibility.Hidden;
-            else
-                return (double)value >= Threshold ? Visibility.Visible : Visibility.Hidden;
-        }
-
-        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
-        {
-            throw new NotImplementedException();
+            return CheckIfLess
+                   ? (double)value < Threshold ? Visibility.Visible : Visibility.Hidden
+                   : (double)value >= Threshold ? Visibility.Visible : Visibility.Hidden;
         }
     }
 }

+ 5 - 4
PixiEditor/Helpers/Converters/ToolSizeToIntConverter.cs

@@ -4,17 +4,18 @@ using System.Linq;
 using System.Text.RegularExpressions;
 using System.Windows.Data;
 
-namespace PixiEditor.Helpers
+namespace PixiEditor.Helpers.Converters
 {
     [ValueConversion(typeof(string), typeof(int))]
-    internal class ToolSizeToIntConverter : IValueConverter
+    internal class ToolSizeToIntConverter
+        : SingleInstanceConverter<ToolSizeToIntConverter>
     {
-        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
+        public override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
         {
             return string.Format("{0} {1}", value, "px");
         }
 
-        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
+        public override object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
         {
             if (string.IsNullOrWhiteSpace(value as string))
             {

+ 3 - 7
PixiEditor/Helpers/Converters/ZoomToViewportConverter.cs

@@ -5,9 +5,10 @@ using System.Windows.Data;
 
 namespace PixiEditor.Helpers.Converters
 {
-    public class ZoomToViewportConverter : IValueConverter
+    public class ZoomToViewportConverter
+        : SingleInstanceConverter<ZoomToViewportConverter>
     {
-        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
+        public override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
         {
             if (value is double scale)
             {
@@ -17,10 +18,5 @@ namespace PixiEditor.Helpers.Converters
 
             return Binding.DoNothing;
         }
-
-        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
-        {
-            throw new NotImplementedException();
-        }
     }
 }

+ 2 - 5
PixiEditor/Views/Dialogs/HelloTherePopup.xaml

@@ -11,9 +11,6 @@
         WindowStyle="None" WindowStartupLocation="CenterScreen">
 
     <Window.Resources>
-        <converters:EqualityBoolToVisibilityConverter x:Key="EqualityBoolToVisibilityConverter"/>
-        <converters:FileExtensionToColorConverter x:Key="FileExtensionToColorConverter"/>
-
         <Style TargetType="TextBlock">
             <Setter Property="Foreground" Value="White"/>
             <Setter Property="FontSize" Value="16"/>
@@ -76,7 +73,7 @@
                     <TextBlock Margin="0,12.5,0,0" Foreground="LightGray" HorizontalAlignment="Center">
                         <TextBlock.Visibility>
                             <Binding Path="RecentlyOpened.Count"
-                                     Converter="{StaticResource EqualityBoolToVisibilityConverter}">
+                                     Converter="{converters:EqualityBoolToVisibilityConverter}">
                                 <Binding.ConverterParameter>
                                     <sys:Int32/>
                                 </Binding.ConverterParameter>
@@ -98,7 +95,7 @@
                                             <Grid Width="100" Height="100">
                                                 <Image Source="{Binding PreviewBitmap}" Margin="20"/>
                                                 <Border Grid.Row="1" Height="8" Width="8" x:Name="extensionBorder" Margin="5"
-                                                        Background="{Binding FileExtension, Converter={StaticResource FileExtensionToColorConverter}}" 
+                                                        Background="{Binding FileExtension, Converter={converters:FileExtensionToColorConverter}}" 
                                                         VerticalAlignment="Bottom" HorizontalAlignment="Right">
                                                     <Border.Style>
                                                         <Style TargetType="Border">

+ 0 - 4
PixiEditor/Views/Dialogs/ImportFilePopup.xaml

@@ -4,16 +4,12 @@
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
         xmlns:local="clr-namespace:PixiEditor.Views"
-        xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
         xmlns:vm="clr-namespace:PixiEditor.ViewModels"
-        xmlns:behaviors="clr-namespace:PixiEditor.Helpers.Behaviours"
-        xmlns:helpers="clr-namespace:PixiEditor.Helpers"
         mc:Ignorable="d" BorderBrush="Black" BorderThickness="1"
         Title="ImportFilePopup" Topmost="True" ShowInTaskbar="False" Height="350" Width="300" WindowStyle="None" WindowStartupLocation="CenterScreen" Name="importFilePopup" MinHeight="350" MinWidth="300"
         DataContext="{DynamicResource ImportFilePopupViewModel}">
     <Window.Resources>
         <vm:ImportFilePopupViewModel x:Key="ImportFilePopupViewModel" />
-        <helpers:ToolSizeToIntConverter x:Key="ToolSizeToIntConverter" />
     </Window.Resources>
     <WindowChrome.WindowChrome>
         <WindowChrome CaptionHeight="32"  GlassFrameThickness="0.1"

+ 0 - 4
PixiEditor/Views/Dialogs/NewFilePopup.xaml

@@ -4,16 +4,12 @@
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
         xmlns:local="clr-namespace:PixiEditor.Views"
-        xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
         xmlns:vm="clr-namespace:PixiEditor.ViewModels"
-        xmlns:helpers="clr-namespace:PixiEditor.Helpers.Behaviours"
-        xmlns:converters="clr-namespace:PixiEditor.Helpers"
         mc:Ignorable="d"
         d:DesignHeight="600" Topmost="True" ShowInTaskbar="False" d:DesignWidth="450"
         DataContext="{DynamicResource NewFileMenuViewModel}" WindowStyle="None" WindowStartupLocation="CenterScreen" MinHeight="300" MinWidth="400" Height="600" Width="450" Name="newFilePopup" BorderBrush="Black" BorderThickness="1">
     <Window.Resources>
         <vm:NewFileMenuViewModel x:Key="NewFileMenuViewModel" />
-        <converters:ToolSizeToIntConverter x:Key="ToolSizeToIntConverter" />
     </Window.Resources>
     <WindowChrome.WindowChrome>
         <WindowChrome CaptionHeight="32"  GlassFrameThickness="0.1"

+ 0 - 5
PixiEditor/Views/Dialogs/ResizeCanvasPopup.xaml

@@ -6,15 +6,10 @@
         xmlns:local="clr-namespace:PixiEditor.Views"
         xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
         xmlns:behaviors="clr-namespace:PixiEditor.Helpers.Behaviours"
-        xmlns:converters="clr-namespace:PixiEditor.Helpers"
         mc:Ignorable="d" Name="window"
         Title="ResizeCanvasPopup" Topmost="True" ShowInTaskbar="False" WindowStartupLocation="CenterScreen"
         Height="390" Width="400" WindowStyle="None">
 
-    <Window.Resources>
-        <converters:ToolSizeToIntConverter x:Key="ToolSizeToIntConverter" />
-    </Window.Resources>
-
     <WindowChrome.WindowChrome>
         <WindowChrome CaptionHeight="32"  GlassFrameThickness="0.1"
                       ResizeBorderThickness="{x:Static SystemParameters.WindowResizeBorderThickness}" />

+ 0 - 5
PixiEditor/Views/Dialogs/ResizeDocumentPopup.xaml

@@ -5,15 +5,10 @@
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
         xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
         xmlns:local="clr-namespace:PixiEditor.Views" xmlns:behaviors="clr-namespace:PixiEditor.Helpers.Behaviours"
-        xmlns:converters="clr-namespace:PixiEditor.Helpers"
         mc:Ignorable="d" Name="window"
         Title="ResizeDocumentPopup" Topmost="True" ShowInTaskbar="False" WindowStartupLocation="CenterScreen"
         Height="300" Width="400" WindowStyle="None">
 
-    <Window.Resources>
-        <converters:ToolSizeToIntConverter x:Key="ToolSizeToIntConverter" />
-    </Window.Resources>
-
     <WindowChrome.WindowChrome>
         <WindowChrome CaptionHeight="32" GlassFrameThickness="0.1"
                       ResizeBorderThickness="{x:Static SystemParameters.WindowResizeBorderThickness}" />

+ 2 - 6
PixiEditor/Views/Dialogs/SaveFilePopup.xaml

@@ -5,14 +5,10 @@
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
         xmlns:local="clr-namespace:PixiEditor.Views"
         xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
-        xmlns:vm="clr-namespace:PixiEditor.ViewModels"
-        xmlns:helpers="clr-namespace:PixiEditor.Helpers.Behaviours" xmlns:helpers1="clr-namespace:PixiEditor.Helpers"
+        xmlns:behaviours="clr-namespace:PixiEditor.Helpers.Behaviours"
         mc:Ignorable="d" BorderBrush="Black" BorderThickness="1"
         Title="SaveFilePopup" Height="300" Width="400" WindowStyle="None" MinHeight="300" MinWidth="400"
         WindowStartupLocation="CenterScreen" Name="saveFilePopup">
-    <Window.Resources>
-        <helpers1:ToolSizeToIntConverter x:Key="ToolSizeToIntConverter" />
-    </Window.Resources>
     <WindowChrome.WindowChrome>
         <WindowChrome CaptionHeight="32"  GlassFrameThickness="0.1"
                       ResizeBorderThickness="{x:Static SystemParameters.WindowResizeBorderThickness}" />
@@ -29,7 +25,7 @@
             <RowDefinition />
         </Grid.RowDefinitions>
         <i:Interaction.Behaviors>
-            <helpers:ClearFocusOnClickBehavior/>
+            <behaviours:ClearFocusOnClickBehavior/>
         </i:Interaction.Behaviors>
 
         <DockPanel Grid.Row="0" Background="{StaticResource MainColor}">

+ 3 - 4
PixiEditor/Views/Dialogs/SettingsWindow.xaml

@@ -12,7 +12,6 @@
         BorderBrush="Black" BorderThickness="1">
     <Window.Resources>
         <viewmodels:SettingsWindowViewModel x:Key="SettingsWindowViewModel"/>
-        <converters:EqualityBoolToVisibilityConverter x:Key="EqualityBoolToVisibilityConverter"/>
         <BoolToVisibilityConverter x:Key="BoolToVisibilityConverter"/>
     </Window.Resources>
     <WindowChrome.WindowChrome>
@@ -54,7 +53,7 @@
                     Command="{Binding SelectCategoryCommand}" CommandParameter="Discord">Discord</Button>
         </StackPanel>
         <Grid Grid.Row="1" Grid.Column="1" Background="{StaticResource AccentColor}">
-            <Grid Visibility="{Binding SelectedCategory, Converter={StaticResource EqualityBoolToVisibilityConverter},
+            <Grid Visibility="{Binding SelectedCategory, Converter={converters:EqualityBoolToVisibilityConverter},
             ConverterParameter='General'}">
                 <StackPanel Orientation="Vertical">
                     <CheckBox Content="Show Document Preview in Taskbar" Margin="25,30,0,0"
@@ -77,7 +76,7 @@
                     </StackPanel>
                 </StackPanel>
             </Grid>
-            <Grid Visibility="{Binding SelectedCategory, Converter={StaticResource EqualityBoolToVisibilityConverter},
+            <Grid Visibility="{Binding SelectedCategory, Converter={converters:EqualityBoolToVisibilityConverter},
             ConverterParameter='Updates'}">
                 <StackPanel Orientation="Vertical">
                     <Label Style="{StaticResource Header1}" Content="Auto-updates"/>
@@ -86,7 +85,7 @@
                     </StackPanel>
                 </StackPanel>
             </Grid>
-            <Grid Visibility="{Binding SelectedCategory, Converter={StaticResource EqualityBoolToVisibilityConverter},
+            <Grid Visibility="{Binding SelectedCategory, Converter={converters:EqualityBoolToVisibilityConverter},
             ConverterParameter='Discord'}">
                 <StackPanel Orientation="Vertical">
                     <Label Style="{StaticResource Header1}" Content="Rich Presence"/>

+ 2 - 3
PixiEditor/Views/Dialogs/ShortcutPopup.xaml

@@ -11,7 +11,6 @@
         Title="ShortcutPopup" Height="815" Width="620" WindowStyle="None"
         MinHeight="400" MinWidth="350" Topmost="{Binding IsTopmost}">
     <Window.Resources>
-        <converters:KeyToStringConverter x:Key="KeyToStringConverter"/>
         <BoolToVisibilityConverter x:Key="BoolToVisibility"/>
         
         <Style TargetType="Border" x:Key="KeyBorder">
@@ -89,7 +88,7 @@
                                                     <ItemsControl.ItemTemplate>
                                                         <DataTemplate DataType="{x:Type ModifierKeys}">
                                                             <Border Style="{StaticResource KeyBorder}">
-                                                                <TextBlock Text="{Binding BindsDirectlyToSource=True, Converter={StaticResource KeyToStringConverter}}" Style="{StaticResource KeyBorderText}"/>
+                                                                <TextBlock Text="{Binding BindsDirectlyToSource=True, Converter={converters:KeyToStringConverter}}" Style="{StaticResource KeyBorderText}"/>
                                                             </Border>
                                                         </DataTemplate>
                                                     </ItemsControl.ItemTemplate>
@@ -100,7 +99,7 @@
                                                     </ItemsControl.ItemsPanel>
                                                 </ItemsControl>
                                                 <Border Style="{StaticResource KeyBorderLast}">
-                                                    <TextBlock Text="{Binding ShortcutKey, Converter={StaticResource KeyToStringConverter}}" Style="{StaticResource KeyBorderText}"/>
+                                                    <TextBlock Text="{Binding ShortcutKey, Converter={converters:KeyToStringConverter}}" Style="{StaticResource KeyBorderText}"/>
                                                 </Border>
 
                                                 <TextBlock Text="{Binding Description}" Foreground="#FFEEEEEE"  FontSize="14" Margin="8,0,0,0"/>

+ 9 - 15
PixiEditor/Views/MainWindow.xaml

@@ -24,12 +24,6 @@
     <Window.Resources>
         <ResourceDictionary>
             <BooleanToVisibilityConverter x:Key="BoolToVisibilityConverter" />
-            <converters:BoolToIntConverter x:Key="BoolToIntConverter" />
-            <converters:NotNullToBoolConverter x:Key="NotNullToBoolConverter" />
-            <converters:LayersToStructuredLayersConverter x:Key="LayersToStructuredLayersConverter"/>
-            <converters:DoubleToIntConverter x:Key="DoubleToIntConverter"/>
-            <converters:IsSpecifiedTypeConverter SpecifiedType="{x:Type tools:ZoomTool}" x:Key="IsZoomToolConverter"/>
-            <converters:IsSpecifiedTypeConverter SpecifiedType="{x:Type tools:MoveViewportTool}" x:Key="IsMoveViewportToolConverter"/>
             <ResourceDictionary.MergedDictionaries>
                 <ResourceDictionary Source="pack://application:,,,/ColorPicker;component/Styles/DefaultColorPickerStyle.xaml" />
             </ResourceDictionary.MergedDictionaries>
@@ -269,8 +263,8 @@
                                         MouseXOnCanvas="{Binding MouseXOnCanvas, Mode=TwoWay}"
                                         MouseYOnCanvas="{Binding MouseYOnCanvas, Mode=TwoWay}"
                                         UseTouchGestures="{Binding XamlAccesibleViewModel.StylusSubViewModel.UseTouchGestures}"
-                                        IsUsingZoomTool="{Binding XamlAccesibleViewModel.BitmapManager.SelectedTool, Converter={StaticResource IsZoomToolConverter}}"
-                                        IsUsingMoveViewportTool="{Binding XamlAccesibleViewModel.BitmapManager.SelectedTool, Converter={StaticResource IsMoveViewportToolConverter}}"
+                                        IsUsingZoomTool="{Binding XamlAccesibleViewModel.BitmapManager.SelectedTool, Converter={converters:IsSpecifiedTypeConverter SpecifiedType={x:Type tools:ZoomTool}}}"
+                                        IsUsingMoveViewportTool="{Binding XamlAccesibleViewModel.BitmapManager.SelectedTool, Converter={converters:IsSpecifiedTypeConverter SpecifiedType={x:Type tools:MoveViewportTool}}}"
                                         Stylus.IsTapFeedbackEnabled="False" Stylus.IsTouchFeedbackEnabled="False">
                                         <i:Interaction.Triggers>
                                             <i:EventTrigger EventName="PreviewMouseDown">
@@ -334,9 +328,9 @@
                                         <layerUserControls:LayersManager                                            
                                             LayerCommandsViewModel="{Binding LayersSubViewModel}"
                                             OpacityInputEnabled="{Binding BitmapManager.ActiveDocument, 
-                    Converter={StaticResource NotNullToBoolConverter}}">
+                    Converter={converters:NotNullToBoolConverter}}">
                                             <layerUserControls:LayersManager.LayerTreeRoot>
-                                                <MultiBinding Converter="{StaticResource LayersToStructuredLayersConverter}">
+                                                <MultiBinding Converter="{converters:LayersToStructuredLayersConverter}">
                                                     <Binding Path="BitmapManager.ActiveDocument.Layers" />
                                                     <Binding Path="BitmapManager.ActiveDocument.LayerStructure"/>
                                                 </MultiBinding>
@@ -371,11 +365,11 @@
             <ItemsControl ItemsSource="{Binding ToolsSubViewModel.ToolSet}">
                 <ItemsControl.ItemTemplate>
                     <DataTemplate>
-                        <Button BorderBrush="White"                                
-                                BorderThickness="{Binding IsActive, Converter={StaticResource BoolToIntConverter}}"
+                        <Button BorderBrush="White"
+                                BorderThickness="{Binding IsActive, Converter={converters:BoolToIntConverter}}"
                                 Style="{StaticResource ToolButtonStyle}"
                                 Command="{Binding Path=DataContext.ToolsSubViewModel.SelectToolCommand,
-                            RelativeSource={RelativeSource AncestorType={x:Type Window}}}"
+                                                  RelativeSource={RelativeSource AncestorType={x:Type Window}}}"
                                 CommandParameter="{Binding}" ToolTip="{Binding Tooltip}">
                             <Button.Background>
                                 <ImageBrush ImageSource="{Binding ImagePath}" Stretch="Uniform" />
@@ -401,9 +395,9 @@
                 <TextBlock Text="{Binding ActionDisplay}" Foreground="White" FontSize="15" Margin="10,0,0,0" VerticalAlignment="Center"/>
                 <StackPanel DockPanel.Dock="Right" Orientation="Horizontal" HorizontalAlignment="Right" VerticalAlignment="Center">
                     <TextBlock Text="X:" Foreground="White" FontSize="16"/>
-                    <TextBlock Margin="4,0,10,0" Text="{Binding BitmapManager.ActiveDocument.MouseXOnCanvas, Converter={StaticResource DoubleToIntConverter}}" Foreground="White" FontSize="16"/>
+                    <TextBlock Margin="4,0,10,0" Text="{Binding BitmapManager.ActiveDocument.MouseXOnCanvas, Converter={converters:DoubleToIntConverter}}" Foreground="White" FontSize="16"/>
                     <TextBlock Text="Y:" Foreground="White" FontSize="16"/>
-                    <TextBlock Margin="4,0,10,0" Text="{Binding BitmapManager.ActiveDocument.MouseYOnCanvas, Converter={StaticResource DoubleToIntConverter}}" Foreground="White" FontSize="16"/>
+                    <TextBlock Margin="4,0,10,0" Text="{Binding BitmapManager.ActiveDocument.MouseYOnCanvas, Converter={converters:DoubleToIntConverter}}" Foreground="White" FontSize="16"/>
                 </StackPanel>
             </DockPanel>
             <StackPanel Margin="10,0,0,0" VerticalAlignment="Center" Grid.Row="3"

+ 0 - 41
PixiEditor/Views/UserControls/AvalonDockWindows/ReferenceLayerWindow.xaml

@@ -1,41 +0,0 @@
-<UserControl x:Class="PixiEditor.Views.UserControls.AvalonDockWindows.ReferenceLayerWindow"
-             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
-             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:local="clr-namespace:PixiEditor.Views.UserControls.AvalonDockWindows" xmlns:views="clr-namespace:PixiEditor.Views" xmlns:converters="clr-namespace:PixiEditor.Helpers.Converters"
-             mc:Ignorable="d" 
-             d:DesignHeight="200" d:DesignWidth="200"
-             Name="uc">
-    <UserControl.Resources>
-        <Style TargetType="TextBlock">
-            <Setter Property="Foreground" Value="White"/>
-        </Style>
-        <converters:NotNullToBoolConverter x:Key="NotNullToBoolConverter"/>
-    </UserControl.Resources>
-    
-    <StackPanel Margin="5">
-        <Grid>
-            <Grid.ColumnDefinitions>
-                <ColumnDefinition Width="Auto"/>
-                <ColumnDefinition/>
-                <ColumnDefinition Width="Auto"/>
-            </Grid.ColumnDefinitions>
-            <TextBlock Margin="0,0,5,0" VerticalAlignment="Center">Path:</TextBlock>
-            <TextBox Text="{Binding FilePath, ElementName=uc}" Grid.Column="1"
-                     Style="{StaticResource DarkTextBoxStyle}" FontSize="14"/>
-            <Button Grid.Column="2" Content="&#xE838;" VerticalAlignment="Center"
-                    Style="{StaticResource ToolSettingsGlyphButton}" Width="20"
-                    Command="{Binding OpenFilePickerCommand, ElementName=uc}"></Button>
-        </Grid>
-        <StackPanel Orientation="Horizontal" Margin="0,5,0,0">
-            <TextBlock Text="Opacity: " Foreground="White" VerticalAlignment="Center"/>
-            <views:NumberInput Min="0" Max="100" Value="{Binding LayerOpacity, ElementName=uc, Mode=TwoWay}"
-                               Width="40" Height="20" VerticalAlignment="Center"/>
-            <TextBlock Text=" %" Foreground="White" VerticalAlignment="Center"/>
-        </StackPanel>
-        <Button Command="{Binding UpdateLayerCommand, ElementName=uc}"
-                Style="{StaticResource DarkRoundButton}" FontSize="14" 
-                Height="25" Margin="0,5">Update</Button>
-    </StackPanel>
-</UserControl>

+ 0 - 82
PixiEditor/Views/UserControls/AvalonDockWindows/ReferenceLayerWindow.xaml.cs

@@ -1,82 +0,0 @@
-using Microsoft.Win32;
-using PixiEditor.Helpers;
-using PixiEditor.Models.DataHolders;
-using PixiEditor.Models.IO;
-using System.Windows;
-using System.Windows.Controls;
-
-namespace PixiEditor.Views.UserControls.AvalonDockWindows
-{
-    /// <summary>
-    /// Interaction logic for ReferenceLayerWindow.xaml
-    /// </summary>
-    public partial class ReferenceLayerWindow : UserControl
-    {
-        public static readonly DependencyProperty DocumentProperty =
-            DependencyProperty.Register(nameof(Document), typeof(Document), typeof(ReferenceLayerWindow));
-
-        public Document Document
-        {
-            get => (Document)GetValue(DocumentProperty);
-            set => SetValue(DocumentProperty, value);
-        }
-
-        public static readonly DependencyProperty FilePathProperty =
-            DependencyProperty.Register(nameof(FilePath), typeof(string), typeof(ReferenceLayerWindow));
-
-        public string FilePath
-        {
-            get => (string)GetValue(FilePathProperty);
-            set => SetValue(FilePathProperty, value);
-        }
-
-        public static readonly DependencyProperty LayerOpacityProperty =
-            DependencyProperty.Register(nameof(LayerOpacity), typeof(float), typeof(ReferenceLayerWindow), new PropertyMetadata(100f));
-
-        public float LayerOpacity
-        {
-            get => (float)GetValue(LayerOpacityProperty);
-            set => SetValue(LayerOpacityProperty, value);
-        }
-
-        public static readonly DependencyProperty HasDocumentProperty =
-            DependencyProperty.Register(nameof(HasDocument), typeof(bool), typeof(ReferenceLayerWindow));
-
-        public bool HasDocument
-        {
-            get => (bool)GetValue(HasDocumentProperty);
-            set => SetValue(HasDocumentProperty, value);
-        }
-
-        public RelayCommand UpdateLayerCommand { get; set; }
-
-        public RelayCommand OpenFilePickerCommand { get; set; }
-
-        public ReferenceLayerWindow()
-        {
-            UpdateLayerCommand = new RelayCommand(UpdateLayer);
-            OpenFilePickerCommand = new RelayCommand(OpenFilePicker);
-            InitializeComponent();
-        }
-
-        private void UpdateLayer(object obj)
-        {
-            Document.ReferenceLayer.LayerBitmap = Importer.ImportImage(FilePath);
-            Document.ReferenceLayer.Opacity = LayerOpacity;
-        }
-
-        private void OpenFilePicker(object obj)
-        {
-            OpenFileDialog dialog = new OpenFileDialog()
-            {
-                Filter = "PNG Files|*.png|JPEG Files|*.jpg;*.jpeg",
-                CheckFileExists = true
-            };
-
-            if ((bool)dialog.ShowDialog())
-            {
-                FilePath = dialog.FileName;
-            }
-        }
-    }
-}

+ 8 - 9
PixiEditor/Views/UserControls/DiscordRPPreview.xaml

@@ -8,9 +8,7 @@
              d:DesignHeight="280" d:DesignWidth="300"
              x:Name="uc">
     <UserControl.Resources>
-        <converters:EmptyStringToVisibilityConverter x:Key="EmptyStringToVisibility"/>
         <BoolToVisibilityConverter x:Key="BoolToVisibility"/>
-        <converters:BoolToBrushConverter x:Key="BoolToBrush"/>
         <converters:BrushTuple FirstBrush="#7289da" SecondBrush="#202225" x:Key="BackgroundBrushTuple"/>
         <converters:BrushTuple FirstBrush="White" SecondBrush="#7289da" x:Key="BotLabelTuple"/>
         <converters:BrushTuple FirstBrush="#7289da" SecondBrush="White" x:Key="BotTextTuple"/>
@@ -20,7 +18,7 @@
         <Grid.OpacityMask>
             <VisualBrush Visual="{Binding ElementName=OutsideBorder}"/>
         </Grid.OpacityMask>
-        <Border CornerRadius="5" Background="{Binding ElementName=uc, Path=IsPlaying, Converter={StaticResource BoolToBrush}, ConverterParameter={StaticResource BackgroundBrushTuple}}" x:Name="OutsideBorder"/>
+        <Border CornerRadius="5" Background="{Binding ElementName=uc, Path=IsPlaying, Converter={converters:BoolToBrushConverter}, ConverterParameter={StaticResource BackgroundBrushTuple}}" x:Name="OutsideBorder"/>
         <Grid x:Name="background">
             <Grid.RowDefinitions>
                     <RowDefinition Height="Auto"/>
@@ -31,7 +29,8 @@
                     <StackPanel>
                         <Grid  Width="80" Height="80" Margin="20">
                             <Image Source="{Binding ElementName=uc, Path=UserSource}"/>
-                        <Border Height="30" Width="30" Background="#FF43B581" CornerRadius="90" BorderThickness="5" BorderBrush="{Binding ElementName=uc, Path=IsPlaying, Converter={StaticResource BoolToBrush}, ConverterParameter={StaticResource BackgroundBrushTuple}}">
+                        <Border Height="30" Width="30" Background="#FF43B581" CornerRadius="90" BorderThickness="5" 
+                                BorderBrush="{Binding ElementName=uc, Path=IsPlaying, Converter={converters:BoolToBrushConverter}, ConverterParameter={StaticResource BackgroundBrushTuple}}">
                                 <Border.RenderTransform>
                                     <TransformGroup>
                                         <TranslateTransform X="27" Y="27"></TranslateTransform>
@@ -42,9 +41,9 @@
 
                         <StackPanel Orientation="Horizontal" HorizontalAlignment="Center" Margin="0,0,0,15">
                             <TextBlock Foreground="White" FontSize="16" FontWeight="SemiBold">PixiBot</TextBlock>
-                        <TextBlock Foreground="{Binding ElementName=uc, Path=IsPlaying, Converter={StaticResource BoolToBrush}, ConverterParameter={StaticResource DiscriminatorTuple}}" FontSize="16">#8523</TextBlock>
-                            <Border CornerRadius="3" BorderThickness="1" Background="{Binding ElementName=uc, Path=IsPlaying, Converter={StaticResource BoolToBrush}, ConverterParameter={StaticResource BotLabelTuple}}" Margin="5,0,0,0" VerticalAlignment="Center">
-                            <TextBlock Foreground="{Binding ElementName=uc, Path=IsPlaying, Converter={StaticResource BoolToBrush}, ConverterParameter={StaticResource BotTextTuple}}" FontSize="12" Margin="4,2,4,2" FontWeight="Medium">BOT</TextBlock>
+                        <TextBlock Foreground="{Binding ElementName=uc, Path=IsPlaying, Converter={converters:BoolToBrushConverter}, ConverterParameter={StaticResource DiscriminatorTuple}}" FontSize="16">#8523</TextBlock>
+                        <Border CornerRadius="3" BorderThickness="1" Background="{Binding ElementName=uc, Path=IsPlaying, Converter={converters:BoolToBrushConverter}, ConverterParameter={StaticResource BotLabelTuple}}" Margin="5,0,0,0" VerticalAlignment="Center">
+                            <TextBlock Foreground="{Binding ElementName=uc, Path=IsPlaying, Converter={converters:BoolToBrushConverter}, ConverterParameter={StaticResource BotTextTuple}}" FontSize="12" Margin="4,2,4,2" FontWeight="Medium">BOT</TextBlock>
                             </Border>
                         </StackPanel>
                     </StackPanel>
@@ -56,8 +55,8 @@
                             <Image Source="../../Images/PixiEditorLogo.png" Height="70"/>
                             <StackPanel Margin="15,0,0,0" VerticalAlignment="Center">
                                 <TextBlock Foreground="White" FontSize="12" FontWeight="SemiBold">PixiEditor</TextBlock>
-                            <TextBlock Foreground="White" FontSize="12" Text="{Binding ElementName=uc, Path=Detail}" Visibility="{Binding ElementName=uc, Path=Detail, Converter={StaticResource EmptyStringToVisibility}}"/>
-                            <TextBlock Foreground="White" FontSize="12" Text="{Binding ElementName=uc, Path=State}" Visibility="{Binding ElementName=uc, Path=State, Converter={StaticResource EmptyStringToVisibility}}"/>
+                            <TextBlock Foreground="White" FontSize="12" Text="{Binding ElementName=uc, Path=Detail}" Visibility="{Binding ElementName=uc, Path=Detail, Converter={converters:EmptyStringToVisibilityConverter}}"/>
+                            <TextBlock Foreground="White" FontSize="12" Text="{Binding ElementName=uc, Path=State}" Visibility="{Binding ElementName=uc, Path=State, Converter={converters:EmptyStringToVisibilityConverter}}"/>
                             <TextBlock Foreground="White" FontSize="12">00:00 elapsed</TextBlock>
                             </StackPanel>
                         </StackPanel>

+ 1 - 4
PixiEditor/Views/UserControls/EditableTextBlock.xaml

@@ -6,9 +6,6 @@
              xmlns:converters="clr-namespace:PixiEditor.Helpers.Converters" xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" xmlns:behaviours="clr-namespace:PixiEditor.Helpers.Behaviours"
              mc:Ignorable="d"
              d:DesignHeight="60" d:DesignWidth="100">
-    <UserControl.Resources>
-        <converters:OppositeVisibilityConverter x:Key="OppositeVisibilityConverter" />
-    </UserControl.Resources>
     <Grid>
         <TextBlock Foreground="Snow" MouseLeftButtonDown="TextBlock_MouseDown"
                    TextTrimming="CharacterEllipsis" Name="textBlock"
@@ -20,7 +17,7 @@
                  KeyDown="TextBox_KeyDown"
                  LostKeyboardFocus="TextBox_LostKeyboardFocus"
                  Visibility="{Binding Path=TextBlockVisibility, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type UserControl}}, 
-            Converter={StaticResource OppositeVisibilityConverter}}"
+                                      Converter={converters:OppositeVisibilityConverter}}"
                  Name="textBox">
             <i:Interaction.Behaviors>
                 <behaviours:GlobalShortcutFocusBehavior/>

+ 6 - 2
PixiEditor/Views/UserControls/Layers/LayerGroupControl.xaml

@@ -7,7 +7,6 @@
              mc:Ignorable="d" Focusable="True"
              d:DesignHeight="60" d:DesignWidth="250" Name="groupControl" DragEnter="GroupControl_DragEnter" DragLeave="GroupControl_DragLeave" DragDrop.Drop="GroupControl_DragLeave">
     <UserControl.Resources>
-        <converters:InverseBooleanConverter x:Key="InverseBooleanConverter"/>
         <BooleanToVisibilityConverter x:Key="BoolToVisibilityConverter" />
     </UserControl.Resources>
     <Border BorderThickness="0 0 0 0.5" BorderBrush="Gray" MinWidth="60" Focusable="True" Tag="{Binding ElementName=groupControl}" MouseDown="Border_MouseDown">
@@ -49,7 +48,12 @@
                     <Image Source="/Images/Folder.png" Height="20" Margin="0,0,10,0" HorizontalAlignment="Right"/>
                 </StackPanel>
             </Grid>
-            <Grid DragEnter="Grid_DragEnter" Drop="Grid_Drop_Bottom"  DragLeave="Grid_DragLeave" Grid.Row="2" AllowDrop="{Binding  GroupData.IsExpanded, ElementName=groupControl, Converter={StaticResource InverseBooleanConverter}}" Grid.ColumnSpan="2" Background="Transparent"/>
+            <Grid DragEnter="Grid_DragEnter" Drop="Grid_Drop_Bottom" 
+                  DragLeave="Grid_DragLeave" Grid.Row="2"
+                  AllowDrop="{Binding GroupData.IsExpanded,
+                                      ElementName=groupControl,
+                                      Converter={converters:InverseBooleanConverter}}"
+                  Grid.ColumnSpan="2" Background="Transparent"/>
         </Grid>
         <Border.ContextMenu>
             <ContextMenu>

+ 1 - 4
PixiEditor/Views/UserControls/Layers/LayersManager.xaml

@@ -9,9 +9,6 @@
              xmlns:converters="clr-namespace:PixiEditor.Helpers.Converters" xmlns:layerUserControls="clr-namespace:PixiEditor.Views.UserControls.Layers"
              mc:Ignorable="d"
              d:DesignHeight="450" d:DesignWidth="250" x:Name="layersManager">
-    <UserControl.Resources>
-        <converters:IndexOfConverter x:Key="IndexOfConverter"/>
-    </UserControl.Resources>
     <Grid>
         <Grid.RowDefinitions>
             <RowDefinition Height="37.5"/>
@@ -82,7 +79,7 @@
                         <layerUserControls:LayerStructureItemContainer    
                             MouseDown="SelectActiveItem"
                             MouseMove="LayerStructureItemContainer_MouseMove" 
-                            ContainerIndex="{Binding Converter={StaticResource IndexOfConverter}}"
+                            ContainerIndex="{Binding Converter={converters:IndexOfConverter}}"
                             Layer="{Binding}" LayerCommandsViewModel="{Binding LayerCommandsViewModel, ElementName=layersManager}"/>
                     </DataTemplate>
                 </TreeView.Resources>

+ 1 - 4
PixiEditor/Views/UserControls/Layers/RawLayersViewer.xaml

@@ -6,9 +6,6 @@
              xmlns:local="clr-namespace:PixiEditor.Views.UserControls" xmlns:ui="clr-namespace:PixiEditor.Helpers.UI" xmlns:converters="clr-namespace:PixiEditor.Helpers.Converters"
              mc:Ignorable="d" 
              d:DesignHeight="450" d:DesignWidth="250" Name="rawLayersControl">
-    <UserControl.Resources>
-        <converters:LayerStructureToGroupsConverter x:Key="LayerStructureToGroupsConverter"/>
-    </UserControl.Resources>
     <StackPanel DataContext="{Binding ElementName=rawLayersControl}">
         <ItemsControl ItemsSource="{Binding Layers}">
             <ItemsControl.ItemsPanel>
@@ -28,7 +25,7 @@
         <Separator/>
         <ItemsControl>
             <ItemsControl.ItemsSource>
-                <MultiBinding Converter="{StaticResource LayerStructureToGroupsConverter}">
+                <MultiBinding Converter="{converters:LayerStructureToGroupsConverter}">
                     <Binding Path="Structure"/>
                     <Binding Path="Structure.Groups.Count"/>
                     <Binding Path="Layers.Count"/>

+ 16 - 10
PixiEditor/Views/UserControls/Layers/ReferenceLayer.xaml

@@ -6,10 +6,6 @@
              xmlns:local="clr-namespace:PixiEditor.Views.UserControls.Layers" xmlns:behaviors="clr-namespace:PixiEditor.Helpers.Behaviours" xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" xmlns:local1="clr-namespace:PixiEditor.Views.UserControls" xmlns:converters="clr-namespace:PixiEditor.Helpers.Converters"
              mc:Ignorable="d" 
              d:DesignHeight="60" d:DesignWidth="350" VerticalAlignment="Center" Name="uc">
-    <UserControl.Resources>
-        <converters:NotNullToVisibilityConverter x:Key="NotNullToVisibilityConverter"/>
-        <converters:NotNullToBoolConverter x:Key="NotNullToBoolConverter"/>
-    </UserControl.Resources>
     <Border BorderBrush="{StaticResource DarkerAccentColor}" BorderThickness="0 2 0 0" MinWidth="60" Focusable="True">
         <i:Interaction.Behaviors>
             <behaviors:ClearFocusOnClickBehavior/>
@@ -25,19 +21,29 @@
                     <Grid MouseDown="Grid_MouseDown" Cursor="Hand" Visibility="{Binding ElementName=visibilityCheckbox, Path=IsChecked, Converter={InverseBoolToVisibilityConverter}}"  Background="Transparent"/>
                 </Grid>
                 <Grid Grid.Column="0" Height="16" Name="layerVisibilityCheckboxGrid">
-                    <CheckBox Visibility="{Binding Layer, ElementName=uc, Converter={StaticResource NotNullToVisibilityConverter}}" Style="{StaticResource ImageCheckBox}" VerticalAlignment="Center"
-                      IsThreeState="False" HorizontalAlignment="Center" 
-                      IsChecked="{Binding Path=Layer.IsVisible, Mode=TwoWay, ElementName=uc}"/>
+                    <CheckBox 
+                        Visibility="{Binding Layer, 
+                                             ElementName=uc, 
+                                             Converter={converters:NotNullToVisibilityConverter}}"
+                        Style="{StaticResource ImageCheckBox}" VerticalAlignment="Center"
+                        IsThreeState="False" HorizontalAlignment="Center" 
+                        IsChecked="{Binding Path=Layer.IsVisible, Mode=TwoWay, ElementName=uc}"/>
                 </Grid>
                 <StackPanel Name="middleStackPanel" Height="40" Orientation="Horizontal" Grid.Column="1" HorizontalAlignment="Center">
-                    <Border HorizontalAlignment="Left" Visibility="{Binding Layer, ElementName=uc, Converter={StaticResource NotNullToVisibilityConverter}}" Width="30" Height="30" BorderThickness="1" BorderBrush="Black" Background="{StaticResource MainColor}"
-                           Margin="5, 0, 10, 0">
+                    <Border HorizontalAlignment="Left" 
+                            Visibility="{Binding Layer, ElementName=uc, Converter={converters:NotNullToVisibilityConverter}}" 
+                            Width="30" Height="30"
+                            BorderThickness="1" BorderBrush="Black"
+                            Background="{StaticResource MainColor}"
+                            Margin="5, 0, 10, 0">
                         <Image Source="{Binding Layer.LayerBitmap, ElementName=uc}" Stretch="Uniform" Width="25" Height="25" 
                        RenderOptions.BitmapScalingMode="NearestNeighbor"/>
                     </Border>
                     <Image Margin="0 0 5 0" Width="20" Source="/Images/Layer-add.png"  Visibility="{Binding Layer, ElementName=uc, Converter={converters:NullToVisibilityConverter}}"/>
 
-                    <local1:PrependTextBlock IsEnabled="{Binding ElementName=uc, Path=IsEnabled}" Margin="0 0 5 0" Prepend="Add " Foreground="White" HidePrepend="{Binding Layer, ElementName=uc, Converter={StaticResource NotNullToBoolConverter}}"
+                    <local1:PrependTextBlock IsEnabled="{Binding ElementName=uc, Path=IsEnabled}" 
+                                             Margin="0 0 5 0" Prepend="Add " Foreground="White" 
+                                             HidePrepend="{Binding Layer, ElementName=uc, Converter={converters:NotNullToBoolConverter}}"
                                              FontSize="15" VerticalAlignment="Center" Text="Reference Layer" />
                     <Button Click="TrashButton_Click" Cursor="Hand" Grid.Column="1" Visibility="{Binding Layer, ElementName=uc, Converter={BoolToVisibilityConverter}}" Style="{StaticResource ImageButtonStyle}" Width="20" Height="20" HorizontalAlignment="Right">
                         <Button.Background>

+ 1 - 2
PixiEditor/Views/UserControls/PreviewWindow.xaml

@@ -12,7 +12,6 @@
 
     <UserControl.Resources>
         <BoolToVisibilityConverter x:Key="BoolToVisibilityConverter"/>
-        <converters:NotNullToVisibilityConverter x:Key="NullToVisibilityConverter"/>
     </UserControl.Resources>
     <Grid>
         <Grid.RowDefinitions>
@@ -23,7 +22,7 @@
 
         <Viewbox Margin="30" VerticalAlignment="Center">
             <Grid x:Name="imageGrid" RenderOptions.BitmapScalingMode="NearestNeighbor"
-              Visibility="{Binding Document, Converter={StaticResource NullToVisibilityConverter}, ElementName=uc}"
+              Visibility="{Binding Document, Converter={converters:NullToVisibilityConverter}, ElementName=uc}"
               Height="{Binding Document.Height, ElementName=uc}" Width="{Binding Document.Width, ElementName=uc}"
               Background="{Binding ActiveItem.Value, ElementName=backgroundButton}" d:Width="8" d:Height="8">
                 <ItemsControl ItemsSource="{Binding Document.Layers, ElementName=uc}">

+ 2 - 5
PixiEditor/Views/UserControls/SizeInput.xaml

@@ -5,19 +5,16 @@
              xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
              xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
              xmlns:behaviors="clr-namespace:PixiEditor.Helpers.Behaviours"
-             xmlns:converters="clr-namespace:PixiEditor.Helpers"
+             xmlns:converters="clr-namespace:PixiEditor.Helpers.Converters"
              xmlns:validators="clr-namespace:PixiEditor.Helpers.Validators"
              mc:Ignorable="d"
              d:DesignHeight="30" d:DesignWidth="160" Name="uc" LayoutUpdated="UserControlLayoutUpdated">
-    <UserControl.Resources>
-        <converters:ToolSizeToIntConverter x:Key="ToolSizeToIntConverter" />
-    </UserControl.Resources>
     <TextBox IsEnabled="{Binding IsEnabled, ElementName=uc}" HorizontalContentAlignment="Center"
              Style="{StaticResource DarkTextBoxStyle}" MaxLength="4" InputScope="Number">
         <TextBox.Text>
             <Binding ElementName="uc"
                      Path="Size" Mode="TwoWay"
-                     Converter="{StaticResource ToolSizeToIntConverter}">
+                     Converter="{converters:ToolSizeToIntConverter}">
                 <Binding.ValidationRules>
                     <validators:SizeValidationRule ValidatesOnTargetUpdated="True" />
                 </Binding.ValidationRules>

+ 4 - 8
PixiEditor/Views/UserControls/SmallColorPicker.xaml

@@ -19,18 +19,14 @@
             <ResourceDictionary.MergedDictionaries>
                 <ResourceDictionary Source="pack://application:,,,/ColorPicker;component/Styles/DefaultColorPickerStyle.xaml" />
             </ResourceDictionary.MergedDictionaries>
-            <conv:IntToPickerTypeConverter x:Key="IntToPickerTypeConverter"/>
-            <conv:FloorConverter x:Key="FloorConverter"/>
-            <conv:ThresholdVisibilityConverter x:Key="ShowWhenBig" CheckIfLess="False" Threshold="380"/>
-            <conv:ThresholdVisibilityConverter x:Key="ShowWhenSmall" CheckIfLess="True" Threshold="380"/>
         </ResourceDictionary>
     </UserControl.Resources>
     <Grid>
         <colorpicker:StandardColorPicker ColorState="{Binding ElementName=uc, Path=ColorState, Mode=TwoWay, Delay=10}"
                                          SecondColorState="{Binding ElementName=uc, Path=SecondColorState, Mode=TwoWay, Delay=10}"
-                                         Visibility="{Binding ElementName=uc, Path=ActualHeight, Converter={StaticResource ShowWhenBig}}"
+                                         Visibility="{Binding ElementName=uc, Path=ActualHeight, Converter={conv:ThresholdVisibilityConverter CheckIfLess=False, Threshold=380}}"
                                          Style="{StaticResource DefaultColorPickerStyle}" x:Name="mainColorPicker" />
-        <Grid Visibility="{Binding ElementName=uc, Path=ActualHeight, Converter={StaticResource ShowWhenSmall}}">
+        <Grid Visibility="{Binding ElementName=uc, Path=ActualHeight, Converter={conv:ThresholdVisibilityConverter CheckIfLess=True, Threshold=380}}">
             <Grid.ColumnDefinitions>
                 <ColumnDefinition MaxWidth="80" Width="1*"/>
                 <ColumnDefinition Width="3*"/>
@@ -43,7 +39,7 @@
             </Grid.RowDefinitions>
             <colorpicker:SquarePicker Grid.ColumnSpan="2" Grid.RowSpan="2" Margin="3"
                                 ColorState="{Binding ColorState, Mode=TwoWay, ElementName=uc}"
-                                PickerType="{Binding ElementName=colorSpaceComboBox, Path=SelectedIndex, Converter={StaticResource IntToPickerTypeConverter}}"/>
+                                PickerType="{Binding ElementName=colorSpaceComboBox, Path=SelectedIndex, Converter={conv:IntToPickerTypeConverter}}"/>
             <colorpicker:ColorDisplay Grid.Row="1" Grid.RowSpan="2" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="3,0,0,0"
                                 ColorState="{Binding ColorState, Mode=TwoWay, ElementName=uc}" 
                                 SecondColorState="{Binding SecondColorState, Mode=TwoWay, ElementName=uc}"/>
@@ -68,7 +64,7 @@
                     Min="0" Max="255"
                     Width="40" Height="20"
                     VerticalAlignment="Center"
-                    Value="{Binding ElementName=uc, Path=Color.A, Mode=TwoWay, Delay=10, Converter={StaticResource FloorConverter}}" />
+                    Value="{Binding ElementName=uc, Path=Color.A, Mode=TwoWay, Delay=10, Converter={conv:FloorConverter}}" />
             </Grid>
         </Grid>
     </Grid>