Skip to content

Commit 22110d6

Browse files
committed
refactor: use async commands
1 parent a05107f commit 22110d6

File tree

8 files changed

+124
-98
lines changed

8 files changed

+124
-98
lines changed

src/IconPacks.Browser/Controls/SideBar.xaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,7 @@
234234
</Style>
235235
</Expander.Resources>
236236
<StackPanel>
237-
<Button Command="{Binding SaveAsSvgCommand}" Content="Save as svg" />
237+
<Button Command="{Binding SaveAsSvgCommand}" Content="Save as Svg" />
238238
<Button Command="{Binding SaveAsWpfCommand}" Content="Save as XAML (WPF)" />
239239
<Button Command="{Binding SaveAsUwpCommand}" Content="Save as XAML (UWP)" />
240240
<Button Command="{Binding SaveAsPngCommand}" Content="Save as Png" />

src/IconPacks.Browser/IconPacks.Browser.csproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,14 @@
1919
</PropertyGroup>
2020

2121
<ItemGroup>
22-
<PackageReference Include="JetBrains.Annotations" Version="2023.3.0" />
22+
<PackageReference Include="JetBrains.Annotations" Version="2024.2.0" />
2323
<PackageReference Include="WpfAnalyzers" Version="4.1.1">
2424
<PrivateAssets>all</PrivateAssets>
2525
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
2626
</PackageReference>
2727
<PackageReference Include="MahApps.Metro.IconPacks" Version="5.0.0" />
2828
<PackageReference Include="MahApps.Metro" Version="2.4.10" />
29-
<PackageReference Include="AsyncAwaitBestPractices" Version="6.0.6" />
29+
<PackageReference Include="AsyncAwaitBestPractices.MVVM" Version="8.0.0" />
3030
<PackageReference Include="Microsoft-WindowsAPICodePack-Shell" Version="1.1.5" />
3131
<PackageReference Include="VirtualizingWrapPanel" Version="2.0.11" />
3232
</ItemGroup>

src/IconPacks.Browser/MainWindow.xaml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,7 @@
195195
<mah:MetroWindow.RightWindowCommands>
196196
<mah:WindowCommands>
197197
<ToggleButton x:Name="ToggleButtonOpenSettings" Content="{iconPacks:Modern Kind=Settings}" />
198-
<Button Command="{x:Static viewModels:MainViewModel.OpenUrlCommand}"
198+
<Button Command="{Binding OpenUrlCommand, Mode=OneWay}"
199199
CommandParameter="https://github.com/MahApps/MahApps.Metro.IconPacks"
200200
Content="{iconPacks:Modern SocialGithubOctocat,
201201
Width=22,
@@ -358,7 +358,7 @@
358358
<Button Style="{StaticResource LinkButtonStyle}"
359359
Margin="0 0 4 0"
360360
VerticalAlignment="Center"
361-
Command="{x:Static viewModels:MainViewModel.OpenUrlCommand}"
361+
Command="{Binding OpenUrlCommand, Mode=OneWay}"
362362
CommandParameter="{Binding SelectedIcon.MetaData.ProjectUrl, Mode=OneWay}">
363363
<Button.ContentTemplate>
364364
<DataTemplate>
@@ -390,7 +390,7 @@
390390
<Button Style="{StaticResource LinkButtonStyle}"
391391
Margin="0 0 4 0"
392392
VerticalAlignment="Center"
393-
Command="{x:Static viewModels:MainViewModel.OpenUrlCommand}"
393+
Command="{Binding OpenUrlCommand, Mode=OneWay}"
394394
CommandParameter="{Binding SelectedIcon.MetaData.LicenseUrl, Mode=OneWay}">
395395
<Button.ContentTemplate>
396396
<DataTemplate>

src/IconPacks.Browser/Styles/HyperlinkTextBox.xaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,7 @@
233233
</ControlTemplate>
234234
</Setter.Value>
235235
</Setter>
236-
<Setter Property="mah:TextBoxHelper.ButtonCommand" Value="{x:Static vm:MainViewModel.OpenUrlCommand}" />
236+
<Setter Property="mah:TextBoxHelper.ButtonCommand" Value="{Binding OpenUrlCommand, Mode=OneWay}" />
237237
<Setter Property="mah:TextBoxHelper.ButtonCommandParameter" Value="{Binding RelativeSource={RelativeSource Mode=Self}, Path=Text}" />
238238
<Setter Property="mah:TextBoxHelper.ButtonContentTemplate">
239239
<Setter.Value>

src/IconPacks.Browser/ViewModels/IconPackViewModel.cs

Lines changed: 45 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,11 @@
1414
using System.Windows.Media.Imaging;
1515
using System.Windows.Shapes;
1616
using AsyncAwaitBestPractices;
17+
using AsyncAwaitBestPractices.MVVM;
1718
using IconPacks.Browser.Model;
1819
using IconPacks.Browser.Properties;
1920
using JetBrains.Annotations;
2021
using MahApps.Metro.Controls;
21-
using MahApps.Metro.Controls.Dialogs;
2222
using MahApps.Metro.IconPacks;
2323
using Microsoft.Win32;
2424
using IO = System.IO;
@@ -32,25 +32,22 @@ public class IconPackViewModel : ViewModelBase
3232
private ICollectionView _iconsCollectionView;
3333
private string _filterText;
3434
private IIconViewModel _selectedIcon;
35-
private readonly IDialogCoordinator dialogCoordinator;
3635

37-
private IconPackViewModel(MainViewModel mainViewModel, IDialogCoordinator dialogCoordinator)
36+
private IconPackViewModel(MainViewModel mainViewModel)
3837
{
3938
this.MainViewModel = mainViewModel;
40-
this.dialogCoordinator = dialogCoordinator;
4139

4240
// Export commands
43-
SaveAsSvgCommand = new SimpleCommand((_) => SaveAsSvg_Execute(), (_) => SelectedIcon is IconViewModel);
44-
SaveAsWpfCommand = new SimpleCommand((_) => SaveAsWpf_Execute(), (_) => SelectedIcon is not null);
45-
SaveAsUwpCommand = new SimpleCommand((_) => SaveAsUwp_Execute(), (_) => SelectedIcon is not null);
46-
47-
SaveAsPngCommand = new SimpleCommand((_) => SaveAsBitmapExecute(new PngBitmapEncoder()), (_) => SelectedIcon is not null);
48-
SaveAsJpegCommand = new SimpleCommand((_) => SaveAsBitmapExecute(new JpegBitmapEncoder()), (_) => SelectedIcon is not null);
49-
SaveAsBmpCommand = new SimpleCommand((_) => SaveAsBitmapExecute(new BmpBitmapEncoder()), (_) => SelectedIcon is not null);
41+
SaveAsSvgCommand = new AsyncCommand(SaveAsSvgAsync, _ => SelectedIcon is IconViewModel);
42+
SaveAsWpfCommand = new AsyncCommand(SaveAsWpfAsync, _ => SelectedIcon is IconViewModel);
43+
SaveAsUwpCommand = new AsyncCommand(SaveAsUwpAsync, _ => SelectedIcon is IconViewModel);
44+
SaveAsPngCommand = new AsyncCommand(() => SaveAsBitmapAsync(new PngBitmapEncoder()), _ => SelectedIcon is IconViewModel);
45+
SaveAsJpegCommand = new AsyncCommand(() => SaveAsBitmapAsync(new JpegBitmapEncoder()), _ => SelectedIcon is IconViewModel);
46+
SaveAsBmpCommand = new AsyncCommand(() => SaveAsBitmapAsync(new BmpBitmapEncoder()), _ => SelectedIcon is IconViewModel);
5047
}
5148

52-
public IconPackViewModel(MainViewModel mainViewModel, Type enumType, Type packType, IDialogCoordinator dialogCoordinator)
53-
: this(mainViewModel, dialogCoordinator)
49+
public IconPackViewModel(MainViewModel mainViewModel, Type enumType, Type packType)
50+
: this(mainViewModel)
5451
{
5552
// Get the Name of the IconPack via Attributes
5653
this.MetaData = Attribute.GetCustomAttribute(packType, typeof(MetaDataAttribute)) as MetaDataAttribute;
@@ -60,8 +57,8 @@ public IconPackViewModel(MainViewModel mainViewModel, Type enumType, Type packTy
6057
this.LoadEnumsAsync(enumType, packType).SafeFireAndForget();
6158
}
6259

63-
public IconPackViewModel(MainViewModel mainViewModel, string caption, Type[] enumTypes, Type[] packTypes, IDialogCoordinator dialogCoordinator)
64-
: this(mainViewModel, dialogCoordinator)
60+
public IconPackViewModel(MainViewModel mainViewModel, string caption, Type[] enumTypes, Type[] packTypes)
61+
: this(mainViewModel)
6562
{
6663
this.MainViewModel = mainViewModel;
6764

@@ -183,13 +180,20 @@ public IIconViewModel SelectedIcon
183180
if (Set(ref _selectedIcon, value))
184181
{
185182
CommandManager.InvalidateRequerySuggested();
183+
184+
SaveAsSvgCommand?.RaiseCanExecuteChanged();
185+
SaveAsWpfCommand?.RaiseCanExecuteChanged();
186+
SaveAsUwpCommand?.RaiseCanExecuteChanged();
187+
SaveAsPngCommand?.RaiseCanExecuteChanged();
188+
SaveAsJpegCommand?.RaiseCanExecuteChanged();
189+
SaveAsBmpCommand?.RaiseCanExecuteChanged();
186190
}
187191
}
188192
}
189193

190-
public ICommand SaveAsSvgCommand { get; }
194+
public IAsyncCommand SaveAsSvgCommand { get; }
191195

192-
private async void SaveAsSvg_Execute()
196+
private async Task SaveAsSvgAsync()
193197
{
194198
var progress = await dialogCoordinator.ShowProgressAsync(MainViewModel, "Export", "Saving selected icon as SVG-file");
195199
progress.SetIndeterminate();
@@ -253,7 +257,11 @@ private async void SaveAsSvg_Execute()
253257

254258
var svgFileContent = ExportHelper.FillTemplate(svgFileTemplate, parameters);
255259

260+
#if NETFRAMEWORK
256261
using IO.StreamWriter file = new IO.StreamWriter(fileSaveDialog.FileName);
262+
#else
263+
await using IO.StreamWriter file = new IO.StreamWriter(fileSaveDialog.FileName);
264+
#endif
257265
await file.WriteAsync(svgFileContent);
258266
}
259267
}
@@ -265,9 +273,9 @@ private async void SaveAsSvg_Execute()
265273
await progress.CloseAsync();
266274
}
267275

268-
public ICommand SaveAsWpfCommand { get; }
276+
public IAsyncCommand SaveAsWpfCommand { get; }
269277

270-
private async void SaveAsWpf_Execute()
278+
private async Task SaveAsWpfAsync()
271279
{
272280
var progress = await dialogCoordinator.ShowProgressAsync(MainViewModel, "Export", "Saving selected icon as WPF-XAML-file");
273281
progress.SetIndeterminate();
@@ -317,7 +325,11 @@ private async void SaveAsWpf_Execute()
317325

318326
var wpfFileContent = ExportHelper.FillTemplate(wpfFileTemplate, parameters);
319327

328+
#if NETFRAMEWORK
320329
using IO.StreamWriter file = new IO.StreamWriter(fileSaveDialog.FileName);
330+
#else
331+
await using IO.StreamWriter file = new IO.StreamWriter(fileSaveDialog.FileName);
332+
#endif
321333
await file.WriteAsync(wpfFileContent);
322334
}
323335
}
@@ -329,9 +341,9 @@ private async void SaveAsWpf_Execute()
329341
await progress.CloseAsync();
330342
}
331343

332-
public ICommand SaveAsUwpCommand { get; }
344+
public IAsyncCommand SaveAsUwpCommand { get; }
333345

334-
private async void SaveAsUwp_Execute()
346+
private async Task SaveAsUwpAsync()
335347
{
336348
var progress = await dialogCoordinator.ShowProgressAsync(MainViewModel, "Export", "Saving selected icon as WPF-XAML-file");
337349
progress.SetIndeterminate();
@@ -380,7 +392,11 @@ private async void SaveAsUwp_Execute()
380392

381393
var wpfFileContent = ExportHelper.FillTemplate(wpfFileTemplate, parameters);
382394

395+
#if NETFRAMEWORK
383396
using IO.StreamWriter file = new IO.StreamWriter(fileSaveDialog.FileName);
397+
#else
398+
await using IO.StreamWriter file = new IO.StreamWriter(fileSaveDialog.FileName);
399+
#endif
384400
await file.WriteAsync(wpfFileContent);
385401
}
386402
}
@@ -392,13 +408,13 @@ private async void SaveAsUwp_Execute()
392408
await progress.CloseAsync();
393409
}
394410

395-
public ICommand SaveAsPngCommand { get; }
411+
public IAsyncCommand SaveAsPngCommand { get; }
396412

397-
public ICommand SaveAsJpegCommand { get; }
413+
public IAsyncCommand SaveAsJpegCommand { get; }
398414

399-
public ICommand SaveAsBmpCommand { get; }
415+
public IAsyncCommand SaveAsBmpCommand { get; }
400416

401-
private async void SaveAsBitmapExecute(BitmapEncoder encoder)
417+
private async Task SaveAsBitmapAsync(BitmapEncoder encoder)
402418
{
403419
var progress = await dialogCoordinator.ShowProgressAsync(MainViewModel, "Export", "Saving selected icon as bitmap image");
404420
progress.SetIndeterminate();
@@ -450,7 +466,11 @@ private async void SaveAsBitmapExecute(BitmapEncoder encoder)
450466

451467
encoder.Frames.Add(BitmapFrame.Create(renderTargetBitmap));
452468

469+
#if NETFRAMEWORK
453470
using var fileStream = new IO.FileStream(fileSaveDialog.FileName, IO.FileMode.Create);
471+
#else
472+
await using var fileStream = new IO.FileStream(fileSaveDialog.FileName, IO.FileMode.Create);
473+
#endif
454474
encoder.Save(fileStream);
455475
}
456476
}

src/IconPacks.Browser/ViewModels/MainViewModel.cs

Lines changed: 4 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -7,31 +7,18 @@
77
using System.Windows;
88
using System.Windows.Input;
99
using System.Windows.Threading;
10-
using MahApps.Metro.Controls.Dialogs;
1110
using MahApps.Metro.IconPacks;
1211

1312
namespace IconPacks.Browser.ViewModels
1413
{
1514
public class MainViewModel : ViewModelBase
1615
{
17-
private readonly IDialogCoordinator dialogCoordinator;
1816
private readonly Dispatcher _dispatcher;
1917
private string _filterText;
2018
private IconPackViewModel _selectedIconPack;
21-
private static MainViewModel _Instance;
2219

2320
public MainViewModel(Dispatcher dispatcher)
2421
{
25-
if (_Instance is null)
26-
{
27-
_Instance = this;
28-
}
29-
else
30-
{
31-
return;
32-
}
33-
34-
this.dialogCoordinator = DialogCoordinator.Instance;
3522
this._dispatcher = dispatcher;
3623
this.AppVersion = FileVersionInfo.GetVersionInfo(Assembly.GetExecutingAssembly().Location).FileVersion;
3724

@@ -80,7 +67,7 @@ public MainViewModel(Dispatcher dispatcher)
8067

8168
foreach (var (enumType, iconPackType) in availableIconPacks)
8269
{
83-
coll.Add(new IconPackViewModel(this, enumType, iconPackType, dialogCoordinator));
70+
coll.Add(new IconPackViewModel(this, enumType, iconPackType));
8471
}
8572

8673
this.IconPacks = coll;
@@ -91,31 +78,13 @@ public MainViewModel(Dispatcher dispatcher)
9178
this,
9279
"All Icons",
9380
availableIconPacks.Select(x => x.EnumType).ToArray(),
94-
availableIconPacks.Select(x => x.IconPackType).ToArray(),
95-
dialogCoordinator)
81+
availableIconPacks.Select(x => x.IconPackType).ToArray()
82+
)
9683
});
9784

9885
this.IconPacksVersion = FileVersionInfo.GetVersionInfo(Assembly.GetAssembly(typeof(PackIconMaterial)).Location).FileVersion;
9986

100-
this.Settings = new SettingsViewModel(this.dialogCoordinator);
101-
}
102-
103-
private static async void OpenUrlLink(string link)
104-
{
105-
try
106-
{
107-
Process.Start(new ProcessStartInfo
108-
{
109-
FileName = link ?? throw new ArgumentNullException(nameof(link)),
110-
// UseShellExecute is default to false on .NET Core while true on .NET Framework.
111-
// Only this value is set to true, the url link can be opened.
112-
UseShellExecute = true,
113-
});
114-
}
115-
catch (Exception e)
116-
{
117-
await DialogCoordinator.Instance.ShowMessageAsync(MainViewModel._Instance, "Error", e.Message);
118-
}
87+
this.Settings = new SettingsViewModel();
11988
}
12089

12190
public IconPackViewModel SelectedIconPack
@@ -138,13 +107,6 @@ public IconPackViewModel SelectedIconPack
138107

139108
public string IconPacksVersion { get; }
140109

141-
public static ICommand OpenUrlCommand { get; } =
142-
new SimpleCommand
143-
{
144-
CanExecuteDelegate = x => !string.IsNullOrWhiteSpace(x as string),
145-
ExecuteDelegate = x => OpenUrlLink(x as string)
146-
};
147-
148110
public string FilterText
149111
{
150112
get => _filterText;

0 commit comments

Comments
 (0)