Skip to content

Commit 7e34740

Browse files
Add NuGet Readme
Closes #73
1 parent b4c436f commit 7e34740

File tree

4 files changed

+485
-2
lines changed

4 files changed

+485
-2
lines changed

Src/AsyncAwaitBestPractices.MVVM/AsyncAwaitBestPractices.MVVM.csproj

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
- Add AsyncCommand support for nullable value types
2929
- Add AsyncValueCommand support for nullable value types
3030
</PackageReleaseNotes>
31-
<Version>6.0.0-pre1</Version>
31+
<Version>6.0.0-pre2</Version>
3232
<RepositoryUrl>https://github.com/brminnick/AsyncAwaitBestPractices</RepositoryUrl>
3333
<Product>$(AssemblyName) ($(TargetFramework))</Product>
3434
<AssemblyVersion>1.0.0.0</AssemblyVersion>
@@ -61,6 +61,7 @@
6161
</ItemGroup>
6262
<ItemGroup>
6363
<ProjectReference Include="..\AsyncAwaitBestPractices\AsyncAwaitBestPractices.csproj" />
64+
<None Include="Src\AsyncAwaitBestPractices.MVVM\README.md" Pack="true" PackagePath="\"/>
6465
</ItemGroup>
6566
<ItemGroup>
6667
<PackageReference Update="NETStandard.Library" PrivateAssets="all" />
Lines changed: 269 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,269 @@
1+
# AsyncAwaitBestPractices.MVVM
2+
3+
[![NuGet](https://buildstats.info/nuget/AsyncAwaitBestPractices.MVVM?includePreReleases=true)](https://www.nuget.org/packages/AsyncAwaitBestPractices.MVVM/)
4+
5+
- Available on NuGet: https://www.nuget.org/packages/AsyncAwaitBestPractices.MVVM/
6+
7+
- Allows for `Task` to safely be used asynchronously with `ICommand`:
8+
- `IAsyncCommand : ICommand`
9+
- `AsyncCommand : IAsyncCommand`
10+
- `IAsyncCommand<T> : ICommand`
11+
- `AsyncCommand<T> : IAsyncCommand<T>`
12+
- `IAsyncCommand<TExecute, TCanExecute> : IAsyncCommand<TExecute>`
13+
- `AsyncCommand<TExecute, TCanExecute> : IAsyncCommand<TExecute, TCanExecute>`
14+
15+
- Allows for `ValueTask` to safely be used asynchronously with `ICommand`:
16+
- `IAsyncValueCommand : ICommand`
17+
- `AsyncValueCommand : IAsyncValueCommand`
18+
- `IAsyncValueCommand<T> : ICommand`
19+
- `AsyncValueCommand<T> : IAsyncValueCommand<T>`
20+
- `IAsyncValueCommand<TExecute, TCanExecute> : IAsyncValueCommand<TExecute>`
21+
- `AsyncValueCommand<TExecute, TCanExecute> : IAsyncValueCommand<TExecute, TCanExecute>`
22+
- [Usage instructions](#asyncawaitbestpracticesmvvm-2)
23+
24+
## Setup
25+
26+
- Available on NuGet: https://www.nuget.org/packages/AsyncAwaitBestPractices.MVVM/
27+
- Add to any project supporting .NET Standard 1.0
28+
29+
## `AsyncCommand`
30+
31+
Allows for `Task` to safely be used asynchronously with `ICommand`:
32+
33+
- `AsyncCommand<TExecute, TCanExecute> : IAsyncCommand<TExecute, TCanExecute>`
34+
- `IAsyncCommand<TExecute, TCanExecute> : IAsyncCommand<TExecute>`
35+
- `AsyncCommand<T> : IAsyncCommand<T>`
36+
- `IAsyncCommand<T> : ICommand`
37+
- `AsyncCommand : IAsyncCommand`
38+
- `IAsyncCommand : ICommand`
39+
40+
```csharp
41+
public AsyncCommand(Func<TExecute, Task> execute,
42+
Func<TCanExecute, bool>? canExecute = null,
43+
Action<Exception>? onException = null,
44+
bool continueOnCapturedContext = false)
45+
```
46+
47+
```csharp
48+
public AsyncCommand(Func<T, Task> execute,
49+
Func<object?, bool>? canExecute = null,
50+
Action<Exception>? onException = null,
51+
bool continueOnCapturedContext = false)
52+
```
53+
54+
```csharp
55+
public AsyncCommand(Func<Task> execute,
56+
Func<object?, bool>? canExecute = null,
57+
Action<Exception>? onException = null,
58+
bool continueOnCapturedContext = false)
59+
```
60+
61+
```csharp
62+
public class ExampleClass
63+
{
64+
bool _isBusy;
65+
66+
public ExampleClass()
67+
{
68+
ExampleAsyncCommand = new AsyncCommand(ExampleAsyncMethod);
69+
ExampleAsyncIntCommand = new AsyncCommand<int>(ExampleAsyncMethodWithIntParameter);
70+
ExampleAsyncIntCommandWithCanExecute = new AsyncCommand<int, int>(ExampleAsyncMethodWithIntParameter, CanExecuteInt);
71+
ExampleAsyncExceptionCommand = new AsyncCommand(ExampleAsyncMethodWithException, onException: ex => Console.WriteLine(ex.ToString()));
72+
ExampleAsyncCommandWithCanExecuteChanged = new AsyncCommand(ExampleAsyncMethod, _ => !IsBusy);
73+
ExampleAsyncCommandReturningToTheCallingThread = new AsyncCommand(ExampleAsyncMethod, continueOnCapturedContext: true);
74+
}
75+
76+
public IAsyncCommand ExampleAsyncCommand { get; }
77+
public IAsyncCommand<int> ExampleAsyncIntCommand { get; }
78+
public IAsyncCommand<int, int> ExampleAsyncIntCommandWithCanExecute { get; }
79+
public IAsyncCommand ExampleAsyncExceptionCommand { get; }
80+
public IAsyncCommand ExampleAsyncCommandWithCanExecuteChanged { get; }
81+
public IAsyncCommand ExampleAsyncCommandReturningToTheCallingThread { get; }
82+
83+
public bool IsBusy
84+
{
85+
get => _isBusy;
86+
set
87+
{
88+
if (_isBusy != value)
89+
{
90+
_isBusy = value;
91+
ExampleAsyncCommandWithCanExecuteChanged.RaiseCanExecuteChanged();
92+
}
93+
}
94+
}
95+
96+
async Task ExampleAsyncMethod()
97+
{
98+
await Task.Delay(1000);
99+
}
100+
101+
async Task ExampleAsyncMethodWithIntParameter(int parameter)
102+
{
103+
await Task.Delay(parameter);
104+
}
105+
106+
async Task ExampleAsyncMethodWithException()
107+
{
108+
await Task.Delay(1000);
109+
throw new Exception();
110+
}
111+
112+
bool CanExecuteInt(int count)
113+
{
114+
if(count > 2)
115+
return true;
116+
117+
return false;
118+
}
119+
120+
void ExecuteCommands()
121+
{
122+
_isBusy = true;
123+
124+
try
125+
{
126+
ExampleAsyncCommand.Execute(null);
127+
ExampleAsyncIntCommand.Execute(1000);
128+
ExampleAsyncExceptionCommand.Execute(null);
129+
ExampleAsyncCommandReturningToTheCallingThread.Execute(null);
130+
131+
if(ExampleAsyncCommandWithCanExecuteChanged.CanExecute(null))
132+
ExampleAsyncCommandWithCanExecuteChanged.Execute(null);
133+
134+
if(ExampleAsyncIntCommandWithCanExecute.CanExecute(1))
135+
ExampleAsyncIntCommandWithCanExecute.Execute(1);
136+
}
137+
finally
138+
{
139+
_isBusy = false;
140+
}
141+
}
142+
}
143+
```
144+
145+
## `AsyncValueCommand`
146+
147+
Allows for `ValueTask` to safely be used asynchronously with `ICommand`.
148+
149+
If you're new to ValueTask, check out this great write-up, [Understanding the Whys, Whats, and Whens of ValueTask
150+
](https://blogs.msdn.microsoft.com/dotnet/2018/11/07/understanding-the-whys-whats-and-whens-of-valuetask?WT.mc_id=mobile-0000-bramin).
151+
152+
- `AsyncValueCommand<TExecute, TCanExecute> : IAsyncValueCommand<TExecute, TCanExecute>`
153+
- `IAsyncValueCommand<TExecute, TCanExecute> : IAsyncValueCommand<TExecute>`
154+
- `AsyncValueCommand<T> : IAsyncValueCommand<T>`
155+
- `IAsyncValueCommand<T> : ICommand`
156+
- `AsyncValueCommand : IAsyncValueCommand`
157+
- `IAsyncValueCommand : ICommand`
158+
159+
```csharp
160+
public AsyncValueCommand(Func<TExecute, ValueTask> execute,
161+
Func<TCanExecute, bool>? canExecute = null,
162+
Action<Exception>? onException = null,
163+
bool continueOnCapturedContext = false)
164+
```
165+
166+
```csharp
167+
public AsyncValueCommand(Func<T, ValueTask> execute,
168+
Func<object?, bool>? canExecute = null,
169+
Action<Exception>? onException = null,
170+
bool continueOnCapturedContext = false)
171+
```
172+
173+
```csharp
174+
public AsyncValueCommand(Func<ValueTask> execute,
175+
Func<object?, bool>? canExecute = null,
176+
Action<Exception>? onException = null,
177+
bool continueOnCapturedContext = false)
178+
```
179+
180+
```csharp
181+
public class ExampleClass
182+
{
183+
bool _isBusy;
184+
185+
public ExampleClass()
186+
{
187+
ExampleValueTaskCommand = new AsyncValueCommand(ExampleValueTaskMethod);
188+
ExampleValueTaskIntCommand = new AsyncValueCommand<int>(ExampleValueTaskMethodWithIntParameter);
189+
ExampleValueTaskIntCommandWithCanExecute = new AsyncValueCommand<int, int>(ExampleValueTaskMethodWithIntParameter, CanExecuteInt);
190+
ExampleValueTaskExceptionCommand = new AsyncValueCommand(ExampleValueTaskMethodWithException, onException: ex => Debug.WriteLine(ex.ToString()));
191+
ExampleValueTaskCommandWithCanExecuteChanged = new AsyncValueCommand(ExampleValueTaskMethod, _ => !IsBusy);
192+
ExampleValueTaskCommandReturningToTheCallingThread = new AsyncValueCommand(ExampleValueTaskMethod, continueOnCapturedContext: true);
193+
}
194+
195+
public IAsyncValueCommand ExampleValueTaskCommand { get; }
196+
public IAsyncValueCommand<int> ExampleValueTaskIntCommand { get; }
197+
public IAsyncCommand<int, int> ExampleValueTaskIntCommandWithCanExecute { get; }
198+
public IAsyncValueCommand ExampleValueTaskExceptionCommand { get; }
199+
public IAsyncValueCommand ExampleValueTaskCommandWithCanExecuteChanged { get; }
200+
public IAsyncValueCommand ExampleValueTaskCommandReturningToTheCallingThread { get; }
201+
202+
public bool IsBusy
203+
{
204+
get => _isBusy;
205+
set
206+
{
207+
if (_isBusy != value)
208+
{
209+
_isBusy = value;
210+
ExampleValueTaskCommandWithCanExecuteChanged.RaiseCanExecuteChanged();
211+
}
212+
}
213+
}
214+
215+
async ValueTask ExampleValueTaskMethod()
216+
{
217+
var random = new Random();
218+
if (random.Next(10) > 9)
219+
await Task.Delay(1000);
220+
}
221+
222+
async ValueTask ExampleValueTaskMethodWithIntParameter(int parameter)
223+
{
224+
var random = new Random();
225+
if (random.Next(10) > 9)
226+
await Task.Delay(parameter);
227+
}
228+
229+
async ValueTask ExampleValueTaskMethodWithException()
230+
{
231+
var random = new Random();
232+
if (random.Next(10) > 9)
233+
await Task.Delay(1000);
234+
235+
throw new Exception();
236+
}
237+
238+
bool CanExecuteInt(int count)
239+
{
240+
if(count > 2)
241+
return true;
242+
243+
return false;
244+
}
245+
246+
void ExecuteCommands()
247+
{
248+
_isBusy = true;
249+
250+
try
251+
{
252+
ExampleValueTaskCommand.Execute(null);
253+
ExampleValueTaskIntCommand.Execute(1000);
254+
ExampleValueTaskExceptionCommand.Execute(null);
255+
ExampleValueTaskCommandReturningToTheCallingThread.Execute(null);
256+
257+
if (ExampleValueTaskCommandWithCanExecuteChanged.CanExecute(null))
258+
ExampleValueTaskCommandWithCanExecuteChanged.Execute(null);
259+
260+
if(ExampleValueTaskIntCommandWithCanExecute.CanExecute(2))
261+
ExampleValueTaskIntCommandWithCanExecute.Execute(2);
262+
}
263+
finally
264+
{
265+
_isBusy = false;
266+
}
267+
}
268+
}
269+
```

Src/AsyncAwaitBestPractices/AsyncAwaitBestPractices.csproj

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
New In This Release:
3030
- Improve Nullability
3131
</PackageReleaseNotes>
32-
<Version>6.0.0-pre1</Version>
32+
<Version>6.0.0-pre2</Version>
3333
<RepositoryUrl>https://github.com/brminnick/AsyncAwaitBestPractices</RepositoryUrl>
3434
<Product>$(AssemblyName) ($(TargetFramework))</Product>
3535
<AssemblyVersion>1.0.0.0</AssemblyVersion>
@@ -76,5 +76,6 @@
7676
</ItemGroup>
7777
<ItemGroup>
7878
<PackageReference Update="NETStandard.Library" PrivateAssets="all" />
79+
<None Include="Src\AsyncAwaitBestPractices\README.md" Pack="true" PackagePath="\"/>
7980
</ItemGroup>
8081
</Project>

0 commit comments

Comments
 (0)