This repository has been archived by the owner on Sep 20, 2021. It is now read-only.
/
RelayCommand.cs
232 lines (213 loc) · 9.4 KB
/
RelayCommand.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
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
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
// <copyright file="RelayCommand.cs" company="GalaSoft Laurent Bugnion">
// Copyright © GalaSoft Laurent Bugnion 2009-2016
// </copyright>
// ****************************************************************************
// <author>Laurent Bugnion</author>
// <email>laurent@galasoft.ch</email>
// <date>22.4.2009</date>
// <project>GalaSoft.MvvmLight</project>
// <web>http://www.mvvmlight.net</web>
// <license>
// See license.txt in this project or http://www.galasoft.ch/license_MIT.txt
// </license>
// ****************************************************************************
// <credits>This class was developed by Josh Smith (http://joshsmithonwpf.wordpress.com) and
// slightly modified with his permission.</credits>
// ****************************************************************************
using System;
using System.Diagnostics.CodeAnalysis;
using System.Windows.Input;
#if !NET_FXCORE
using GalaSoft.MvvmLight.Helpers;
#endif
////using GalaSoft.Utilities.Attributes;
#if PLATFORMNET45
namespace GalaSoft.MvvmLight.CommandWpf
#else
namespace GalaSoft.MvvmLight.Command
#endif
{
/// <summary>
/// A command whose sole purpose is to relay its functionality to other
/// objects by invoking delegates. The default return value for the CanExecute
/// method is 'true'. This class does not allow you to accept command parameters in the
/// Execute and CanExecute callback methods.
/// </summary>
/// <remarks>If you are using this class in WPF4.5 or above, you need to use the
/// GalaSoft.MvvmLight.CommandWpf namespace (instead of 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.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")]
public class RelayCommand : ICommand
{
private readonly WeakAction _execute;
private readonly WeakFunc<bool> _canExecute;
/// <summary>
/// Initializes a new instance of the RelayCommand class that
/// can always execute.
/// </summary>
/// <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, bool keepTargetAlive = false)
: this(execute, null, keepTargetAlive)
{
}
/// <summary>
/// Initializes a new instance of the RelayCommand class.
/// </summary>
/// <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, keepTargetAlive);
if (canExecute != null)
{
_canExecute = new WeakFunc<bool>(canExecute, keepTargetAlive);
}
}
#if SILVERLIGHT
/// <summary>
/// Occurs when changes occur that affect whether the command should execute.
/// </summary>
public event EventHandler CanExecuteChanged;
#elif NETFX_CORE
/// <summary>
/// Occurs when changes occur that affect whether the command should execute.
/// </summary>
public event EventHandler CanExecuteChanged;
#elif XAMARIN
/// <summary>
/// Occurs when changes occur that affect whether the command should execute.
/// </summary>
public event EventHandler CanExecuteChanged;
#else
private EventHandler _requerySuggestedLocal;
/// <summary>
/// Occurs when changes occur that affect whether the command should execute.
/// </summary>
public event EventHandler CanExecuteChanged
{
add
{
if (_canExecute != null)
{
// add event handler to local handler backing field in a thread safe manner
EventHandler handler2;
EventHandler canExecuteChanged = _requerySuggestedLocal;
do
{
handler2 = canExecuteChanged;
EventHandler handler3 = (EventHandler)Delegate.Combine(handler2, value);
canExecuteChanged = System.Threading.Interlocked.CompareExchange<EventHandler>(
ref _requerySuggestedLocal,
handler3,
handler2);
}
while (canExecuteChanged != handler2);
CommandManager.RequerySuggested += value;
}
}
remove
{
if (_canExecute != null)
{
// removes an event handler from local backing field in a thread safe manner
EventHandler handler2;
EventHandler canExecuteChanged = this._requerySuggestedLocal;
do
{
handler2 = canExecuteChanged;
EventHandler handler3 = (EventHandler)Delegate.Remove(handler2, value);
canExecuteChanged = System.Threading.Interlocked.CompareExchange<EventHandler>(
ref this._requerySuggestedLocal,
handler3,
handler2);
}
while (canExecuteChanged != handler2);
CommandManager.RequerySuggested -= value;
}
}
}
#endif
/// <summary>
/// Raises the <see cref="CanExecuteChanged" /> event.
/// </summary>
[SuppressMessage(
"Microsoft.Performance",
"CA1822:MarkMembersAsStatic",
Justification = "The this keyword is used in the Silverlight version")]
[SuppressMessage(
"Microsoft.Design",
"CA1030:UseEventsWhereAppropriate",
Justification = "This cannot be an event")]
public void RaiseCanExecuteChanged()
{
#if SILVERLIGHT
var handler = CanExecuteChanged;
if (handler != null)
{
handler(this, EventArgs.Empty);
}
#elif NETFX_CORE
var handler = CanExecuteChanged;
if (handler != null)
{
handler(this, EventArgs.Empty);
}
#elif XAMARIN
var handler = CanExecuteChanged;
if (handler != null)
{
handler(this, EventArgs.Empty);
}
#else
CommandManager.InvalidateRequerySuggested();
#endif
}
/// <summary>
/// Defines the method that determines whether the command can execute in its current state.
/// </summary>
/// <param name="parameter">This parameter will always be ignored.</param>
/// <returns>true if this command can be executed; otherwise, false.</returns>
public bool CanExecute(object parameter)
{
return _canExecute == null
|| (_canExecute.IsStatic || _canExecute.IsAlive)
&& _canExecute.Execute();
}
/// <summary>
/// Defines the method to be called when the command is invoked.
/// </summary>
/// <param name="parameter">This parameter will always be ignored.</param>
public virtual void Execute(object parameter)
{
if (CanExecute(parameter)
&& _execute != null
&& (_execute.IsStatic || _execute.IsAlive))
{
_execute.Execute();
}
}
}
}