Adding KeepTargetAlive for weak references. See http://galasoft.ch/s/mvvmweakaction
This commit is contained in:
Родитель
b1a6b1df29
Коммит
f46a9fb15c
|
@ -10,7 +10,6 @@
|
|||
// <license>
|
||||
// See license.txt in this project or http://www.galasoft.ch/license_MIT.txt
|
||||
// </license>
|
||||
// <LastBaseLevel>BL0011</LastBaseLevel>
|
||||
// ****************************************************************************
|
||||
// <credits>This class was developed by Josh Smith (http://joshsmithonwpf.wordpress.com) and
|
||||
// slightly modified with his permission.</credits>
|
||||
|
@ -43,8 +42,8 @@ namespace GalaSoft.MvvmLight.Command
|
|||
/// This will enable (or restore) the CommandManager class which handles
|
||||
/// automatic enabling/disabling of controls based on the CanExecute delegate.</remarks>
|
||||
////[ClassInfo(typeof(RelayCommand),
|
||||
//// VersionString = "5.3.14",
|
||||
//// DateString = "201604212130",
|
||||
//// VersionString = "5.4.15",
|
||||
//// DateString = "201612041700",
|
||||
//// Description = "A command whose sole purpose is to relay its functionality to other objects by invoking delegates.",
|
||||
//// UrlContacts = "http://www.galasoft.ch/contact_en.html",
|
||||
//// Email = "laurent@galasoft.ch")]
|
||||
|
@ -58,34 +57,42 @@ namespace GalaSoft.MvvmLight.Command
|
|||
/// Initializes a new instance of the RelayCommand class that
|
||||
/// can always execute.
|
||||
/// </summary>
|
||||
/// <param name="execute">The execution logic. IMPORTANT: Note that closures are not supported at the moment
|
||||
/// due to the use of WeakActions (see http://stackoverflow.com/questions/25730530/). </param>
|
||||
/// <param name="execute">The execution logic. IMPORTANT: If the action causes a closure,
|
||||
/// you must set keepTargetAlive to true to avoid side effects. </param>
|
||||
/// <param name="keepTargetAlive">If true, the target of the Action will
|
||||
/// be kept as a hard reference, which might cause a memory leak. You should only set this
|
||||
/// parameter to true if the action is causing a closure. See
|
||||
/// http://galasoft.ch/s/mvvmweakaction. </param>
|
||||
/// <exception cref="ArgumentNullException">If the execute argument is null.</exception>
|
||||
public RelayCommand(Action execute)
|
||||
: this(execute, null)
|
||||
public RelayCommand(Action execute, bool keepTargetAlive = false)
|
||||
: this(execute, null, keepTargetAlive)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the RelayCommand class.
|
||||
/// </summary>
|
||||
/// <param name="execute">The execution logic. IMPORTANT: Note that closures are not supported at the moment
|
||||
/// due to the use of WeakActions (see http://stackoverflow.com/questions/25730530/). </param>
|
||||
/// <param name="canExecute">The execution status logic.</param>
|
||||
/// <exception cref="ArgumentNullException">If the execute argument is null. IMPORTANT: Note that closures are not supported at the moment
|
||||
/// due to the use of WeakActions (see http://stackoverflow.com/questions/25730530/). </exception>
|
||||
public RelayCommand(Action execute, Func<bool> canExecute)
|
||||
/// <param name="execute">The execution logic. IMPORTANT: If the action causes a closure,
|
||||
/// you must set keepTargetAlive to true to avoid side effects. </param>
|
||||
/// <param name="canExecute">The execution status logic. IMPORTANT: If the func causes a closure,
|
||||
/// you must set keepTargetAlive to true to avoid side effects. </param>
|
||||
/// <param name="keepTargetAlive">If true, the target of the Action will
|
||||
/// be kept as a hard reference, which might cause a memory leak. You should only set this
|
||||
/// parameter to true if the action is causing a closures. See
|
||||
/// http://galasoft.ch/s/mvvmweakaction. </param>
|
||||
/// <exception cref="ArgumentNullException">If the execute argument is null.</exception>
|
||||
public RelayCommand(Action execute, Func<bool> canExecute, bool keepTargetAlive = false)
|
||||
{
|
||||
if (execute == null)
|
||||
{
|
||||
throw new ArgumentNullException("execute");
|
||||
}
|
||||
|
||||
_execute = new WeakAction(execute);
|
||||
_execute = new WeakAction(execute, keepTargetAlive);
|
||||
|
||||
if (canExecute != null)
|
||||
{
|
||||
_canExecute = new WeakFunc<bool>(canExecute);
|
||||
_canExecute = new WeakFunc<bool>(canExecute, keepTargetAlive);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -55,34 +55,42 @@ namespace GalaSoft.MvvmLight.Command
|
|||
/// Initializes a new instance of the RelayCommand class that
|
||||
/// can always execute.
|
||||
/// </summary>
|
||||
/// <param name="execute">The execution logic. IMPORTANT: Note that closures are not supported at the moment
|
||||
/// due to the use of WeakActions (see http://stackoverflow.com/questions/25730530/). </param>
|
||||
/// <param name="execute">The execution logic. IMPORTANT: If the action causes a closure,
|
||||
/// you must set keepTargetAlive to true to avoid side effects. </param>
|
||||
/// <param name="keepTargetAlive">If true, the target of the Action will
|
||||
/// be kept as a hard reference, which might cause a memory leak. You should only set this
|
||||
/// parameter to true if the action is causing a closure. See
|
||||
/// http://galasoft.ch/s/mvvmweakaction. </param>
|
||||
/// <exception cref="ArgumentNullException">If the execute argument is null.</exception>
|
||||
public RelayCommand(Action<T> execute)
|
||||
: this(execute, null)
|
||||
public RelayCommand(Action<T> execute, bool keepTargetAlive = false)
|
||||
: this(execute, null, keepTargetAlive)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the RelayCommand class.
|
||||
/// </summary>
|
||||
/// <param name="execute">The execution logic. IMPORTANT: Note that closures are not supported at the moment
|
||||
/// due to the use of WeakActions (see http://stackoverflow.com/questions/25730530/). </param>
|
||||
/// <param name="canExecute">The execution status logic. IMPORTANT: Note that closures are not supported at the moment
|
||||
/// due to the use of WeakActions (see http://stackoverflow.com/questions/25730530/). </param>
|
||||
/// <param name="execute">The execution logic. IMPORTANT: If the action causes a closure,
|
||||
/// you must set keepTargetAlive to true to avoid side effects. </param>
|
||||
/// <param name="canExecute">The execution status logic. IMPORTANT: If the func causes a closure,
|
||||
/// you must set keepTargetAlive to true to avoid side effects. </param>
|
||||
/// <param name="keepTargetAlive">If true, the target of the Action will
|
||||
/// be kept as a hard reference, which might cause a memory leak. You should only set this
|
||||
/// parameter to true if the action is causing a closure. See
|
||||
/// http://galasoft.ch/s/mvvmweakaction. </param>
|
||||
/// <exception cref="ArgumentNullException">If the execute argument is null.</exception>
|
||||
public RelayCommand(Action<T> execute, Func<T, bool> canExecute)
|
||||
public RelayCommand(Action<T> execute, Func<T, bool> canExecute, bool keepTargetAlive = false)
|
||||
{
|
||||
if (execute == null)
|
||||
{
|
||||
throw new ArgumentNullException("execute");
|
||||
}
|
||||
|
||||
_execute = new WeakAction<T>(execute);
|
||||
_execute = new WeakAction<T>(execute, keepTargetAlive);
|
||||
|
||||
if (canExecute != null)
|
||||
{
|
||||
_canExecute = new WeakFunc<T,bool>(canExecute);
|
||||
_canExecute = new WeakFunc<T,bool>(canExecute, keepTargetAlive);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -25,8 +25,8 @@ namespace GalaSoft.MvvmLight.Helpers
|
|||
/// to be created to the Action's owner. The owner can be garbage collected at any time.
|
||||
/// </summary>
|
||||
////[ClassInfo(typeof(WeakAction),
|
||||
//// VersionString = "5.1.16",
|
||||
//// DateString = "201502072030",
|
||||
//// VersionString = "5.4.18",
|
||||
//// DateString = "201708281410",
|
||||
//// Description = "A class allowing to store and invoke actions without keeping a hard reference to the action's target.",
|
||||
//// UrlContacts = "http://www.galasoft.ch/contact_en.html",
|
||||
//// Email = "laurent@galasoft.ch")]
|
||||
|
@ -93,6 +93,17 @@ namespace GalaSoft.MvvmLight.Helpers
|
|||
set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Saves the <see cref="ActionReference"/> as a hard reference. This is
|
||||
/// used in relation with this instance's constructor and only if
|
||||
/// the constructor's keepTargetAlive parameter is true.
|
||||
/// </summary>
|
||||
protected object LiveReference
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a WeakReference to the target passed when constructing
|
||||
/// the WeakAction. This is not necessarily the same as
|
||||
|
@ -132,8 +143,12 @@ namespace GalaSoft.MvvmLight.Helpers
|
|||
/// Initializes a new instance of the <see cref="WeakAction" /> class.
|
||||
/// </summary>
|
||||
/// <param name="action">The action that will be associated to this instance.</param>
|
||||
public WeakAction(Action action)
|
||||
: this(action == null ? null : action.Target, action)
|
||||
/// <param name="keepTargetAlive">If true, the target of the Action will
|
||||
/// be kept as a hard reference, which might cause a memory leak. You should only set this
|
||||
/// parameter to true if the action is using closures. See
|
||||
/// http://galasoft.ch/s/mvvmweakaction. </param>
|
||||
public WeakAction(Action action, bool keepTargetAlive = false)
|
||||
: this(action == null ? null : action.Target, action, keepTargetAlive)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -142,12 +157,16 @@ namespace GalaSoft.MvvmLight.Helpers
|
|||
/// </summary>
|
||||
/// <param name="target">The action's owner.</param>
|
||||
/// <param name="action">The action that will be associated to this instance.</param>
|
||||
/// <param name="keepTargetAlive">If true, the target of the Action will
|
||||
/// be kept as a hard reference, which might cause a memory leak. You should only set this
|
||||
/// parameter to true if the action is using closures. See
|
||||
/// http://galasoft.ch/s/mvvmweakaction. </param>
|
||||
[SuppressMessage(
|
||||
"Microsoft.Design",
|
||||
"Microsoft.Design",
|
||||
"CA1062:Validate arguments of public methods",
|
||||
MessageId = "1",
|
||||
Justification = "Method should fail with an exception if action is null.")]
|
||||
public WeakAction(object target, Action action)
|
||||
public WeakAction(object target, Action action, bool keepTargetAlive = false)
|
||||
{
|
||||
#if NETFX_CORE
|
||||
if (action.GetMethodInfo().IsStatic)
|
||||
|
@ -189,6 +208,7 @@ namespace GalaSoft.MvvmLight.Helpers
|
|||
{
|
||||
Method = action.Method;
|
||||
ActionReference = new WeakReference(action.Target);
|
||||
LiveReference = keepTargetAlive ? action.Target : null;
|
||||
}
|
||||
}
|
||||
#else
|
||||
|
@ -200,7 +220,24 @@ namespace GalaSoft.MvvmLight.Helpers
|
|||
ActionReference = new WeakReference(action.Target);
|
||||
#endif
|
||||
|
||||
LiveReference = keepTargetAlive ? action.Target : null;
|
||||
Reference = new WeakReference(target);
|
||||
|
||||
#if DEBUG
|
||||
if (ActionReference != null
|
||||
&& ActionReference.Target != null
|
||||
&& !keepTargetAlive)
|
||||
{
|
||||
var type = ActionReference.Target.GetType();
|
||||
|
||||
if (type.Name.StartsWith("<>")
|
||||
&& type.Name.Contains("DisplayClass"))
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine(
|
||||
"You are attempting to register a lambda with a closure without using keepTargetAlive. Are you sure? Check http://galasoft.ch/s/mvvmweakaction for more info.");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -212,7 +249,8 @@ namespace GalaSoft.MvvmLight.Helpers
|
|||
get
|
||||
{
|
||||
if (_staticAction == null
|
||||
&& Reference == null)
|
||||
&& Reference == null
|
||||
&& LiveReference == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
@ -227,7 +265,19 @@ namespace GalaSoft.MvvmLight.Helpers
|
|||
return true;
|
||||
}
|
||||
|
||||
return Reference.IsAlive;
|
||||
// Non static action
|
||||
|
||||
if (LiveReference != null)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (Reference != null)
|
||||
{
|
||||
return Reference.IsAlive;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -255,6 +305,11 @@ namespace GalaSoft.MvvmLight.Helpers
|
|||
{
|
||||
get
|
||||
{
|
||||
if (LiveReference != null)
|
||||
{
|
||||
return LiveReference;
|
||||
}
|
||||
|
||||
if (ActionReference == null)
|
||||
{
|
||||
return null;
|
||||
|
@ -281,11 +336,12 @@ namespace GalaSoft.MvvmLight.Helpers
|
|||
if (IsAlive)
|
||||
{
|
||||
if (Method != null
|
||||
&& ActionReference != null
|
||||
&& (LiveReference != null
|
||||
|| ActionReference != null)
|
||||
&& actionTarget != null)
|
||||
{
|
||||
Method.Invoke(actionTarget, null);
|
||||
|
||||
|
||||
// ReSharper disable RedundantJumpStatement
|
||||
return;
|
||||
// ReSharper restore RedundantJumpStatement
|
||||
|
@ -307,6 +363,7 @@ namespace GalaSoft.MvvmLight.Helpers
|
|||
{
|
||||
Reference = null;
|
||||
ActionReference = null;
|
||||
LiveReference = null;
|
||||
Method = null;
|
||||
_staticAction = null;
|
||||
|
||||
|
|
|
@ -15,9 +15,9 @@
|
|||
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
// ReSharper disable RedundantUsingDirective
|
||||
using System.Reflection;
|
||||
|
||||
// ReSharper restore RedundantUsingDirective
|
||||
|
||||
namespace GalaSoft.MvvmLight.Helpers
|
||||
|
@ -101,8 +101,12 @@ namespace GalaSoft.MvvmLight.Helpers
|
|||
/// Initializes a new instance of the WeakAction class.
|
||||
/// </summary>
|
||||
/// <param name="action">The action that will be associated to this instance.</param>
|
||||
public WeakAction(Action<T> action)
|
||||
: this(action == null ? null : action.Target, action)
|
||||
/// <param name="keepTargetAlive">If true, the target of the Action will
|
||||
/// be kept as a hard reference, which might cause a memory leak. You should only set this
|
||||
/// parameter to true if the action is using closures. See
|
||||
/// http://galasoft.ch/s/mvvmweakaction. </param>
|
||||
public WeakAction(Action<T> action, bool keepTargetAlive = false)
|
||||
: this(action == null ? null : action.Target, action, keepTargetAlive)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -111,12 +115,16 @@ namespace GalaSoft.MvvmLight.Helpers
|
|||
/// </summary>
|
||||
/// <param name="target">The action's owner.</param>
|
||||
/// <param name="action">The action that will be associated to this instance.</param>
|
||||
/// <param name="keepTargetAlive">If true, the target of the Action will
|
||||
/// be kept as a hard reference, which might cause a memory leak. You should only set this
|
||||
/// parameter to true if the action is using closures. See
|
||||
/// http://galasoft.ch/s/mvvmweakaction. </param>
|
||||
[SuppressMessage(
|
||||
"Microsoft.Design",
|
||||
"CA1062:Validate arguments of public methods",
|
||||
"Microsoft.Design",
|
||||
"CA1062:Validate arguments of public methods",
|
||||
MessageId = "1",
|
||||
Justification = "Method should fail with an exception if action is null.")]
|
||||
public WeakAction(object target, Action<T> action)
|
||||
public WeakAction(object target, Action<T> action, bool keepTargetAlive = false)
|
||||
{
|
||||
#if NETFX_CORE
|
||||
if (action.GetMethodInfo().IsStatic)
|
||||
|
@ -157,6 +165,7 @@ namespace GalaSoft.MvvmLight.Helpers
|
|||
{
|
||||
Method = action.Method;
|
||||
ActionReference = new WeakReference(action.Target);
|
||||
LiveReference = keepTargetAlive ? action.Target : null;
|
||||
}
|
||||
}
|
||||
#else
|
||||
|
@ -168,7 +177,24 @@ namespace GalaSoft.MvvmLight.Helpers
|
|||
ActionReference = new WeakReference(action.Target);
|
||||
#endif
|
||||
|
||||
LiveReference = keepTargetAlive ? action.Target : null;
|
||||
Reference = new WeakReference(target);
|
||||
|
||||
#if DEBUG
|
||||
if (ActionReference != null
|
||||
&& ActionReference.Target != null
|
||||
&& !keepTargetAlive)
|
||||
{
|
||||
var type = ActionReference.Target.GetType();
|
||||
|
||||
if (type.Name.StartsWith("<>")
|
||||
&& type.Name.Contains("DisplayClass"))
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine(
|
||||
"You are attempting to register a lambda with a closure without using keepTargetAlive. Are you sure? Check http://galasoft.ch/s/mvvmweakaction for more info.");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -198,7 +224,8 @@ namespace GalaSoft.MvvmLight.Helpers
|
|||
if (IsAlive)
|
||||
{
|
||||
if (Method != null
|
||||
&& ActionReference != null
|
||||
&& (LiveReference != null
|
||||
|| ActionReference != null)
|
||||
&& actionTarget != null)
|
||||
{
|
||||
Method.Invoke(
|
||||
|
@ -228,7 +255,7 @@ namespace GalaSoft.MvvmLight.Helpers
|
|||
/// being casted to T.</param>
|
||||
public void ExecuteWithObject(object parameter)
|
||||
{
|
||||
var parameterCasted = (T) parameter;
|
||||
var parameterCasted = (T)parameter;
|
||||
Execute(parameterCasted);
|
||||
}
|
||||
|
||||
|
|
|
@ -105,6 +105,17 @@ namespace GalaSoft.MvvmLight.Helpers
|
|||
set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Saves the <see cref="FuncReference"/> as a hard reference. This is
|
||||
/// used in relation with this instance's constructor and only if
|
||||
/// the constructor's keepTargetAlive parameter is true.
|
||||
/// </summary>
|
||||
protected object LiveReference
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a WeakReference to the target passed when constructing
|
||||
/// the WeakFunc. This is not necessarily the same as
|
||||
|
@ -128,8 +139,12 @@ namespace GalaSoft.MvvmLight.Helpers
|
|||
/// Initializes a new instance of the WeakFunc class.
|
||||
/// </summary>
|
||||
/// <param name="func">The Func that will be associated to this instance.</param>
|
||||
public WeakFunc(Func<TResult> func)
|
||||
: this(func == null ? null : func.Target, func)
|
||||
/// <param name="keepTargetAlive">If true, the target of the Action will
|
||||
/// be kept as a hard reference, which might cause a memory leak. You should only set this
|
||||
/// parameter to true if the action is using closures. See
|
||||
/// http://galasoft.ch/s/mvvmweakaction. </param>
|
||||
public WeakFunc(Func<TResult> func, bool keepTargetAlive = false)
|
||||
: this(func == null ? null : func.Target, func, keepTargetAlive)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -138,12 +153,16 @@ namespace GalaSoft.MvvmLight.Helpers
|
|||
/// </summary>
|
||||
/// <param name="target">The Func's owner.</param>
|
||||
/// <param name="func">The Func that will be associated to this instance.</param>
|
||||
/// <param name="keepTargetAlive">If true, the target of the Action will
|
||||
/// be kept as a hard reference, which might cause a memory leak. You should only set this
|
||||
/// parameter to true if the action is using closures. See
|
||||
/// http://galasoft.ch/s/mvvmweakaction. </param>
|
||||
[SuppressMessage(
|
||||
"Microsoft.Design",
|
||||
"Microsoft.Design",
|
||||
"CA1062:Validate arguments of public methods",
|
||||
MessageId = "1",
|
||||
Justification = "Method should fail with an exception if func is null.")]
|
||||
public WeakFunc(object target, Func<TResult> func)
|
||||
public WeakFunc(object target, Func<TResult> func, bool keepTargetAlive = false)
|
||||
{
|
||||
#if NETFX_CORE
|
||||
if (func.GetMethodInfo().IsStatic)
|
||||
|
@ -185,6 +204,7 @@ namespace GalaSoft.MvvmLight.Helpers
|
|||
{
|
||||
Method = func.Method;
|
||||
FuncReference = new WeakReference(func.Target);
|
||||
LiveReference = keepTargetAlive ? func.Target : null;
|
||||
}
|
||||
}
|
||||
#else
|
||||
|
@ -196,7 +216,24 @@ namespace GalaSoft.MvvmLight.Helpers
|
|||
FuncReference = new WeakReference(func.Target);
|
||||
#endif
|
||||
|
||||
LiveReference = keepTargetAlive ? func.Target : null;
|
||||
Reference = new WeakReference(target);
|
||||
|
||||
#if DEBUG
|
||||
if (FuncReference != null
|
||||
&& FuncReference.Target != null
|
||||
&& !keepTargetAlive)
|
||||
{
|
||||
var type = FuncReference.Target.GetType();
|
||||
|
||||
if (type.Name.StartsWith("<>")
|
||||
&& type.Name.Contains("DisplayClass"))
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine(
|
||||
"You are attempting to register a lambda with a closure without using keepTargetAlive. Are you sure? Check http://galasoft.ch/s/mvvmweakaction for more info.");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -208,7 +245,8 @@ namespace GalaSoft.MvvmLight.Helpers
|
|||
get
|
||||
{
|
||||
if (_staticFunc == null
|
||||
&& Reference == null)
|
||||
&& Reference == null
|
||||
&& LiveReference == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
@ -223,7 +261,19 @@ namespace GalaSoft.MvvmLight.Helpers
|
|||
return true;
|
||||
}
|
||||
|
||||
return Reference.IsAlive;
|
||||
// Non static action
|
||||
|
||||
if (LiveReference != null)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (Reference != null)
|
||||
{
|
||||
return Reference.IsAlive;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -254,6 +304,11 @@ namespace GalaSoft.MvvmLight.Helpers
|
|||
{
|
||||
get
|
||||
{
|
||||
if (LiveReference != null)
|
||||
{
|
||||
return LiveReference;
|
||||
}
|
||||
|
||||
if (FuncReference == null)
|
||||
{
|
||||
return null;
|
||||
|
@ -280,7 +335,8 @@ namespace GalaSoft.MvvmLight.Helpers
|
|||
if (IsAlive)
|
||||
{
|
||||
if (Method != null
|
||||
&& FuncReference != null
|
||||
&& (LiveReference != null
|
||||
|| FuncReference != null)
|
||||
&& funcTarget != null)
|
||||
{
|
||||
return (TResult)Method.Invoke(funcTarget, null);
|
||||
|
@ -304,6 +360,7 @@ namespace GalaSoft.MvvmLight.Helpers
|
|||
{
|
||||
Reference = null;
|
||||
FuncReference = null;
|
||||
LiveReference = null;
|
||||
Method = null;
|
||||
_staticFunc = null;
|
||||
|
||||
|
|
|
@ -102,8 +102,12 @@ namespace GalaSoft.MvvmLight.Helpers
|
|||
/// Initializes a new instance of the WeakFunc class.
|
||||
/// </summary>
|
||||
/// <param name="func">The Func that will be associated to this instance.</param>
|
||||
public WeakFunc(Func<T, TResult> func)
|
||||
: this(func == null ? null : func.Target, func)
|
||||
/// <param name="keepTargetAlive">If true, the target of the Action will
|
||||
/// be kept as a hard reference, which might cause a memory leak. You should only set this
|
||||
/// parameter to true if the action is using closures. See
|
||||
/// http://galasoft.ch/s/mvvmweakaction. </param>
|
||||
public WeakFunc(Func<T, TResult> func, bool keepTargetAlive = false)
|
||||
: this(func == null ? null : func.Target, func, keepTargetAlive)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -112,12 +116,16 @@ namespace GalaSoft.MvvmLight.Helpers
|
|||
/// </summary>
|
||||
/// <param name="target">The Func's owner.</param>
|
||||
/// <param name="func">The Func that will be associated to this instance.</param>
|
||||
/// <param name="keepTargetAlive">If true, the target of the Action will
|
||||
/// be kept as a hard reference, which might cause a memory leak. You should only set this
|
||||
/// parameter to true if the action is using closures. See
|
||||
/// http://galasoft.ch/s/mvvmweakaction. </param>
|
||||
[SuppressMessage(
|
||||
"Microsoft.Design",
|
||||
"CA1062:Validate arguments of public methods",
|
||||
MessageId = "1",
|
||||
Justification = "Method should fail with an exception if func is null.")]
|
||||
public WeakFunc(object target, Func<T, TResult> func)
|
||||
public WeakFunc(object target, Func<T, TResult> func, bool keepTargetAlive = false)
|
||||
{
|
||||
#if NETFX_CORE
|
||||
if (func.GetMethodInfo().IsStatic)
|
||||
|
@ -158,6 +166,7 @@ namespace GalaSoft.MvvmLight.Helpers
|
|||
{
|
||||
Method = func.Method;
|
||||
FuncReference = new WeakReference(func.Target);
|
||||
LiveReference = keepTargetAlive ? func.Target : null;
|
||||
}
|
||||
}
|
||||
#else
|
||||
|
@ -169,7 +178,24 @@ namespace GalaSoft.MvvmLight.Helpers
|
|||
FuncReference = new WeakReference(func.Target);
|
||||
#endif
|
||||
|
||||
LiveReference = keepTargetAlive ? func.Target : null;
|
||||
Reference = new WeakReference(target);
|
||||
|
||||
#if DEBUG
|
||||
if (FuncReference != null
|
||||
&& FuncReference.Target != null
|
||||
&& !keepTargetAlive)
|
||||
{
|
||||
var type = FuncReference.Target.GetType();
|
||||
|
||||
if (type.Name.StartsWith("<>")
|
||||
&& type.Name.Contains("DisplayClass"))
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine(
|
||||
"You are attempting to register a lambda with a closure without using keepTargetAlive. Are you sure? Check http://galasoft.ch/s/mvvmweakaction for more info.");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -200,7 +226,8 @@ namespace GalaSoft.MvvmLight.Helpers
|
|||
if (IsAlive)
|
||||
{
|
||||
if (Method != null
|
||||
&& FuncReference != null
|
||||
&& (LiveReference != null
|
||||
|| FuncReference != null)
|
||||
&& funcTarget != null)
|
||||
{
|
||||
return (TResult) Method.Invoke(
|
||||
|
|
|
@ -38,7 +38,14 @@ namespace GalaSoft.MvvmLight.Messaging
|
|||
/// <param name="action">The action that will be executed when a message
|
||||
/// of type TMessage is sent. IMPORTANT: Note that closures are not supported at the moment
|
||||
/// due to the use of WeakActions (see http://stackoverflow.com/questions/25730530/). </param>
|
||||
void Register<TMessage>(object recipient, Action<TMessage> action);
|
||||
/// <param name="keepTargetAlive">If true, the target of the Action will
|
||||
/// be kept as a hard reference, which might cause a memory leak. You should only set this
|
||||
/// parameter to true if the action is using closures. See
|
||||
/// http://galasoft.ch/s/mvvmweakaction. </param>
|
||||
void Register<TMessage>(
|
||||
object recipient,
|
||||
Action<TMessage> action,
|
||||
bool keepTargetAlive = false);
|
||||
|
||||
/// <summary>
|
||||
/// Registers a recipient for a type of message TMessage.
|
||||
|
@ -59,9 +66,16 @@ namespace GalaSoft.MvvmLight.Messaging
|
|||
/// get the message. Similarly, messages sent without any token, or with a different
|
||||
/// token, will not be delivered to that recipient.</param>
|
||||
/// <param name="action">The action that will be executed when a message
|
||||
/// of type TMessage is sent. IMPORTANT: Note that closures are not supported at the moment
|
||||
/// due to the use of WeakActions (see http://stackoverflow.com/questions/25730530/). </param>
|
||||
void Register<TMessage>(object recipient, object token, Action<TMessage> action);
|
||||
/// of type TMessage is sent.</param>
|
||||
/// <param name="keepTargetAlive">If true, the target of the Action will
|
||||
/// be kept as a hard reference, which might cause a memory leak. You should only set this
|
||||
/// parameter to true if the action is using closures. See
|
||||
/// http://galasoft.ch/s/mvvmweakaction. </param>
|
||||
void Register<TMessage>(
|
||||
object recipient,
|
||||
object token,
|
||||
Action<TMessage> action,
|
||||
bool keepTargetAlive = false);
|
||||
|
||||
/// <summary>
|
||||
/// Registers a recipient for a type of message TMessage.
|
||||
|
@ -93,9 +107,17 @@ namespace GalaSoft.MvvmLight.Messaging
|
|||
/// and ExecuteOrderMessage to the recipient that registered.</para>
|
||||
/// </param>
|
||||
/// <param name="action">The action that will be executed when a message
|
||||
/// of type TMessage is sent. IMPORTANT: Note that closures are not supported at the moment
|
||||
/// due to the use of WeakActions (see http://stackoverflow.com/questions/25730530/). </param>
|
||||
void Register<TMessage>(object recipient, object token, bool receiveDerivedMessagesToo, Action<TMessage> action);
|
||||
/// of type TMessage is sent.</param>
|
||||
/// <param name="keepTargetAlive">If true, the target of the Action will
|
||||
/// be kept as a hard reference, which might cause a memory leak. You should only set this
|
||||
/// parameter to true if the action is using closures. See
|
||||
/// http://galasoft.ch/s/mvvmweakaction. </param>
|
||||
void Register<TMessage>(
|
||||
object recipient,
|
||||
object token,
|
||||
bool receiveDerivedMessagesToo,
|
||||
Action<TMessage> action,
|
||||
bool keepTargetAlive = false);
|
||||
|
||||
/// <summary>
|
||||
/// Registers a recipient for a type of message TMessage.
|
||||
|
@ -121,9 +143,16 @@ namespace GalaSoft.MvvmLight.Messaging
|
|||
/// and ExecuteOrderMessage to the recipient that registered.</para>
|
||||
/// </param>
|
||||
/// <param name="action">The action that will be executed when a message
|
||||
/// of type TMessage is sent. IMPORTANT: Note that closures are not supported at the moment
|
||||
/// due to the use of WeakActions (see http://stackoverflow.com/questions/25730530/). </param>
|
||||
void Register<TMessage>(object recipient, bool receiveDerivedMessagesToo, Action<TMessage> action);
|
||||
/// of type TMessage is sent.</param>
|
||||
/// <param name="keepTargetAlive">If true, the target of the Action will
|
||||
/// be kept as a hard reference, which might cause a memory leak. You should only set this
|
||||
/// parameter to true if the action is using closures. See
|
||||
/// http://galasoft.ch/s/mvvmweakaction. </param>
|
||||
void Register<TMessage>(
|
||||
object recipient,
|
||||
bool receiveDerivedMessagesToo,
|
||||
Action<TMessage> action,
|
||||
bool keepTargetAlive = false);
|
||||
|
||||
/// <summary>
|
||||
/// Sends a message to registered recipients. The message will
|
||||
|
|
|
@ -43,8 +43,8 @@ namespace GalaSoft.MvvmLight.Messaging
|
|||
/// The Messenger is a class allowing objects to exchange messages.
|
||||
/// </summary>
|
||||
////[ClassInfo(typeof(Messenger),
|
||||
//// VersionString = "5.3.19",
|
||||
//// DateString = "201604212130",
|
||||
//// VersionString = "5.4.21",
|
||||
//// DateString = "201708281410",
|
||||
//// Description = "A messenger class allowing a class to send a message to multiple recipients",
|
||||
//// UrlContacts = "http://www.galasoft.ch/contact_en.html",
|
||||
//// Email = "laurent@galasoft.ch")]
|
||||
|
@ -95,11 +95,18 @@ namespace GalaSoft.MvvmLight.Messaging
|
|||
/// for.</typeparam>
|
||||
/// <param name="recipient">The recipient that will receive the messages.</param>
|
||||
/// <param name="action">The action that will be executed when a message
|
||||
/// of type TMessage is sent. IMPORTANT: Note that closures are not supported at the moment
|
||||
/// due to the use of WeakActions (see http://stackoverflow.com/questions/25730530/). </param>
|
||||
public virtual void Register<TMessage>(object recipient, Action<TMessage> action)
|
||||
/// of type TMessage is sent. IMPORTANT: If the action causes a closure,
|
||||
/// you must set keepTargetAlive to true to avoid side effects. </param>
|
||||
/// <param name="keepTargetAlive">If true, the target of the Action will
|
||||
/// be kept as a hard reference, which might cause a memory leak. You should only set this
|
||||
/// parameter to true if the action is using closures. See
|
||||
/// http://galasoft.ch/s/mvvmweakaction. </param>
|
||||
public virtual void Register<TMessage>(
|
||||
object recipient,
|
||||
Action<TMessage> action,
|
||||
bool keepTargetAlive = false)
|
||||
{
|
||||
Register(recipient, null, false, action);
|
||||
Register(recipient, null, false, action, keepTargetAlive);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -110,35 +117,8 @@ namespace GalaSoft.MvvmLight.Messaging
|
|||
/// messages implementing TMessage) can be received too.
|
||||
/// <para>Registering a recipient does not create a hard reference to it,
|
||||
/// so if this recipient is deleted, no memory leak is caused.</para>
|
||||
/// </summary>
|
||||
/// <typeparam name="TMessage">The type of message that the recipient registers
|
||||
/// for.</typeparam>
|
||||
/// <param name="recipient">The recipient that will receive the messages.</param>
|
||||
/// <param name="receiveDerivedMessagesToo">If true, message types deriving from
|
||||
/// TMessage will also be transmitted to the recipient. For example, if a SendOrderMessage
|
||||
/// and an ExecuteOrderMessage derive from OrderMessage, registering for OrderMessage
|
||||
/// and setting receiveDerivedMessagesToo to true will send SendOrderMessage
|
||||
/// and ExecuteOrderMessage to the recipient that registered.
|
||||
/// <para>Also, if TMessage is an interface, message types implementing TMessage will also be
|
||||
/// transmitted to the recipient. For example, if a SendOrderMessage
|
||||
/// and an ExecuteOrderMessage implement IOrderMessage, registering for IOrderMessage
|
||||
/// and setting receiveDerivedMessagesToo to true will send SendOrderMessage
|
||||
/// and ExecuteOrderMessage to the recipient that registered.</para>
|
||||
/// </param>
|
||||
/// <param name="action">The action that will be executed when a message
|
||||
/// of type TMessage is sent. IMPORTANT: Note that closures are not supported at the moment
|
||||
/// due to the use of WeakActions (see http://stackoverflow.com/questions/25730530/). </param>
|
||||
public virtual void Register<TMessage>(object recipient, bool receiveDerivedMessagesToo, Action<TMessage> action)
|
||||
{
|
||||
Register(recipient, null, receiveDerivedMessagesToo, action);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Registers a recipient for a type of message TMessage.
|
||||
/// The action parameter will be executed when a corresponding
|
||||
/// message is sent.
|
||||
/// <para>Registering a recipient does not create a hard reference to it,
|
||||
/// so if this recipient is deleted, no memory leak is caused.</para>
|
||||
/// <para>However if you use closures and set keepTargetAlive to true, you might
|
||||
/// cause a memory leak if you don't call <see cref="Unregister"/> when you are cleaning up.</para>
|
||||
/// </summary>
|
||||
/// <typeparam name="TMessage">The type of message that the recipient registers
|
||||
/// for.</typeparam>
|
||||
|
@ -150,11 +130,19 @@ namespace GalaSoft.MvvmLight.Messaging
|
|||
/// get the message. Similarly, messages sent without any token, or with a different
|
||||
/// token, will not be delivered to that recipient.</param>
|
||||
/// <param name="action">The action that will be executed when a message
|
||||
/// of type TMessage is sent. IMPORTANT: Note that closures are not supported at the moment
|
||||
/// due to the use of WeakActions (see http://stackoverflow.com/questions/25730530/). </param>
|
||||
public virtual void Register<TMessage>(object recipient, object token, Action<TMessage> action)
|
||||
/// of type TMessage is sent. IMPORTANT: If the action causes a closure,
|
||||
/// you must set keepTargetAlive to true to avoid side effects. </param>
|
||||
/// <param name="keepTargetAlive">If true, the target of the Action will
|
||||
/// be kept as a hard reference, which might cause a memory leak. You should only set this
|
||||
/// parameter to true if the action is using closures. See
|
||||
/// http://galasoft.ch/s/mvvmweakaction. </param>
|
||||
public virtual void Register<TMessage>(
|
||||
object recipient,
|
||||
object token,
|
||||
Action<TMessage> action,
|
||||
bool keepTargetAlive = false)
|
||||
{
|
||||
Register(recipient, token, false, action);
|
||||
Register(recipient, token, false, action, keepTargetAlive);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -187,13 +175,18 @@ namespace GalaSoft.MvvmLight.Messaging
|
|||
/// and ExecuteOrderMessage to the recipient that registered.</para>
|
||||
/// </param>
|
||||
/// <param name="action">The action that will be executed when a message
|
||||
/// of type TMessage is sent. IMPORTANT: Note that closures are not supported at the moment
|
||||
/// due to the use of WeakActions (see http://stackoverflow.com/questions/25730530/). </param>
|
||||
/// of type TMessage is sent. IMPORTANT: If the action causes a closure,
|
||||
/// you must set keepTargetAlive to true to avoid side effects. </param>
|
||||
/// <param name="keepTargetAlive">If true, the target of the Action will
|
||||
/// be kept as a hard reference, which might cause a memory leak. You should only set this
|
||||
/// parameter to true if the action is using closures. See
|
||||
/// http://galasoft.ch/s/mvvmweakaction. </param>
|
||||
public virtual void Register<TMessage>(
|
||||
object recipient,
|
||||
object token,
|
||||
bool receiveDerivedMessagesToo,
|
||||
Action<TMessage> action)
|
||||
Action<TMessage> action,
|
||||
bool keepTargetAlive = false)
|
||||
{
|
||||
lock (_registerLock)
|
||||
{
|
||||
|
@ -234,7 +227,7 @@ namespace GalaSoft.MvvmLight.Messaging
|
|||
list = recipients[messageType];
|
||||
}
|
||||
|
||||
var weakAction = new WeakAction<TMessage>(recipient, action);
|
||||
var weakAction = new WeakAction<TMessage>(recipient, action, keepTargetAlive);
|
||||
|
||||
var item = new WeakActionAndToken
|
||||
{
|
||||
|
@ -249,6 +242,45 @@ namespace GalaSoft.MvvmLight.Messaging
|
|||
RequestCleanup();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Registers a recipient for a type of message TMessage.
|
||||
/// The action parameter will be executed when a corresponding
|
||||
/// message is sent. See the receiveDerivedMessagesToo parameter
|
||||
/// for details on how messages deriving from TMessage (or, if TMessage is an interface,
|
||||
/// messages implementing TMessage) can be received too.
|
||||
/// <para>Registering a recipient does not create a hard reference to it,
|
||||
/// so if this recipient is deleted, no memory leak is caused.</para>
|
||||
/// </summary>
|
||||
/// <typeparam name="TMessage">The type of message that the recipient registers
|
||||
/// for.</typeparam>
|
||||
/// <param name="recipient">The recipient that will receive the messages.</param>
|
||||
/// <param name="receiveDerivedMessagesToo">If true, message types deriving from
|
||||
/// TMessage will also be transmitted to the recipient. For example, if a SendOrderMessage
|
||||
/// and an ExecuteOrderMessage derive from OrderMessage, registering for OrderMessage
|
||||
/// and setting receiveDerivedMessagesToo to true will send SendOrderMessage
|
||||
/// and ExecuteOrderMessage to the recipient that registered.
|
||||
/// <para>Also, if TMessage is an interface, message types implementing TMessage will also be
|
||||
/// transmitted to the recipient. For example, if a SendOrderMessage
|
||||
/// and an ExecuteOrderMessage implement IOrderMessage, registering for IOrderMessage
|
||||
/// and setting receiveDerivedMessagesToo to true will send SendOrderMessage
|
||||
/// and ExecuteOrderMessage to the recipient that registered.</para>
|
||||
/// </param>
|
||||
/// <param name="action">The action that will be executed when a message
|
||||
/// of type TMessage is sent. IMPORTANT: If the action causes a closure,
|
||||
/// you must set keepTargetAlive to true to avoid side effects. </param>
|
||||
/// <param name="keepTargetAlive">If true, the target of the Action will
|
||||
/// be kept as a hard reference, which might cause a memory leak. You should only set this
|
||||
/// parameter to true if the action is using closures. See
|
||||
/// http://galasoft.ch/s/mvvmweakaction. </param>
|
||||
public virtual void Register<TMessage>(
|
||||
object recipient,
|
||||
bool receiveDerivedMessagesToo,
|
||||
Action<TMessage> action,
|
||||
bool keepTargetAlive = false)
|
||||
{
|
||||
Register(recipient, null, receiveDerivedMessagesToo, action, keepTargetAlive);
|
||||
}
|
||||
|
||||
private bool _isCleanupRegistered;
|
||||
|
||||
/// <summary>
|
||||
|
|
Загрузка…
Ссылка в новой задаче