From 14a681e6426b8a15d0c164b19a38789d0465270a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tiago=20Concei=C3=A7=C3=A3o?= Date: Sun, 27 Sep 2020 16:28:29 +0100 Subject: [PATCH] WPF progress --- UVtools.Core/FileFormats/ChituboxZipFile.cs | 11 ++- UVtools.Core/Objects/BindableBase.cs | 34 ++++++-- .../Operations/OperationChangeResolution.cs | 4 +- UVtools.Core/Operations/OperationProgress.cs | 24 +++--- UVtools.Core/Operations/OperationResize.cs | 8 +- UVtools.Core/Operations/OperationRotate.cs | 2 +- UVtools.Core/Operations/OperationThreshold.cs | 6 +- UVtools.GUI/Program.cs | 3 +- UVtools.WPF/App.axaml.cs | 4 +- UVtools.WPF/Controls/AdvancedImageBox.cs | 86 ++++++++----------- .../ToolChangeResolutionControl.axaml.cs | 2 +- .../Controls/Tools/ToolControl.axaml.cs | 49 +++++------ .../Tools/ToolThresholdControl.axaml.cs | 8 +- UVtools.WPF/Controls/WindowEx.cs | 48 +++++------ UVtools.WPF/MainWindow.axaml.cs | 86 +++++++++---------- UVtools.WPF/Structures/LogItem.cs | 8 +- UVtools.WPF/UserSettings.cs | 58 +++++++++++-- UVtools.WPF/Windows/ProgressWindow.axaml.cs | 4 +- UVtools.WPF/Windows/ToolWindow.axaml.cs | 32 +++---- 19 files changed, 258 insertions(+), 219 deletions(-) diff --git a/UVtools.Core/FileFormats/ChituboxZipFile.cs b/UVtools.Core/FileFormats/ChituboxZipFile.cs index 014a72e..7760b1a 100644 --- a/UVtools.Core/FileFormats/ChituboxZipFile.cs +++ b/UVtools.Core/FileFormats/ChituboxZipFile.cs @@ -9,6 +9,7 @@ using System; using System.ComponentModel; using System.Drawing; +using System.Globalization; using System.IO; using System.IO.Compression; using System.Linq; @@ -386,11 +387,17 @@ namespace UVtools.Core.FileFormats { HeaderSettings.LightPWM = byte.Parse(pwm.Groups[1].Value); } + var asd = exposureTime.NextMatch(); + var asd1 = currPos.Groups[1].Value; + var asd2 = exposureTime.NextMatch().Groups[1].Value; + + var posZ = float.Parse(asd1, CultureInfo.InvariantCulture); + var exp = float.Parse(asd2, CultureInfo.InvariantCulture) / 1000f; LayerManager[layerIndex] = new Layer(layerIndex, entry.Open(), entry.Name) { - PositionZ = float.Parse(currPos.Groups[1].Value), - ExposureTime = float.Parse(exposureTime.NextMatch().Groups[1].Value) / 1000f + PositionZ = posZ, + ExposureTime = exp }; progress++; } diff --git a/UVtools.Core/Objects/BindableBase.cs b/UVtools.Core/Objects/BindableBase.cs index 946b5ca..f2ce458 100644 --- a/UVtools.Core/Objects/BindableBase.cs +++ b/UVtools.Core/Objects/BindableBase.cs @@ -6,6 +6,7 @@ * of this license document, but changing it is not allowed. */ +using System.Collections.Generic; using System.ComponentModel; using System.Runtime.CompilerServices; @@ -19,7 +20,14 @@ namespace UVtools.Core.Objects /// /// Multicast event for property change notifications. /// - public event PropertyChangedEventHandler PropertyChanged; + private PropertyChangedEventHandler _propertyChanged; + private List events = new List(); + + public event PropertyChangedEventHandler PropertyChanged + { + add { _propertyChanged += value; events.Add("added"); } + remove { _propertyChanged -= value; events.Add("removed"); } + } /// /// Checks if a property already matches a desired value. Sets the property and @@ -37,7 +45,7 @@ namespace UVtools.Core.Objects /// True if the value was changed, false if the existing value matched the /// desired value. /// - protected bool SetProperty(ref T storage, T value, [CallerMemberName] string propertyName = null) + /*protected bool SetProperty(ref T storage, T value, [CallerMemberName] string propertyName = null) { if (Equals(storage, value)) { @@ -45,14 +53,21 @@ namespace UVtools.Core.Objects } storage = value; - OnPropertyChanged(propertyName); + RaisePropertyChanged(propertyName); + return true; + }*/ + + protected bool RaiseAndSetIfChanged(ref T field, T value, [CallerMemberName] string propertyName = null) + { + if (EqualityComparer.Default.Equals(field, value)) return false; + field = value; + RaisePropertyChanged(propertyName); return true; } - protected bool SetProperty([CallerMemberName] string propertyName = null) + + protected virtual void OnPropertyChanged(PropertyChangedEventArgs e) { - OnPropertyChanged(propertyName); - return true; } /// @@ -63,10 +78,11 @@ namespace UVtools.Core.Objects /// value is optional and can be provided automatically when invoked from compilers /// that support . /// - protected void OnPropertyChanged([CallerMemberName] string propertyName = null) + protected void RaisePropertyChanged([CallerMemberName] string propertyName = null) { - var eventHandler = PropertyChanged; - eventHandler?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + var e = new PropertyChangedEventArgs(propertyName); + OnPropertyChanged(e); + _propertyChanged?.Invoke(this, e); } } } diff --git a/UVtools.Core/Operations/OperationChangeResolution.cs b/UVtools.Core/Operations/OperationChangeResolution.cs index 5f6b0e9..9fa8eb1 100644 --- a/UVtools.Core/Operations/OperationChangeResolution.cs +++ b/UVtools.Core/Operations/OperationChangeResolution.cs @@ -91,13 +91,13 @@ namespace UVtools.Core.Operations public uint NewResolutionX { get => _newResolutionX; - set => SetProperty(ref _newResolutionX, value); + set => RaiseAndSetIfChanged(ref _newResolutionX, value); } public uint NewResolutionY { get => _newResolutionY; - set => SetProperty(ref _newResolutionY, value); + set => RaiseAndSetIfChanged(ref _newResolutionY, value); } public Rectangle VolumeBonds { get; } diff --git a/UVtools.Core/Operations/OperationProgress.cs b/UVtools.Core/Operations/OperationProgress.cs index 3ffce1f..5400f16 100644 --- a/UVtools.Core/Operations/OperationProgress.cs +++ b/UVtools.Core/Operations/OperationProgress.cs @@ -70,7 +70,7 @@ namespace UVtools.Core.Operations if (!_canCancel) return _canCancel; return !Token.IsCancellationRequested && Token.CanBeCanceled && _canCancel; } - set => SetProperty(ref _canCancel, value); + set => RaiseAndSetIfChanged(ref _canCancel, value); } /// @@ -79,7 +79,7 @@ namespace UVtools.Core.Operations public string Title { get => _title; - set => SetProperty(ref _title, value); + set => RaiseAndSetIfChanged(ref _title, value); } public string ElapsedTimeStr => $"{StopWatch.Elapsed.Minutes}m {StopWatch.Elapsed.Seconds}s {StopWatch.Elapsed.Milliseconds}ms"; @@ -90,7 +90,7 @@ namespace UVtools.Core.Operations public string ItemName { get => _itemName; - set => SetProperty(ref _itemName, value); + set => RaiseAndSetIfChanged(ref _itemName, value); } /// @@ -102,9 +102,9 @@ namespace UVtools.Core.Operations set { //_processedItems = value; - SetProperty(ref _processedItems, value); - OnPropertyChanged(nameof(ProgressPercent)); - OnPropertyChanged(nameof(Description)); + RaiseAndSetIfChanged(ref _processedItems, value); + RaisePropertyChanged(nameof(ProgressPercent)); + RaisePropertyChanged(nameof(Description)); } } @@ -116,10 +116,10 @@ namespace UVtools.Core.Operations get => _itemCount; set { - SetProperty(ref _itemCount, value); - OnPropertyChanged(nameof(IsIndeterminate)); - OnPropertyChanged(nameof(ProgressPercent)); - OnPropertyChanged(nameof(Description)); + RaiseAndSetIfChanged(ref _itemCount, value); + RaisePropertyChanged(nameof(IsIndeterminate)); + RaisePropertyChanged(nameof(ProgressPercent)); + RaisePropertyChanged(nameof(Description)); } } @@ -174,8 +174,8 @@ namespace UVtools.Core.Operations public void TriggerRefresh() { - OnPropertyChanged(nameof(ElapsedTimeStr)); - OnPropertyChanged(nameof(CanCancel)); + RaisePropertyChanged(nameof(ElapsedTimeStr)); + RaisePropertyChanged(nameof(CanCancel)); //OnPropertyChanged(nameof(ProgressPercent)); //OnPropertyChanged(nameof(Description)); } diff --git a/UVtools.Core/Operations/OperationResize.cs b/UVtools.Core/Operations/OperationResize.cs index b921a8d..2225067 100644 --- a/UVtools.Core/Operations/OperationResize.cs +++ b/UVtools.Core/Operations/OperationResize.cs @@ -51,7 +51,7 @@ namespace UVtools.Core.Operations get => _x; set { - SetProperty(ref _x, value); + RaiseAndSetIfChanged(ref _x, value); if (_constrainXy) Y = value; } @@ -60,7 +60,7 @@ namespace UVtools.Core.Operations public decimal Y { get => _y; - set => SetProperty(ref _y, value); + set => RaiseAndSetIfChanged(ref _y, value); } public bool ConstrainXY @@ -68,7 +68,7 @@ namespace UVtools.Core.Operations get => _constrainXy; set { - if (!SetProperty(ref _constrainXy, value)) return; + if (!RaiseAndSetIfChanged(ref _constrainXy, value)) return; if (_constrainXy) { Y = _x; @@ -79,7 +79,7 @@ namespace UVtools.Core.Operations public bool IsFade { get => _isFade; - set => SetProperty(ref _isFade, value); + set => RaiseAndSetIfChanged(ref _isFade, value); } diff --git a/UVtools.Core/Operations/OperationRotate.cs b/UVtools.Core/Operations/OperationRotate.cs index c52bacf..e95991f 100644 --- a/UVtools.Core/Operations/OperationRotate.cs +++ b/UVtools.Core/Operations/OperationRotate.cs @@ -28,7 +28,7 @@ namespace UVtools.Core.Operations public decimal AngleDegrees { get => _angleDegrees; - set => SetProperty(ref _angleDegrees, value); + set => RaiseAndSetIfChanged(ref _angleDegrees, value); } } } diff --git a/UVtools.Core/Operations/OperationThreshold.cs b/UVtools.Core/Operations/OperationThreshold.cs index 183bc00..8854ac7 100644 --- a/UVtools.Core/Operations/OperationThreshold.cs +++ b/UVtools.Core/Operations/OperationThreshold.cs @@ -35,19 +35,19 @@ namespace UVtools.Core.Operations public byte Threshold { get => _threshold; - set => SetProperty(ref _threshold, value); + set => RaiseAndSetIfChanged(ref _threshold, value); } public byte Maximum { get => _maximum; - set => SetProperty(ref _maximum, value); + set => RaiseAndSetIfChanged(ref _maximum, value); } public ThresholdType Type { get => _type; - set => SetProperty(ref _type, value); + set => RaiseAndSetIfChanged(ref _type, value); } public static Array ThresholdTypes => Enum.GetValues(typeof(ThresholdType)); diff --git a/UVtools.GUI/Program.cs b/UVtools.GUI/Program.cs index ed723a1..cf00d74 100644 --- a/UVtools.GUI/Program.cs +++ b/UVtools.GUI/Program.cs @@ -79,7 +79,8 @@ namespace UVtools.GUI static void Main(string[] args) { Args = args; - Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture("en-GB"); + CultureInfo.DefaultThreadCurrentCulture = CultureInfo.InvariantCulture; + CultureInfo.DefaultThreadCurrentUICulture = CultureInfo.InvariantCulture; Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); diff --git a/UVtools.WPF/App.axaml.cs b/UVtools.WPF/App.axaml.cs index 4c01abb..7faf6d8 100644 --- a/UVtools.WPF/App.axaml.cs +++ b/UVtools.WPF/App.axaml.cs @@ -39,7 +39,9 @@ namespace UVtools.WPF { if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) { - Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture("en-GB"); + CultureInfo.DefaultThreadCurrentCulture = CultureInfo.InvariantCulture; + CultureInfo.DefaultThreadCurrentUICulture = CultureInfo.InvariantCulture; + UserSettings.Load(); UserSettings.SetVersion(); diff --git a/UVtools.WPF/Controls/AdvancedImageBox.cs b/UVtools.WPF/Controls/AdvancedImageBox.cs index 5b785da..80cb86f 100644 --- a/UVtools.WPF/Controls/AdvancedImageBox.cs +++ b/UVtools.WPF/Controls/AdvancedImageBox.cs @@ -30,40 +30,25 @@ namespace UVtools.WPF.Controls /// /// Multicast event for property change notifications. /// - public event PropertyChangedEventHandler ImageBoxPropertyChanged; + private PropertyChangedEventHandler _propertyChanged; + private List events = new List(); - /// - /// Checks if a property already matches a desired value. Sets the property and - /// notifies listeners only when necessary. - /// - /// Type of the property. - /// Reference to a property with both getter and setter. - /// Desired value for the property. - /// - /// Name of the property used to notify listeners. This - /// value is optional and can be provided automatically when invoked from compilers that - /// support CallerMemberName. - /// - /// - /// True if the value was changed, false if the existing value matched the - /// desired value. - /// - protected bool SetProperty(ref T storage, T value, [CallerMemberName] string propertyName = null) + public event PropertyChangedEventHandler PropertyChanged { - if (Equals(storage, value)) - { - return false; - } - - storage = value; - OnPropertyChanged(propertyName); + add { _propertyChanged += value; events.Add("added"); } + remove { _propertyChanged -= value; events.Add("removed"); } + } + protected bool RaiseAndSetIfChanged(ref T field, T value, [CallerMemberName] string propertyName = null) + { + if (EqualityComparer.Default.Equals(field, value)) return false; + field = value; + RaisePropertyChanged(propertyName); return true; } - protected bool SetProperty([CallerMemberName] string propertyName = null) + + protected virtual void OnPropertyChanged(PropertyChangedEventArgs e) { - OnPropertyChanged(propertyName); - return true; } /// @@ -74,10 +59,11 @@ namespace UVtools.WPF.Controls /// value is optional and can be provided automatically when invoked from compilers /// that support . /// - protected void OnPropertyChanged([CallerMemberName] string propertyName = null) + protected void RaisePropertyChanged([CallerMemberName] string propertyName = null) { - var eventHandler = ImageBoxPropertyChanged; - eventHandler?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + var e = new PropertyChangedEventArgs(propertyName); + OnPropertyChanged(e); + _propertyChanged?.Invoke(this, e); } #endregion @@ -443,7 +429,7 @@ namespace UVtools.WPF.Controls public byte GridCellSize { get => _gridCellSize; - set => SetProperty(ref _gridCellSize, value); + set => RaiseAndSetIfChanged(ref _gridCellSize, value); } /// @@ -452,7 +438,7 @@ namespace UVtools.WPF.Controls public ISolidColorBrush GridColor { get => _gridColor; - set => SetProperty(ref _gridColor, value); + set => RaiseAndSetIfChanged(ref _gridColor, value); } /// @@ -461,7 +447,7 @@ namespace UVtools.WPF.Controls public ISolidColorBrush GridColorAlternate { get => _gridColorAlternate; - set => SetProperty(ref _gridColorAlternate, value); + set => RaiseAndSetIfChanged(ref _gridColorAlternate, value); } /// @@ -472,7 +458,7 @@ namespace UVtools.WPF.Controls get => _image; set { - if (!SetProperty(ref _image, value)) return; + if (!RaiseAndSetIfChanged(ref _image, value)) return; if (_image is null) { SizedContainer.Width = 0; @@ -513,7 +499,7 @@ namespace UVtools.WPF.Controls public bool ShowGrid { get => _showGrid; - set => SetProperty(ref _showGrid, value); + set => RaiseAndSetIfChanged(ref _showGrid, value); } public bool IsPanning @@ -521,7 +507,7 @@ namespace UVtools.WPF.Controls get => _isPanning; protected set { - if (!SetProperty(ref _isPanning, value)) return; + if (!RaiseAndSetIfChanged(ref _isPanning, value)) return; _startScrollPosition = Offset; if (value) @@ -549,44 +535,44 @@ namespace UVtools.WPF.Controls public bool AutoPan { get => _autoPan; - set => SetProperty(ref _autoPan, value); + set => RaiseAndSetIfChanged(ref _autoPan, value); } public PanMouseButtons PanWithMouseButtons { get => _panWithMouseButtons; - set => SetProperty(ref _panWithMouseButtons, value); + set => RaiseAndSetIfChanged(ref _panWithMouseButtons, value); } public bool PanWithArrows { get => _panWithArrows; - set => SetProperty(ref _panWithArrows, value); + set => RaiseAndSetIfChanged(ref _panWithArrows, value); } public bool InvertMouse { get => _invertMouse; - set => SetProperty(ref _invertMouse, value); + set => RaiseAndSetIfChanged(ref _invertMouse, value); } public bool AutoCenter { get => _autoCenter; - set => SetProperty(ref _autoCenter, value); + set => RaiseAndSetIfChanged(ref _autoCenter, value); } public SizeModes SizeMode { get => _sizeMode; - set => SetProperty(ref _sizeMode, value); + set => RaiseAndSetIfChanged(ref _sizeMode, value); } private bool _allowZoom = true; public virtual bool AllowZoom { get => _allowZoom; - set => SetProperty(ref _allowZoom, value); + set => RaiseAndSetIfChanged(ref _allowZoom, value); } ZoomLevelCollection _zoomLevels = ZoomLevelCollection.Default; @@ -597,7 +583,7 @@ namespace UVtools.WPF.Controls public virtual ZoomLevelCollection ZoomLevels { get => _zoomLevels; - set => SetProperty(ref _zoomLevels, value); + set => RaiseAndSetIfChanged(ref _zoomLevels, value); } private int _zoom = 100; @@ -621,7 +607,7 @@ namespace UVtools.WPF.Controls public virtual ISolidColorBrush PixelGridColor { get => _pixelGridColor; - set => SetProperty(ref _pixelGridColor, value); + set => RaiseAndSetIfChanged(ref _pixelGridColor, value); } private int _pixelGridThreshold = 5; @@ -633,13 +619,13 @@ namespace UVtools.WPF.Controls public virtual int PixelGridThreshold { get => _pixelGridThreshold; - set => SetProperty(ref _pixelGridThreshold, value); + set => RaiseAndSetIfChanged(ref _pixelGridThreshold, value); } public Rect SelectionRegion { get => _selectionRegion; - set => SetProperty(ref _selectionRegion, value); + set => RaiseAndSetIfChanged(ref _selectionRegion, value); } @@ -687,7 +673,7 @@ namespace UVtools.WPF.Controls //Container.PointerPressed += ScrollViewerOnPointerPressed; //Container.PointerReleased += ScrollViewerOnPointerReleased; - PropertyChanged += EventOnPropertyChanged; + base.PropertyChanged += EventOnPropertyChanged; } private void FillContainerOnPointerWheelChanged(object? sender, PointerWheelEventArgs e) @@ -935,7 +921,7 @@ namespace UVtools.WPF.Controls InvalidateArrange(); } - OnPropertyChanged(nameof(Zoom)); + RaisePropertyChanged(nameof(Zoom)); //this.OnZoomChanged(EventArgs.Empty); //this.OnZoomed(new ImageBoxZoomEventArgs(actions, source, previousZoom, this.Zoom)); } diff --git a/UVtools.WPF/Controls/Tools/ToolChangeResolutionControl.axaml.cs b/UVtools.WPF/Controls/Tools/ToolChangeResolutionControl.axaml.cs index 97260e8..6254a2b 100644 --- a/UVtools.WPF/Controls/Tools/ToolChangeResolutionControl.axaml.cs +++ b/UVtools.WPF/Controls/Tools/ToolChangeResolutionControl.axaml.cs @@ -14,7 +14,7 @@ namespace UVtools.WPF.Controls.Tools get => _selectedPresetItem; set { - SetProperty(ref _selectedPresetItem, value); + RaiseAndSetIfChanged(ref _selectedPresetItem, value); if (_selectedPresetItem is null || _selectedPresetItem.IsEmpty) return; Operation.NewResolutionX = _selectedPresetItem.ResolutionX; Operation.NewResolutionY = _selectedPresetItem.ResolutionY; diff --git a/UVtools.WPF/Controls/Tools/ToolControl.axaml.cs b/UVtools.WPF/Controls/Tools/ToolControl.axaml.cs index 799c071..4a3cfa8 100644 --- a/UVtools.WPF/Controls/Tools/ToolControl.axaml.cs +++ b/UVtools.WPF/Controls/Tools/ToolControl.axaml.cs @@ -1,4 +1,5 @@ -using System.ComponentModel; +using System.Collections.Generic; +using System.ComponentModel; using System.Runtime.CompilerServices; using Avalonia.Controls; using Avalonia.Markup.Xaml; @@ -15,36 +16,27 @@ namespace UVtools.WPF.Controls.Tools /// /// Multicast event for property change notifications. /// - public event PropertyChangedEventHandler PropertyChanged; + private PropertyChangedEventHandler _propertyChanged; + private List events = new List(); - /// - /// Checks if a property already matches a desired value. Sets the property and - /// notifies listeners only when necessary. - /// - /// Type of the property. - /// Reference to a property with both getter and setter. - /// Desired value for the property. - /// - /// Name of the property used to notify listeners. This - /// value is optional and can be provided automatically when invoked from compilers that - /// support CallerMemberName. - /// - /// - /// True if the value was changed, false if the existing value matched the - /// desired value. - /// - protected bool SetProperty(ref T storage, T value, [CallerMemberName] string propertyName = null) + public event PropertyChangedEventHandler PropertyChanged { - if (Equals(storage, value)) - { - return false; - } + add { _propertyChanged += value; events.Add("added"); } + remove { _propertyChanged -= value; events.Add("removed"); } + } - storage = value; - OnPropertyChanged(propertyName); + protected bool RaiseAndSetIfChanged(ref T field, T value, [CallerMemberName] string propertyName = null) + { + if (EqualityComparer.Default.Equals(field, value)) return false; + field = value; + RaisePropertyChanged(propertyName); return true; } + protected virtual void OnPropertyChanged(PropertyChangedEventArgs e) + { + } + /// /// Notifies listeners that a property value has changed. /// @@ -53,10 +45,11 @@ namespace UVtools.WPF.Controls.Tools /// value is optional and can be provided automatically when invoked from compilers /// that support . /// - protected void OnPropertyChanged([CallerMemberName] string propertyName = null) + protected void RaisePropertyChanged([CallerMemberName] string propertyName = null) { - var eventHandler = PropertyChanged; - eventHandler?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + var e = new PropertyChangedEventArgs(propertyName); + OnPropertyChanged(e); + _propertyChanged?.Invoke(this, e); } #endregion diff --git a/UVtools.WPF/Controls/Tools/ToolThresholdControl.axaml.cs b/UVtools.WPF/Controls/Tools/ToolThresholdControl.axaml.cs index 6776c84..7d5b9cb 100644 --- a/UVtools.WPF/Controls/Tools/ToolThresholdControl.axaml.cs +++ b/UVtools.WPF/Controls/Tools/ToolThresholdControl.axaml.cs @@ -22,19 +22,19 @@ namespace UVtools.WPF.Controls.Tools public bool IsThresholdEnabled { get => _isThresholdEnabled; - set => SetProperty(ref _isThresholdEnabled, value); + set => RaiseAndSetIfChanged(ref _isThresholdEnabled, value); } public bool IsMaximumEnabled { get => _isMaximumEnabled; - set => SetProperty(ref _isMaximumEnabled, value); + set => RaiseAndSetIfChanged(ref _isMaximumEnabled, value); } public bool IsTypeEnabled { get => _isTypeEnabled; - set => SetProperty(ref _isTypeEnabled, value); + set => RaiseAndSetIfChanged(ref _isTypeEnabled, value); } public int SelectedPresetIndex @@ -42,7 +42,7 @@ namespace UVtools.WPF.Controls.Tools get => _selectedPresetIndex; set { - if (!SetProperty(ref _selectedPresetIndex, value)) return; + if (!RaiseAndSetIfChanged(ref _selectedPresetIndex, value)) return; switch (_selectedPresetIndex) { diff --git a/UVtools.WPF/Controls/WindowEx.cs b/UVtools.WPF/Controls/WindowEx.cs index 25b7ed8..f3b062d 100644 --- a/UVtools.WPF/Controls/WindowEx.cs +++ b/UVtools.WPF/Controls/WindowEx.cs @@ -6,6 +6,7 @@ * of this license document, but changing it is not allowed. */ +using System.Collections.Generic; using System.ComponentModel; using System.Runtime.CompilerServices; using System.Threading.Tasks; @@ -19,36 +20,28 @@ namespace UVtools.WPF.Controls /// /// Multicast event for property change notifications. /// - public event PropertyChangedEventHandler PropertyChanged; + private PropertyChangedEventHandler _propertyChanged; + private List events = new List(); - /// - /// Checks if a property already matches a desired value. Sets the property and - /// notifies listeners only when necessary. - /// - /// Type of the property. - /// Reference to a property with both getter and setter. - /// Desired value for the property. - /// - /// Name of the property used to notify listeners. This - /// value is optional and can be provided automatically when invoked from compilers that - /// support CallerMemberName. - /// - /// - /// True if the value was changed, false if the existing value matched the - /// desired value. - /// - protected bool SetProperty(ref T storage, T value, [CallerMemberName] string propertyName = null) + public event PropertyChangedEventHandler PropertyChanged { - if (Equals(storage, value)) - { - return false; - } + add { _propertyChanged += value; events.Add("added"); } + remove { _propertyChanged -= value; events.Add("removed"); } + } - storage = value; - OnPropertyChanged(propertyName); + protected bool RaiseAndSetIfChanged(ref T field, T value, [CallerMemberName] string propertyName = null) + { + if (EqualityComparer.Default.Equals(field, value)) return false; + field = value; + RaisePropertyChanged(propertyName); return true; } + + protected virtual void OnPropertyChanged(PropertyChangedEventArgs e) + { + } + /// /// Notifies listeners that a property value has changed. /// @@ -57,10 +50,11 @@ namespace UVtools.WPF.Controls /// value is optional and can be provided automatically when invoked from compilers /// that support . /// - protected void OnPropertyChanged([CallerMemberName] string propertyName = null) + protected void RaisePropertyChanged([CallerMemberName] string propertyName = null) { - var eventHandler = PropertyChanged; - eventHandler?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + var e = new PropertyChangedEventArgs(propertyName); + OnPropertyChanged(e); + _propertyChanged?.Invoke(this, e); } #endregion diff --git a/UVtools.WPF/MainWindow.axaml.cs b/UVtools.WPF/MainWindow.axaml.cs index af4f9b5..493c684 100644 --- a/UVtools.WPF/MainWindow.axaml.cs +++ b/UVtools.WPF/MainWindow.axaml.cs @@ -226,7 +226,7 @@ namespace UVtools.WPF public ObservableCollection Issues { get => _issues; - private set => SetProperty(ref _issues, value); + private set => RaiseAndSetIfChanged(ref _issues, value); } public ObservableCollection Drawings { get; } = new ObservableCollection(); @@ -268,7 +268,7 @@ namespace UVtools.WPF get => _isGUIEnabled; set { - if (!SetProperty(ref _isGUIEnabled, value)) return; + if (!RaiseAndSetIfChanged(ref _isGUIEnabled, value)) return; if (!_isGUIEnabled) { ProgressWindow = new ProgressWindow(); @@ -301,32 +301,32 @@ namespace UVtools.WPF public bool IsFileLoaded { get => !(SlicerFile is null); - set => OnPropertyChanged(); + set => RaisePropertyChanged(); } public int TabSelectedIndex { get => _tabSelectedIndex; - set => SetProperty(ref _tabSelectedIndex, value); + set => RaiseAndSetIfChanged(ref _tabSelectedIndex, value); } #endregion public uint SavesCount { get => _savesCount; - set => SetProperty(ref _savesCount, value); + set => RaiseAndSetIfChanged(ref _savesCount, value); } public bool CanSave { get => IsFileLoaded && _canSave; - set => SetProperty(ref _canSave, value); + set => RaiseAndSetIfChanged(ref _canSave, value); } public MenuItem[] MenuFileConvertItems { get => _menuFileConvertItems; - set => SetProperty(ref _menuFileConvertItems, value); + set => RaiseAndSetIfChanged(ref _menuFileConvertItems, value); } @@ -338,9 +338,9 @@ namespace UVtools.WPF { if (value == 0) { - SetProperty(ref _visibleThumbnailIndex, value); - OnPropertyChanged(nameof(ThumbnailCanGoPrevious)); - OnPropertyChanged(nameof(ThumbnailCanGoNext)); + RaiseAndSetIfChanged(ref _visibleThumbnailIndex, value); + RaisePropertyChanged(nameof(ThumbnailCanGoPrevious)); + RaisePropertyChanged(nameof(ThumbnailCanGoNext)); VisibleThumbnailImage = null; return; } @@ -349,11 +349,11 @@ namespace UVtools.WPF var index = value-1; if (index >= SlicerFile.CreatedThumbnailsCount) return; if (SlicerFile.Thumbnails[index] is null) return; - if (!SetProperty(ref _visibleThumbnailIndex, value)) return; + if (!RaiseAndSetIfChanged(ref _visibleThumbnailIndex, value)) return; VisibleThumbnailImage = SlicerFile.Thumbnails[index].ToBitmap(); - OnPropertyChanged(nameof(ThumbnailCanGoPrevious)); - OnPropertyChanged(nameof(ThumbnailCanGoNext)); + RaisePropertyChanged(nameof(ThumbnailCanGoPrevious)); + RaisePropertyChanged(nameof(ThumbnailCanGoNext)); } } @@ -377,8 +377,8 @@ namespace UVtools.WPF get => _visibleThumbnailImage; set { - SetProperty(ref _visibleThumbnailImage, value); - OnPropertyChanged(nameof(VisibleThumbnailResolution)); + RaiseAndSetIfChanged(ref _visibleThumbnailImage, value); + RaisePropertyChanged(nameof(VisibleThumbnailResolution)); } } @@ -509,8 +509,8 @@ namespace UVtools.WPF { if (!HaveGCode) return; SlicerFile.RebuildGCode(); - OnPropertyChanged(nameof(GCodeLines)); - OnPropertyChanged(nameof(GCodeStr)); + RaisePropertyChanged(nameof(GCodeLines)); + RaisePropertyChanged(nameof(GCodeStr)); } public async void OnClickGCodeSaveFile() @@ -790,10 +790,10 @@ namespace UVtools.WPF get => _issueSelectedIndex; set { - if (!SetProperty(ref _issueSelectedIndex, value)) return; - OnPropertyChanged(nameof(IssueSelectedIndexStr)); - OnPropertyChanged(nameof(IssueCanGoPrevious)); - OnPropertyChanged(nameof(IssueCanGoNext)); + if (!RaiseAndSetIfChanged(ref _issueSelectedIndex, value)) return; + RaisePropertyChanged(nameof(IssueSelectedIndexStr)); + RaisePropertyChanged(nameof(IssueCanGoPrevious)); + RaisePropertyChanged(nameof(IssueCanGoNext)); IssuesGridOnSelectionChanged(); } } @@ -905,9 +905,9 @@ namespace UVtools.WPF if (resultIssues is null) return; Issues.AddRange(resultIssues); - OnPropertyChanged(nameof(IssueSelectedIndexStr)); - OnPropertyChanged(nameof(IssueCanGoPrevious)); - OnPropertyChanged(nameof(IssueCanGoNext)); + RaisePropertyChanged(nameof(IssueSelectedIndexStr)); + RaisePropertyChanged(nameof(IssueCanGoPrevious)); + RaisePropertyChanged(nameof(IssueCanGoNext)); } @@ -952,7 +952,7 @@ namespace UVtools.WPF public bool IsVerbose { get => _isVerbose; - set => SetProperty(ref _isVerbose, value); + set => RaiseAndSetIfChanged(ref _isVerbose, value); } public void AddLog(LogItem log) @@ -980,7 +980,7 @@ namespace UVtools.WPF get => _showLayerImageRotated; set { - if (SetProperty(ref _showLayerImageRotated, value)) + if (RaiseAndSetIfChanged(ref _showLayerImageRotated, value)) { ShowLayer(); } @@ -992,7 +992,7 @@ namespace UVtools.WPF get => _showLayerImageDifference; set { - if (SetProperty(ref _showLayerImageDifference, value)) + if (RaiseAndSetIfChanged(ref _showLayerImageDifference, value)) { ShowLayer(); } @@ -1004,7 +1004,7 @@ namespace UVtools.WPF get => _showLayerImageIssues; set { - if (SetProperty(ref _showLayerImageIssues, value)) + if (RaiseAndSetIfChanged(ref _showLayerImageIssues, value)) { ShowLayer(); } @@ -1016,7 +1016,7 @@ namespace UVtools.WPF get => _showLayerImageCrosshairs; set { - if (SetProperty(ref _showLayerImageCrosshairs, value)) + if (RaiseAndSetIfChanged(ref _showLayerImageCrosshairs, value)) { ShowLayer(); } @@ -1028,7 +1028,7 @@ namespace UVtools.WPF get => _showLayerOutlinePrintVolumeBoundary; set { - if (SetProperty(ref _showLayerOutlinePrintVolumeBoundary, value)) + if (RaiseAndSetIfChanged(ref _showLayerOutlinePrintVolumeBoundary, value)) { ShowLayer(); } @@ -1040,7 +1040,7 @@ namespace UVtools.WPF get => _showLayerOutlineLayerBoundary; set { - if (SetProperty(ref _showLayerOutlineLayerBoundary, value)) + if (RaiseAndSetIfChanged(ref _showLayerOutlineLayerBoundary, value)) { ShowLayer(); } @@ -1052,7 +1052,7 @@ namespace UVtools.WPF get => _showLayerOutlineHollowAreas; set { - if (SetProperty(ref _showLayerOutlineHollowAreas, value)) + if (RaiseAndSetIfChanged(ref _showLayerOutlineHollowAreas, value)) { ShowLayer(); } @@ -1064,7 +1064,7 @@ namespace UVtools.WPF get => _showLayerOutlineEdgeDetection; set { - if (SetProperty(ref _showLayerOutlineEdgeDetection, value)) + if (RaiseAndSetIfChanged(ref _showLayerOutlineEdgeDetection, value)) { ShowLayer(); } @@ -1074,7 +1074,7 @@ namespace UVtools.WPF public bool IsPixelEditorActive { get => _isPixelEditorActive; - set => SetProperty(ref _isPixelEditorActive, value); + set => RaiseAndSetIfChanged(ref _isPixelEditorActive, value); } public string MinimumLayerString => SlicerFile is null ? "???" : $"{SlicerFile.LayerHeight}mm\n0"; @@ -1104,7 +1104,7 @@ namespace UVtools.WPF public long ShowLayerRenderMs { get => _showLayerRenderMs; - set => SetProperty(ref _showLayerRenderMs, value); + set => RaiseAndSetIfChanged(ref _showLayerRenderMs, value); } public PixelPicker LayerPixelPicker { get; } = new PixelPicker(); @@ -1118,7 +1118,7 @@ namespace UVtools.WPF get => _actualLayer; set { - if (!SetProperty(ref _actualLayer, value)) return; + if (!RaiseAndSetIfChanged(ref _actualLayer, value)) return; ShowLayer(); InvalidateLayerNavigation(); } @@ -1129,17 +1129,17 @@ namespace UVtools.WPF _actualLayer = layerIndex; ShowLayer(); InvalidateLayerNavigation(); - OnPropertyChanged(nameof(ActualLayer)); + RaisePropertyChanged(nameof(ActualLayer)); } public void InvalidateLayerNavigation() { - OnPropertyChanged(nameof(CanGoDown)); - OnPropertyChanged(nameof(CanGoUp)); - OnPropertyChanged(nameof(ActualLayerTooltip)); - OnPropertyChanged(nameof(LayerNavigationTooltipMargin)); - OnPropertyChanged(nameof(LayerPixelCountStr)); - OnPropertyChanged(nameof(LayerBoundsStr)); + RaisePropertyChanged(nameof(CanGoDown)); + RaisePropertyChanged(nameof(CanGoUp)); + RaisePropertyChanged(nameof(ActualLayerTooltip)); + RaisePropertyChanged(nameof(LayerNavigationTooltipMargin)); + RaisePropertyChanged(nameof(LayerPixelCountStr)); + RaisePropertyChanged(nameof(LayerBoundsStr)); } public Thickness LayerNavigationTooltipMargin diff --git a/UVtools.WPF/Structures/LogItem.cs b/UVtools.WPF/Structures/LogItem.cs index 4dc6872..afd192b 100644 --- a/UVtools.WPF/Structures/LogItem.cs +++ b/UVtools.WPF/Structures/LogItem.cs @@ -21,25 +21,25 @@ namespace UVtools.WPF.Structures public int Index { get => _index; - set => SetProperty(ref _index, value); + set => RaiseAndSetIfChanged(ref _index, value); } public string StartTime { get => _startTime; - set => SetProperty(ref _startTime, value); + set => RaiseAndSetIfChanged(ref _startTime, value); } public double ElapsedTime { get => _elapsedTime; - set => SetProperty(ref _elapsedTime, Math.Round(value, 2)); + set => RaiseAndSetIfChanged(ref _elapsedTime, Math.Round(value, 2)); } public string Description { get => _description; - set => SetProperty(ref _description, value); + set => RaiseAndSetIfChanged(ref _description, value); } public LogItem(int index, string description, double elapsedTime = 0) diff --git a/UVtools.WPF/UserSettings.cs b/UVtools.WPF/UserSettings.cs index a68a1c9..4ada331 100644 --- a/UVtools.WPF/UserSettings.cs +++ b/UVtools.WPF/UserSettings.cs @@ -13,7 +13,6 @@ using System.Xml.Serialization; using Avalonia.Media; using JetBrains.Annotations; using ReactiveUI; -using UVtools.WPF.Extensions; using Color=UVtools.WPF.Structures.Color; namespace UVtools.WPF @@ -21,6 +20,10 @@ namespace UVtools.WPF [Serializable] public sealed class UserSettings : ReactiveObject { + #region Constants + public const ushort SETTINGS_VERSION = 1; + #endregion + #region Sub classes [Serializable] public sealed class GeneralUserSettings : ReactiveObject @@ -35,6 +38,7 @@ namespace UVtools.WPF private bool _promptOverwriteFileSave = true; private string _fileSaveNamePrefix; private string _fileSaveNameSuffix = "_copy"; + private int _maxDegreeOfParallelism; public bool StartMaximized { @@ -96,6 +100,20 @@ namespace UVtools.WPF set => this.RaiseAndSetIfChanged(ref _fileSaveNameSuffix, value); } + /// + /// Gets or sets the maximum number of concurrent tasks enabled by a ParallelOptions instance. + /// + public int MaxDegreeOfParallelism + { + get => _maxDegreeOfParallelism; + set => this.RaiseAndSetIfChanged(ref _maxDegreeOfParallelism, value); + } + + public GeneralUserSettings() + { + MaxDegreeOfParallelism = Environment.ProcessorCount; + } + public GeneralUserSettings Clone() { return MemberwiseClone() as GeneralUserSettings; @@ -836,11 +854,12 @@ namespace UVtools.WPF private IssuesUserSettings _issues; private PixelEditorUserSettings _pixelEditor; private LayerRepairUserSettings _layerRepair; - private string _version; + private ushort _settingsVersion = SETTINGS_VERSION; + private string _appVersion; private uint _savesCount; private DateTime _modifiedDateTime; - + public GeneralUserSettings General { get => _general ??= new GeneralUserSettings(); @@ -882,14 +901,20 @@ namespace UVtools.WPF public uint ResetCount { get; set; } */ + public ushort SettingsVersion + { + get => _settingsVersion; + set => this.RaiseAndSetIfChanged(ref _settingsVersion, value); + } + /// /// Gets or sets the last running version of UVtools with these settings /// [NotNull] - public string Version + public string AppVersion { - get => _version ??= AppSettings.Version.ToString(); - set => this.RaiseAndSetIfChanged(ref _version, value); + get => _appVersion ??= AppSettings.Version.ToString(); + set => this.RaiseAndSetIfChanged(ref _appVersion, value); } /// @@ -939,10 +964,21 @@ namespace UVtools.WPF } var serializer = new XmlSerializer(typeof(UserSettings)); - using StreamReader myXmlReader = new StreamReader(FilePath); + using var myXmlReader = new StreamReader(FilePath); try { _instance = (UserSettings)serializer.Deserialize(myXmlReader); + if (_instance.General.MaxDegreeOfParallelism <= 0) + _instance.General.MaxDegreeOfParallelism = Environment.ProcessorCount; + + if (_instance.SettingsVersion < SETTINGS_VERSION) + { + // Upgrade + + _instance.SettingsVersion = SETTINGS_VERSION; + } + + } catch (Exception e) { @@ -960,7 +996,7 @@ namespace UVtools.WPF Instance.SavesCount++; _instance.ModifiedDateTime = DateTime.Now; var serializer = new XmlSerializer(_instance.GetType()); - using StreamWriter myXmlWriter = new StreamWriter(FilePath); + using var myXmlWriter = new StreamWriter(FilePath); try { serializer.Serialize(myXmlWriter, _instance); @@ -973,7 +1009,7 @@ namespace UVtools.WPF public static void SetVersion() { - Instance.Version = AppSettings.Version.ToString(); + Instance.AppVersion = AppSettings.Version.ToString(); } public static object[] PackObjects => @@ -987,6 +1023,8 @@ namespace UVtools.WPF }; #endregion + #region Methods + public UserSettings Clone() { var clone = MemberwiseClone() as UserSettings; @@ -997,5 +1035,7 @@ namespace UVtools.WPF clone.LayerRepair = clone.LayerRepair.Clone(); return clone; } + + #endregion } } diff --git a/UVtools.WPF/Windows/ProgressWindow.axaml.cs b/UVtools.WPF/Windows/ProgressWindow.axaml.cs index f492c79..2b6ae99 100644 --- a/UVtools.WPF/Windows/ProgressWindow.axaml.cs +++ b/UVtools.WPF/Windows/ProgressWindow.axaml.cs @@ -33,7 +33,7 @@ namespace UVtools.WPF.Windows set { Progress.CanCancel = value; - OnPropertyChanged(); + RaisePropertyChanged(); } } @@ -69,7 +69,7 @@ namespace UVtools.WPF.Windows { if (!CanCancel) return; DialogResult = DialogResults.Cancel; - OnPropertyChanged(nameof(CanCancel)); + RaisePropertyChanged(nameof(CanCancel)); Progress.TokenSource.Cancel(); } diff --git a/UVtools.WPF/Windows/ToolWindow.axaml.cs b/UVtools.WPF/Windows/ToolWindow.axaml.cs index f87d0a9..d88bc18 100644 --- a/UVtools.WPF/Windows/ToolWindow.axaml.cs +++ b/UVtools.WPF/Windows/ToolWindow.axaml.cs @@ -38,13 +38,13 @@ namespace UVtools.WPF.Windows public string Description { get => _description; - set => SetProperty(ref _description, value); + set => RaiseAndSetIfChanged(ref _description, value); } public double DescriptionMaxWidth { get => _descriptionMaxWidth; - set => SetProperty(ref _descriptionMaxWidth, value); + set => RaiseAndSetIfChanged(ref _descriptionMaxWidth, value); } #endregion @@ -54,7 +54,7 @@ namespace UVtools.WPF.Windows public bool LayerRangeVisible { get => _layerRangeVisible; - set => SetProperty(ref _layerRangeVisible, value); + set => RaiseAndSetIfChanged(ref _layerRangeVisible, value); } public uint LayerIndexStart @@ -65,9 +65,9 @@ namespace UVtools.WPF.Windows if (!(ToolControl?.BaseOperation is null)) ToolControl.BaseOperation.LayerIndexStart = value; - if (!SetProperty(ref _layerIndexStart, value)) return; - OnPropertyChanged(nameof(LayerStartMM)); - OnPropertyChanged(nameof(LayerRangeCountStr)); + if (!RaiseAndSetIfChanged(ref _layerIndexStart, value)) return; + RaisePropertyChanged(nameof(LayerStartMM)); + RaisePropertyChanged(nameof(LayerRangeCountStr)); } } @@ -81,9 +81,9 @@ namespace UVtools.WPF.Windows if (!(ToolControl?.BaseOperation is null)) ToolControl.BaseOperation.LayerIndexEnd = value; - if (!SetProperty(ref _layerIndexEnd, value)) return; - OnPropertyChanged(nameof(LayerEndMM)); - OnPropertyChanged(nameof(LayerRangeCountStr)); + if (!RaiseAndSetIfChanged(ref _layerIndexEnd, value)) return; + RaisePropertyChanged(nameof(LayerEndMM)); + RaisePropertyChanged(nameof(LayerRangeCountStr)); } } @@ -140,19 +140,19 @@ namespace UVtools.WPF.Windows public bool IsROIVisible { get => ToolControl?.BaseOperation.HaveROI ?? _isROIVisible; - set => SetProperty(ref _isROIVisible, value); + set => RaiseAndSetIfChanged(ref _isROIVisible, value); } public Rect ROI { get => _roi; - set => SetProperty(ref _roi, value); + set => RaiseAndSetIfChanged(ref _roi, value); } public bool ClearROIAfterOperation { get => _clearRoiAfterOperation; - set => SetProperty(ref _clearRoiAfterOperation, value); + set => RaiseAndSetIfChanged(ref _clearRoiAfterOperation, value); } public async void ClearROI() @@ -174,7 +174,7 @@ namespace UVtools.WPF.Windows public IControl ContentControl { get => _contentControl; - set => SetProperty(ref _contentControl, value); + set => RaiseAndSetIfChanged(ref _contentControl, value); } #endregion @@ -184,13 +184,13 @@ namespace UVtools.WPF.Windows public bool ButtonOkEnabled { get => _buttonOkEnabled; - set => SetProperty(ref _buttonOkEnabled, value); + set => RaiseAndSetIfChanged(ref _buttonOkEnabled, value); } public string ButtonOkText { get => _buttonOkText; - set => SetProperty(ref _buttonOkText, value); + set => RaiseAndSetIfChanged(ref _buttonOkText, value); } #endregion @@ -219,7 +219,7 @@ namespace UVtools.WPF.Windows ContentControl = toolControl; ButtonOkText = toolControl.BaseOperation.ButtonOkText; - OnPropertyChanged(nameof(IsContentVisible)); + RaisePropertyChanged(nameof(IsContentVisible)); switch (toolControl.BaseOperation.LayerRangeSelection) {