├── .gitignore
├── Amuse.UI
├── Amuse.UI.csproj
├── Amuse.nsi
├── App.xaml
├── App.xaml.cs
├── AssemblyInfo.cs
├── Behaviors
│ ├── ShiftEnterBehavior.cs
│ ├── SliderMouseWheelBehavior.cs
│ └── SmoothProgressBarBehavior.cs
├── Commands
│ ├── AsyncRelayCommand.cs
│ └── RelayCommand.cs
├── Converters
│ ├── BooleanToHiddenConverter.cs
│ ├── ComboBoxAllItemConverter.cs
│ ├── DiffuserVisibilityConverter.cs
│ ├── EnumDescriptionConverter.cs
│ ├── InverseBoolConverter.cs
│ ├── InverseBooleanToHiddenConverter.cs
│ ├── InverseBooleanToVisibilityConverter.cs
│ ├── InverseNullVisibilityConverter.cs
│ ├── NullVisibilityConverter.cs
│ └── PipelineVisibilityConverter.cs
├── Dialogs
│ ├── AddModelDialog.xaml
│ ├── AddModelDialog.xaml.cs
│ ├── AddUpscaleModelDialog.xaml
│ ├── AddUpscaleModelDialog.xaml.cs
│ ├── CropImageDialog.xaml
│ ├── CropImageDialog.xaml.cs
│ ├── MessageDialog.xaml
│ ├── MessageDialog.xaml.cs
│ ├── TextInputDialog.xaml
│ ├── TextInputDialog.xaml.cs
│ ├── UpdateModelDialog.xaml
│ ├── UpdateModelDialog.xaml.cs
│ ├── UpdateModelMetadataDialog.xaml
│ ├── UpdateModelMetadataDialog.xaml.cs
│ ├── UpdateModelSettingsDialog.xaml
│ ├── UpdateModelSettingsDialog.xaml.cs
│ ├── UpdateUpscaleModelDialog.xaml
│ ├── UpdateUpscaleModelDialog.xaml.cs
│ ├── UpdateUpscaleModelSettingsDialog.xaml
│ ├── UpdateUpscaleModelSettingsDialog.xaml.cs
│ ├── ViewModelMetadataDialog.xaml
│ └── ViewModelMetadataDialog.xaml.cs
├── Fonts
│ ├── fa-brands-400.ttf
│ ├── fa-duotone-900.ttf
│ ├── fa-light-300.ttf
│ ├── fa-regular-400.ttf
│ └── fa-solid-900.ttf
├── Helpers
│ └── RepositoryDownloader.cs
├── Images
│ ├── Icon.ico
│ ├── Icon.png
│ ├── Model.png
│ ├── Upscale.png
│ ├── placeholder.png
│ └── placeholder_sm.png
├── MainWindow.xaml
├── MainWindow.xaml.cs
├── Models
│ ├── AmuseSettings.cs
│ ├── BatchOptionsModel.cs
│ ├── ImageInput.cs
│ ├── ImageResult.cs
│ ├── ModelFileViewModel.cs
│ ├── ModelTemplateCategory.cs
│ ├── ModelTemplateViewModel.cs
│ ├── PromptOptionsModel.cs
│ ├── SchedulerOptionsModel.cs
│ ├── StableDiffusionModelSetViewModel.cs
│ ├── StableDiffusionModelTemplate.cs
│ ├── StableDiffusionSchedulerDefaults.cs
│ ├── UpdateModelSetViewModel.cs
│ ├── UpdateUpscaleModelSetViewModel.cs
│ ├── UpscaleInfoModel.cs
│ ├── UpscaleModelSetViewModel.cs
│ ├── UpscaleModelTemplate.cs
│ ├── UpscaleResult.cs
│ └── ValidationResult.cs
├── Services
│ ├── DialogService.cs
│ ├── IDialogService.cs
│ ├── IModelDownloadService.cs
│ ├── IModelFactory.cs
│ ├── ModelDownloadService.cs
│ └── ModelFactory.cs
├── UserControls
│ ├── CachedImage.cs
│ ├── FilePickerTextBox.xaml
│ ├── FilePickerTextBox.xaml.cs
│ ├── FontAwesome.xaml
│ ├── FontAwesome.xaml.cs
│ ├── ImageInputControl.xaml
│ ├── ImageInputControl.xaml.cs
│ ├── ImageResultControl.xaml
│ ├── ImageResultControl.xaml.cs
│ ├── ModelPickerControl.xaml
│ ├── ModelPickerControl.xaml.cs
│ ├── PaintInputControl.xaml
│ ├── PaintInputControl.xaml.cs
│ ├── PromptControl.xaml
│ ├── PromptControl.xaml.cs
│ ├── SchedulerControl.xaml
│ ├── SchedulerControl.xaml.cs
│ ├── UpscalePickerControl.xaml
│ └── UpscalePickerControl.xaml.cs
├── Utils.cs
├── Views
│ ├── INavigatable.cs
│ ├── ImageInpaintView.xaml
│ ├── ImageInpaintView.xaml.cs
│ ├── ImageToImageView.xaml
│ ├── ImageToImageView.xaml.cs
│ ├── LoggerView.xaml
│ ├── LoggerView.xaml.cs
│ ├── ModelSettingsView.xaml
│ ├── ModelSettingsView.xaml.cs
│ ├── PaintToImageView.xaml
│ ├── PaintToImageView.xaml.cs
│ ├── SettingsView.xaml
│ ├── SettingsView.xaml.cs
│ ├── TextToImageView.xaml
│ ├── TextToImageView.xaml.cs
│ ├── UpscaleView.xaml
│ └── UpscaleView.xaml.cs
├── WindowLogger.cs
└── appsettings.json
├── Amuse.sln
├── Assets
├── Amuse-Logo-1024.png
├── Amuse-Logo-128.png
├── Amuse-Logo-2048.png
├── Amuse-Logo-256.png
├── Amuse-Logo-512.png
├── Amuse-Logo-64.png
├── Amuse-Logo.psd
├── Icon-1024.png
├── Icon-128.png
├── Icon-2048.png
├── Icon-256.png
├── Icon-512.png
└── Icon-64.png
├── Docs
├── GettingStarted.md
└── ModelTemplate.md
├── LICENSE
└── README.md
/Amuse.UI/Amuse.UI.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 1.0.0
5 | WinExe
6 | net7.0-windows
7 | disable
8 | true
9 | true
10 | x64
11 | Debug;Release;Debug-DML;Debug-Cuda;Release-DML;Release-Cuda;Debug-TensorRT;Release-TensorRT
12 | Images\Icon.ico
13 | Amuse
14 |
15 |
16 |
17 | True
18 |
19 |
20 |
21 | True
22 |
23 |
24 |
25 | True
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 | PreserveNewest
47 | true
48 | PreserveNewest
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
--------------------------------------------------------------------------------
/Amuse.UI/Amuse.nsi:
--------------------------------------------------------------------------------
1 | ; Amuse.nsi
2 | ;
3 | ; This script is based on Amuse.nsi but it remembers the directory,
4 | ; has uninstall support and (optionally) installs start menu shortcuts.
5 | ;
6 | ; It will install example2.nsi into a directory that the user selects.
7 | ;
8 | ; See install-shared.nsi for a more robust way of checking for administrator rights.
9 | ; See install-per-user.nsi for a file association example.
10 |
11 | ;--------------------------------
12 | !define BUILD_VERSION "v0.1.0"
13 | !define BUILD_NAME "CPU"
14 |
15 | !define BUILD_FOLDER "D:\Build\Amuse"
16 | !define MUI_ICON "${BUILD_FOLDER}\Assets\Icon.ico"
17 | !define MUI_UNICON "${BUILD_FOLDER}\Assets\Icon.ico"
18 |
19 | !include "MUI2.nsh"
20 |
21 | ; The name of the installer
22 | Name "Amuse"
23 |
24 | ; The file to write
25 | OutFile "Amuse_${BUILD_VERSION}_${BUILD_NAME}.exe"
26 |
27 | ; Request application privileges for Windows Vista and higher
28 | RequestExecutionLevel admin
29 |
30 | ; Build Unicode installer
31 | Unicode True
32 |
33 | ; The default installation directory
34 | InstallDir $PROGRAMFILES64\Amuse
35 |
36 | ; Registry key to check for directory (so if you install again, it will
37 | ; overwrite the old one automatically)
38 | InstallDirRegKey HKLM "Software\Amuse" "Install_Dir"
39 |
40 | ;--------------------------------
41 |
42 | ; Pages
43 |
44 | !insertmacro MUI_PAGE_DIRECTORY
45 | !insertmacro MUI_PAGE_INSTFILES
46 |
47 | !insertmacro MUI_LANGUAGE "English"
48 |
49 | UninstPage uninstConfirm
50 | UninstPage instfiles
51 |
52 | ;--------------------------------
53 |
54 | ; The stuff to install
55 | Section "Amuse (required)"
56 |
57 | SectionIn RO
58 |
59 | ; Set output path to the installation directory.
60 | SetOutPath $INSTDIR
61 |
62 | ; Put file there
63 | File "${BUILD_FOLDER}\Amuse_${BUILD_NAME}\*.*"
64 | File "${BUILD_FOLDER}\Amuse_${BUILD_NAME}\runtimes\win-x64\native\*.*"
65 |
66 | ; Write the installation path into the registry
67 | WriteRegStr HKLM SOFTWARE\NSIS_Amuse "Install_Dir" "$INSTDIR"
68 |
69 | ; Write the uninstall keys for Windows
70 | WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Amuse" "DisplayName" "Amuse"
71 | WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Amuse" "UninstallString" '"$INSTDIR\uninstall.exe"'
72 | WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Amuse" "NoModify" 1
73 | WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\EAmuse" "NoRepair" 1
74 | WriteUninstaller "$INSTDIR\uninstall.exe"
75 |
76 | SectionEnd
77 |
78 | ; Optional section (can be disabled by the user)
79 | Section "Start Menu Shortcuts"
80 |
81 | CreateDirectory "$SMPROGRAMS\Amuse"
82 | CreateShortcut "$SMPROGRAMS\Amuse\Uninstall.lnk" "$INSTDIR\uninstall.exe"
83 | CreateShortcut "$SMPROGRAMS\Amuse\Amuse.lnk" "$INSTDIR\Amuse.exe"
84 |
85 | SectionEnd
86 |
87 | ;--------------------------------
88 |
89 | ; Uninstaller
90 |
91 | Section "Uninstall"
92 |
93 | ; Remove registry keys
94 | DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Amuse"
95 | DeleteRegKey HKLM SOFTWARE\Amuse
96 |
97 | ; Remove files and uninstaller
98 | Delete $INSTDIR\*.*
99 | Delete $INSTDIR\uninstall.exe
100 |
101 | ; Remove shortcuts, if any
102 | Delete "$SMPROGRAMS\Amuse\*.lnk"
103 |
104 | ; Remove directories
105 | RMDir "$SMPROGRAMS\Amuse"
106 | RMDir "$INSTDIR"
107 |
108 | SectionEnd
109 |
110 |
--------------------------------------------------------------------------------
/Amuse.UI/App.xaml.cs:
--------------------------------------------------------------------------------
1 | using Amuse.UI.Dialogs;
2 | using Amuse.UI.Models;
3 | using Amuse.UI.Services;
4 | using Microsoft.Extensions.DependencyInjection;
5 | using Microsoft.Extensions.Hosting;
6 | using Microsoft.Extensions.Logging;
7 | using OnnxStack.Core;
8 | using OnnxStack.ImageUpscaler;
9 | using System;
10 | using System.Windows;
11 | using System.Windows.Threading;
12 |
13 | namespace Amuse.UI
14 | {
15 | ///
16 | /// Interaction logic for App.xaml
17 | ///
18 | public partial class App : Application
19 | {
20 | private static IHost _applicationHost;
21 |
22 | public App()
23 | {
24 | var builder = Host.CreateApplicationBuilder();
25 | builder.Logging.ClearProviders();
26 | builder.Services.AddLogging((loggingBuilder) => loggingBuilder.AddWindowLogger());
27 |
28 | // Add OnnxStackStableDiffusion
29 | builder.Services.AddOnnxStackStableDiffusion();
30 | builder.Services.AddOnnxStackImageUpscaler();
31 | builder.Services.AddOnnxStackConfig();
32 |
33 | // Add Windows
34 | builder.Services.AddSingleton();
35 | builder.Services.AddTransient();
36 | builder.Services.AddTransient();
37 | builder.Services.AddTransient();
38 | builder.Services.AddTransient();
39 | builder.Services.AddTransient();
40 | builder.Services.AddTransient();
41 | builder.Services.AddTransient();
42 | builder.Services.AddTransient();
43 | builder.Services.AddTransient();
44 | builder.Services.AddTransient();
45 | builder.Services.AddTransient ();
46 | builder.Services.AddSingleton();
47 | builder.Services.AddSingleton();
48 | builder.Services.AddSingleton();
49 |
50 | // Build App
51 | _applicationHost = builder.Build();
52 | }
53 |
54 |
55 | public static T GetService() => _applicationHost.Services.GetService();
56 |
57 | public static void UIInvoke(Action action, DispatcherPriority priority = DispatcherPriority.Render) => Current.Dispatcher.BeginInvoke(priority, action);
58 |
59 |
60 | ///
61 | /// Raises the event.
62 | ///
63 | /// The instance containing the event data.
64 | protected override async void OnStartup(StartupEventArgs e)
65 | {
66 | base.OnStartup(e);
67 | await _applicationHost.StartAsync();
68 | GetService().Show();
69 | }
70 |
71 |
72 | ///
73 | /// Raises the event.
74 | ///
75 | /// The instance containing the event data.
76 | protected override async void OnExit(ExitEventArgs e)
77 | {
78 | await _applicationHost.StopAsync();
79 | base.OnExit(e);
80 | }
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/Amuse.UI/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Windows;
2 |
3 | [assembly: ThemeInfo(
4 | ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
5 | //(used if a resource is not found in the page,
6 | // or application resource dictionaries)
7 | ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
8 | //(used if a resource is not found in the page,
9 | // app, or any theme specific resource dictionaries)
10 | )]
11 |
--------------------------------------------------------------------------------
/Amuse.UI/Behaviors/ShiftEnterBehavior.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Windows;
3 | using System.Windows.Controls;
4 | using System.Windows.Input;
5 |
6 | namespace Amuse.UI.Behaviors
7 | {
8 | ///
9 | /// Behaviour to use Shift + Enfer to add a new line to a TextBox allowing IsDefault Commands to be fired on Enter
10 | ///
11 | public class ShiftEnterBehavior
12 | {
13 |
14 | ///
15 | /// The enable property
16 | ///
17 | public static readonly DependencyProperty EnableProperty = DependencyProperty.RegisterAttached("Enable", typeof(bool), typeof(ShiftEnterBehavior), new PropertyMetadata(false, OnEnableChanged));
18 |
19 |
20 | ///
21 | /// Gets the enable value.
22 | ///
23 | /// The object.
24 | public static bool GetEnable(DependencyObject obj)
25 | {
26 | return (bool)obj.GetValue(EnableProperty);
27 | }
28 |
29 | ///
30 | /// Sets the enable valse.
31 | ///
32 | /// The object.
33 | /// if set to true [value].
34 | public static void SetEnable(DependencyObject obj, bool value)
35 | {
36 | obj.SetValue(EnableProperty, value);
37 | }
38 |
39 |
40 | ///
41 | /// Called when enable changed.
42 | ///
43 | /// The object.
44 | /// The instance containing the event data.
45 | private static void OnEnableChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
46 | {
47 | if (obj is TextBox textBox)
48 | {
49 | bool attach = (bool)e.NewValue;
50 |
51 | if (attach)
52 | {
53 | textBox.PreviewKeyDown += TextBox_PreviewKeyDown;
54 | }
55 | else
56 | {
57 | textBox.PreviewKeyDown -= TextBox_PreviewKeyDown;
58 | }
59 | }
60 | }
61 |
62 |
63 | ///
64 | /// Handles the PreviewKeyDown event of the TextBox control.
65 | ///
66 | /// The source of the event.
67 | /// The instance containing the event data.
68 | private static void TextBox_PreviewKeyDown(object sender, KeyEventArgs e)
69 | {
70 | if (e.Key == Key.Enter && Keyboard.Modifiers == ModifierKeys.Shift)
71 | {
72 | if (sender is TextBox textBox)
73 | {
74 | e.Handled = true;
75 | textBox.AppendText(Environment.NewLine);
76 | textBox.CaretIndex = textBox.Text.Length;
77 | }
78 | }
79 | }
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/Amuse.UI/Behaviors/SliderMouseWheelBehavior.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Xaml.Behaviors;
2 | using System.Windows.Controls;
3 | using System.Windows.Input;
4 |
5 | namespace Amuse.UI.Behaviors
6 | {
7 | public class SliderMouseWheelBehavior : Behavior
8 | {
9 | ///
10 | /// Handles the PreviewMouseWheel event of the AssociatedObject control.
11 | ///
12 | /// The source of the event.
13 | /// The instance containing the event data.
14 | private void AssociatedObject_PreviewMouseWheel(object sender, MouseWheelEventArgs e)
15 | {
16 | var slider = (Slider)sender;
17 | if (e.Delta > 0)
18 | {
19 | var newValue = slider.Value + slider.TickFrequency;
20 | if (newValue > slider.Maximum)
21 | return;
22 |
23 | slider.Value = newValue;
24 | }
25 | else
26 | {
27 | var newValue = slider.Value - slider.TickFrequency;
28 | if (newValue < slider.Minimum)
29 | return;
30 |
31 | slider.Value = newValue;
32 | }
33 | }
34 |
35 |
36 | ///
37 | /// Called after the behavior is attached to an AssociatedObject.
38 | ///
39 | ///
40 | /// Override this to hook up functionality to the AssociatedObject.
41 | ///
42 | protected override void OnAttached()
43 | {
44 | base.OnAttached();
45 | AssociatedObject.PreviewMouseWheel += AssociatedObject_PreviewMouseWheel;
46 | }
47 |
48 |
49 | ///
50 | /// Called when the behavior is being detached from its AssociatedObject, but before it has actually occurred.
51 | ///
52 | ///
53 | /// Override this to unhook functionality from the AssociatedObject.
54 | ///
55 | protected override void OnDetaching()
56 | {
57 | base.OnDetaching();
58 | AssociatedObject.PreviewMouseWheel -= AssociatedObject_PreviewMouseWheel;
59 | }
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/Amuse.UI/Behaviors/SmoothProgressBarBehavior.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Windows;
3 | using System.Windows.Controls;
4 | using System.Windows.Media.Animation;
5 |
6 | namespace Amuse.UI.Behaviors
7 | {
8 | public class SmoothProgressBarBehavior
9 | {
10 | public static double GetSmoothValue(DependencyObject obj)
11 | {
12 | return (double)obj.GetValue(SmoothValueProperty);
13 | }
14 |
15 | public static void SetSmoothValue(DependencyObject obj, double value)
16 | {
17 | obj.SetValue(SmoothValueProperty, value);
18 | }
19 |
20 | public static readonly DependencyProperty SmoothValueProperty =
21 | DependencyProperty.RegisterAttached("SmoothValue", typeof(double), typeof(SmoothProgressBarBehavior), new PropertyMetadata(0.0, changing));
22 |
23 | private static void changing(DependencyObject d, DependencyPropertyChangedEventArgs e)
24 | {
25 | var anim = new DoubleAnimation((double)e.OldValue, (double)e.NewValue, new TimeSpan(0, 0, 0, 0, 200));
26 | (d as ProgressBar).BeginAnimation(ProgressBar.ValueProperty, anim, HandoffBehavior.Compose);
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/Amuse.UI/Commands/AsyncRelayCommand.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Threading;
3 | using System.Threading.Tasks;
4 | using System.Windows.Input;
5 |
6 | namespace Amuse.UI.Commands
7 | {
8 |
9 | ///
10 | /// Async Relay command implemtation
11 | ///
12 | ///
13 | public class AsyncRelayCommand : ICommand
14 | {
15 | private readonly Func execute;
16 | private readonly Func canExecute;
17 | private long isExecuting;
18 |
19 |
20 | ///
21 | /// Initializes a new instance of the class.
22 | ///
23 | /// The execute.
24 | /// The can execute.
25 | public AsyncRelayCommand(Func execute, Func canExecute = null)
26 | {
27 | this.execute = execute;
28 | this.canExecute = canExecute ?? (() => true);
29 | }
30 |
31 | ///
32 | /// Occurs when changes occur that affect whether or not the command should execute.
33 | ///
34 | public event EventHandler CanExecuteChanged
35 | {
36 | add { CommandManager.RequerySuggested += value; }
37 | remove { CommandManager.RequerySuggested -= value; }
38 | }
39 |
40 | ///
41 | /// Raises the can execute changed.
42 | ///
43 | public void RaiseCanExecuteChanged()
44 | {
45 | CommandManager.InvalidateRequerySuggested();
46 | }
47 |
48 | ///
49 | /// Defines the method that determines whether the command can execute in its current state.
50 | ///
51 | /// Data used by the command. If the command does not require data to be passed, this object can be set to .
52 | ///
53 | /// if this command can be executed; otherwise, .
54 | ///
55 | public bool CanExecute(object parameter)
56 | {
57 | if (Interlocked.Read(ref isExecuting) != 0)
58 | return false;
59 |
60 | return canExecute();
61 | }
62 |
63 |
64 | ///
65 | /// Defines the method to be called when the command is invoked.
66 | ///
67 | /// Data used by the command. If the command does not require data to be passed, this object can be set to .
68 | public async void Execute(object parameter)
69 | {
70 | Interlocked.Exchange(ref isExecuting, 1);
71 | RaiseCanExecuteChanged();
72 |
73 | try
74 | {
75 | await execute();
76 | }
77 | finally
78 | {
79 | Interlocked.Exchange(ref isExecuting, 0);
80 | RaiseCanExecuteChanged();
81 | }
82 | }
83 | }
84 |
85 | ///
86 | /// Async Relay command with type argument implemtation
87 | ///
88 | ///
89 | public class AsyncRelayCommand : ICommand
90 | {
91 | private readonly Func execute;
92 | private readonly Func canExecute;
93 | private long isExecuting;
94 |
95 |
96 | ///
97 | /// Initializes a new instance of the class.
98 | ///
99 | /// The execute.
100 | /// The can execute.
101 | public AsyncRelayCommand(Func execute, Func canExecute = null)
102 | {
103 | this.execute = execute;
104 | this.canExecute = canExecute ?? (o => true);
105 | }
106 |
107 | ///
108 | /// Occurs when changes occur that affect whether or not the command should execute.
109 | ///
110 | public event EventHandler CanExecuteChanged
111 | {
112 | add { CommandManager.RequerySuggested += value; }
113 | remove { CommandManager.RequerySuggested -= value; }
114 | }
115 |
116 | ///
117 | /// Raises the can execute changed.
118 | ///
119 | public void RaiseCanExecuteChanged()
120 | {
121 | CommandManager.InvalidateRequerySuggested();
122 | }
123 |
124 | ///
125 | /// Defines the method that determines whether the command can execute in its current state.
126 | ///
127 | /// Data used by the command. If the command does not require data to be passed, this object can be set to .
128 | ///
129 | /// if this command can be executed; otherwise, .
130 | ///
131 | public bool CanExecute(object parameter)
132 | {
133 | if (Interlocked.Read(ref isExecuting) != 0)
134 | return false;
135 |
136 | return canExecute(parameter is T r ? r : default);
137 | }
138 |
139 | ///
140 | /// Defines the method to be called when the command is invoked.
141 | ///
142 | /// Data used by the command. If the command does not require data to be passed, this object can be set to .
143 | public async void Execute(object parameter)
144 | {
145 | Interlocked.Exchange(ref isExecuting, 1);
146 | RaiseCanExecuteChanged();
147 |
148 | try
149 | {
150 | await execute((T)parameter);
151 | }
152 | finally
153 | {
154 | Interlocked.Exchange(ref isExecuting, 0);
155 | RaiseCanExecuteChanged();
156 | }
157 | }
158 | }
159 | }
160 |
--------------------------------------------------------------------------------
/Amuse.UI/Commands/RelayCommand.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Diagnostics;
3 | using System.Windows.Input;
4 |
5 | namespace Amuse.UI.Commands
6 | {
7 | ///
8 | /// Relay command implemtation
9 | ///
10 | ///
11 | public class RelayCommand : ICommand
12 | {
13 | readonly Action