Skip to content

Commit

Permalink
Fill in comments.
Browse files Browse the repository at this point in the history
  • Loading branch information
jamesmontemagno committed Sep 12, 2019
1 parent dffc610 commit 99c2a93
Show file tree
Hide file tree
Showing 6 changed files with 138 additions and 2 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -226,3 +226,4 @@ pip-log.txt
.mr.developer.cfg

XamarinEvolve.userprefs
/MvvmHelpers/MvvmHelpers.xml
44 changes: 44 additions & 0 deletions MvvmHelpers/Commands/AsyncCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,13 @@ public class AsyncCommand : IAsyncCommand
readonly bool continueOnCapturedContext;
readonly WeakEventManager weakEventManager = new WeakEventManager();

/// <summary>
/// Create a new AsyncCommand
/// </summary>
/// <param name="execute">Function to execute</param>
/// <param name="canExecute">Function to call to determine if it can be executed</param>
/// <param name="onException">Action callback when an exception occurs</param>
/// <param name="continueOnCapturedContext">If the context should be captured on exception</param>
public AsyncCommand(Func<Task> execute,
Func<object, bool> canExecute = null,
Action<Exception> onException = null,
Expand All @@ -31,16 +38,31 @@ public AsyncCommand(Func<Task> execute,
this.continueOnCapturedContext = continueOnCapturedContext;
}

/// <summary>
/// Event triggered when Can Excecute changes.
/// </summary>
public event EventHandler CanExecuteChanged
{
add { weakEventManager.AddEventHandler(value); }
remove { weakEventManager.RemoveEventHandler(value); }
}

/// <summary>
/// Invoke the CanExecute method and return if it can be executed.
/// </summary>
/// <param name="parameter">Parameter to pass to CanExecute.</param>
/// <returns>If it can be executed.</returns>
public bool CanExecute(object parameter) => canExecute?.Invoke(parameter) ?? true;

/// <summary>
/// Execute the command async.
/// </summary>
/// <returns>Task of action being executed that can be awaited.</returns>
public Task ExecuteAsync() => execute();

/// <summary>
/// Raise a CanExecute change event.
/// </summary>
public void RaiseCanExecuteChanged() => weakEventManager.HandleEvent(this, EventArgs.Empty, nameof(CanExecuteChanged));

#region Explicit implementations
Expand All @@ -59,6 +81,13 @@ public class AsyncCommand<T> : IAsyncCommand<T>
readonly bool continueOnCapturedContext;
readonly WeakEventManager weakEventManager = new WeakEventManager();

/// <summary>
/// Create a new AsyncCommand
/// </summary>
/// <param name="execute">Function to execute</param>
/// <param name="canExecute">Function to call to determine if it can be executed</param>
/// <param name="onException">Action callback when an exception occurs</param>
/// <param name="continueOnCapturedContext">If the context should be captured on exception</param>
public AsyncCommand(Func<T, Task> execute,
Func<object, bool> canExecute = null,
Action<Exception> onException = null,
Expand All @@ -70,16 +99,31 @@ public AsyncCommand(Func<T, Task> execute,
this.continueOnCapturedContext = continueOnCapturedContext;
}

/// <summary>
/// Event triggered when Can Excecute changes.
/// </summary>
public event EventHandler CanExecuteChanged
{
add { weakEventManager.AddEventHandler(value); }
remove { weakEventManager.RemoveEventHandler(value); }
}

/// <summary>
/// Invoke the CanExecute method and return if it can be executed.
/// </summary>
/// <param name="parameter">Parameter to pass to CanExecute.</param>
/// <returns>If it can be executed</returns>
public bool CanExecute(object parameter) => canExecute?.Invoke(parameter) ?? true;

/// <summary>
/// Execute the command async.
/// </summary>
/// <returns>Task that is executing and can be awaited.</returns>
public Task ExecuteAsync(T parameter) => execute(parameter);

/// <summary>
/// Raise a CanExecute change event.
/// </summary>
public void RaiseCanExecuteChanged() => weakEventManager.HandleEvent(this, EventArgs.Empty, nameof(CanExecuteChanged));

#region Explicit implementations
Expand Down
42 changes: 42 additions & 0 deletions MvvmHelpers/Commands/Command.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ namespace MvvmHelpers.Commands
/// <typeparam name="T"></typeparam>
public class Command<T> : Command
{
/// <summary>
/// Command that takes an action to execute
/// </summary>
/// <param name="execute">The action to execute of type T</param>
public Command(Action<T> execute)
: base(o =>
{
Expand All @@ -23,6 +27,11 @@ public Command(Action<T> execute)
}
}

/// <summary>
/// Command that takes an action to execute
/// </summary>
/// <param name="execute">The action to execute of type T</param>
/// <param name="canExecute">Function to call to determine if it can be executed.</param>
public Command(Action<T> execute, Func<T, bool> canExecute)
: base(o =>
{
Expand All @@ -49,22 +58,40 @@ public class Command : ICommand
readonly Action<object> execute;
readonly WeakEventManager weakEventManager = new WeakEventManager();

/// <summary>
/// Command that takes an action to execute.
/// </summary>
/// <param name="execute">Action to execute.</param>
public Command(Action<object> execute)
{
this.execute = execute ?? throw new ArgumentNullException(nameof(execute));
}

/// <summary>
/// Command that takes an action to execute.
/// </summary>
/// <param name="execute">Action to execute.</param>
public Command(Action execute) : this(o => execute())
{
if (execute == null)
throw new ArgumentNullException(nameof(execute));
}

/// <summary>
/// Command that takes an action to execute.
/// </summary>
/// <param name="execute">Action to execute.</param>
/// <param name="canExecute">Function to determine if can execute.</param>
public Command(Action<object> execute, Func<object, bool> canExecute) : this(execute)
{
this.canExecute = canExecute ?? throw new ArgumentNullException(nameof(canExecute));
}

/// <summary>
/// Command that takes an action to execute.
/// </summary>
/// <param name="execute">Action to execute.</param>
/// <param name="canExecute">Function to determine if can execute.</param>
public Command(Action execute, Func<bool> canExecute) : this(o => execute(), o => canExecute())
{
if (execute == null)
Expand All @@ -73,16 +100,31 @@ public Command(Action execute, Func<bool> canExecute) : this(o => execute(), o =
throw new ArgumentNullException(nameof(canExecute));
}

/// <summary>
/// Invoke the CanExecute method to determine if it can be executed.
/// </summary>
/// <param name="parameter">Parameter to test and pass to CanExecute.</param>
/// <returns>If it can be executed.</returns>
public bool CanExecute(object parameter) => canExecute?.Invoke(parameter) ?? true;

/// <summary>
/// Event handler raised when CanExecute changes.
/// </summary>
public event EventHandler CanExecuteChanged
{
add { weakEventManager.AddEventHandler(value); }
remove { weakEventManager.RemoveEventHandler(value); }
}

/// <summary>
/// Execute the command with or without a parameter.
/// </summary>
/// <param name="parameter">Parameter to pass to execute method.</param>
public void Execute(object parameter) => execute(parameter);

/// <summary>
/// Manually raise a CanExecuteChanged event.
/// </summary>
public void RaiseCanExecuteChanged() => weakEventManager.HandleEvent(this, EventArgs.Empty, nameof(CanExecuteChanged));
}
}
16 changes: 14 additions & 2 deletions MvvmHelpers/MvvmHelpers.csproj
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<Project Sdk="MSBuild.Sdk.Extras/2.0.43">
<Project Sdk="MSBuild.Sdk.Extras/2.0.43">

<PropertyGroup>
<TargetFrameworks>net461;netstandard1.0;netstandard2.0</TargetFrameworks>
Expand All @@ -12,7 +12,7 @@
<PackOnBuild>true</PackOnBuild>
<PackageIconUrl>https://raw.githubusercontent.com/jamesmontemagno/mvvm-helpers/master/art/Icon.png</PackageIconUrl>
<NeutralLanguage>en</NeutralLanguage>
<PackageLicenseUrl>https://raw.githubusercontent.com/jamesmontemagno/mvvm-helpers/master/LICENSE.md</PackageLicenseUrl>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<Owners>James Montemagno</Owners>
<PackageProjectUrl>https://github.com/jamesmontemagno/mvvm-helpers</PackageProjectUrl>
<Summary>Collection of MVVM Helpers such as ObservableRangeCollection, BaseViewModel, Grouping, and others.</Summary>
Expand Down Expand Up @@ -43,6 +43,18 @@
<AllowedOutputExtensionsInPackageBuildOutputFolder>$(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb</AllowedOutputExtensionsInPackageBuildOutputFolder>
</PropertyGroup>

<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|net461|AnyCPU'">
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<WarningsAsErrors />
<WarningLevel>4</WarningLevel>
<DocumentationFile>C:\Users\jamont\Source\Repos\jamesmontemagno\mvvm-helpers\MvvmHelpers\MvvmHelpers.xml</DocumentationFile>
</PropertyGroup>

<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|net461|AnyCPU'">
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<WarningsAsErrors />
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0-beta2-19367-01" PrivateAssets="All" />
<PackageReference Include="System.ValueTuple" Version="4.5.0" />
Expand Down
6 changes: 6 additions & 0 deletions MvvmHelpers/Utils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,12 @@ public static Task<T> WithTimeout<T>(this Task<T> task, TimeSpan timeout) =>
WithTimeout(task, (int)timeout.TotalMilliseconds);

#pragma warning disable RECS0165 // Asynchronous methods should return a Task instead of void
/// <summary>
/// Attempts to await on the task and catches exception
/// </summary>
/// <param name="task">Task to execute</param>
/// <param name="onException">What to do when method has an exception</param>
/// <param name="continueOnCapturedContext">If the context should be captured.</param>
public static async void SafeFireAndForget(this Task task, Action<Exception> onException = null, bool continueOnCapturedContext = false)
#pragma warning restore RECS0165 // Asynchronous methods should return a Task instead of void
{
Expand Down
31 changes: 31 additions & 0 deletions MvvmHelpers/WeakEventManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,19 @@

namespace MvvmHelpers
{
/// <summary>
/// Weak event manager to subscribe and unsubscribe from events.
/// </summary>
public class WeakEventManager
{
readonly Dictionary<string, List<Subscription>> eventHandlers = new Dictionary<string, List<Subscription>>();

/// <summary>
/// Add an event handler to the manager.
/// </summary>
/// <typeparam name="TEventArgs">Event handler of T</typeparam>
/// <param name="handler">Handler of the event</param>
/// <param name="eventName">Name to use in the dictionary. Should be unique.</param>
public void AddEventHandler<TEventArgs>(EventHandler<TEventArgs> handler, [CallerMemberName]string eventName = null)
where TEventArgs : EventArgs
{
Expand All @@ -23,6 +32,11 @@ public void AddEventHandler<TEventArgs>(EventHandler<TEventArgs> handler, [Calle
AddEventHandler(eventName, handler.Target, handler.GetMethodInfo());
}

/// <summary>
/// Add an event handler to the manager.
/// </summary>
/// <param name="handler">Handler of the event</param>
/// <param name="eventName">Name to use in the dictionary. Should be unique.</param>
public void AddEventHandler(EventHandler handler, [CallerMemberName]string eventName = null)
{
if (IsNullOrEmpty(eventName))
Expand All @@ -34,6 +48,12 @@ public void AddEventHandler(EventHandler handler, [CallerMemberName]string event
AddEventHandler(eventName, handler.Target, handler.GetMethodInfo());
}

/// <summary>
/// Handle an event
/// </summary>
/// <param name="sender">Sender of the event</param>
/// <param name="args">Arguments for the event</param>
/// <param name="eventName">Name of the event.</param>
public void HandleEvent(object sender, object args, string eventName)
{
var toRaise = new List<(object subscriber, MethodInfo handler)>();
Expand Down Expand Up @@ -75,6 +95,12 @@ public void HandleEvent(object sender, object args, string eventName)
}
}

/// <summary>
/// Remove an event handler.
/// </summary>
/// <typeparam name="TEventArgs">Type of the EventArgs</typeparam>
/// <param name="handler">Handler to remove</param>
/// <param name="eventName">Event name to remove</param>
public void RemoveEventHandler<TEventArgs>(EventHandler<TEventArgs> handler, [CallerMemberName]string eventName = null)
where TEventArgs : EventArgs
{
Expand All @@ -87,6 +113,11 @@ public void RemoveEventHandler<TEventArgs>(EventHandler<TEventArgs> handler, [Ca
RemoveEventHandler(eventName, handler.Target, handler.GetMethodInfo());
}

/// <summary>
/// Remove an event handler.
/// </summary>
/// <param name="handler">Handler to remove</param>
/// <param name="eventName">Event name to remove</param>
public void RemoveEventHandler(EventHandler handler, [CallerMemberName]string eventName = null)
{
if (IsNullOrEmpty(eventName))
Expand Down

0 comments on commit 99c2a93

Please sign in to comment.