Added passing EventArgs to Command through EventToCommand if desired.
This commit is contained in:
Laurent Bugnion 2009-11-13 16:16:20 +00:00
Родитель b1c32962da
Коммит 96185b896e
12 изменённых файлов: 563 добавлений и 9 удалений

Двоичные данные
GalaSoft.MvvmLight/External/Silverlight/Microsoft.Silverlight.Testing.dll поставляемый Normal file

Двоичный файл не отображается.

Двоичные данные
GalaSoft.MvvmLight/External/Silverlight/Microsoft.VisualStudio.QualityTools.UnitTesting.Silverlight.dll поставляемый Normal file

Двоичный файл не отображается.

Двоичные данные
GalaSoft.MvvmLight/External/Silverlight/System.Windows.Interactivity.dll поставляемый Normal file

Двоичный файл не отображается.

Двоичные данные
GalaSoft.MvvmLight/External/WPF/System.Windows.Interactivity.dll поставляемый Normal file

Двоичный файл не отображается.

Просмотреть файл

@ -0,0 +1,229 @@
// ****************************************************************************
// <copyright file="EventToCommand.WPF.cs" company="GalaSoft Laurent Bugnion">
// Copyright © GalaSoft Laurent Bugnion 2009
// </copyright>
// ****************************************************************************
// <author>Laurent Bugnion</author>
// <email>laurent@galasoft.ch</email>
// <date>3.11.2009</date>
// <project>GalaSoft.MvvmLight.Extras</project>
// <web>http://www.galasoft.ch</web>
// <license>
// See license.txt in this solution or http://www.galasoft.ch/license_MIT.txt
// </license>
// <LastBaseLevel>BL0001</LastBaseLevel>
// ****************************************************************************
// This partial class contains the WPF-only implementation. See
// EventToCommand.cs for the shared implementation, and EventToCommand.SL.cs
// for the Silverlight-only implementation.
// ****************************************************************************
using System.Windows;
using System.Windows.Input;
namespace GalaSoft.MvvmLight.Command
{
/// <summary>
/// This <see cref="System.Windows.Interactivity.TriggerAction" /> can be
/// used to bind any event on any FrameworkElement to an <see cref="ICommand" />.
/// Typically, this element is used in XAML to connect the attached element
/// to a command located in a ViewModel. This trigger can only be attached
/// to a FrameworkElement or a class deriving from FrameworkElement.
/// </summary>
public partial class EventToCommand
{
/// <summary>
/// Identifies the <see cref="CommandParameter" /> dependency property
/// </summary>
public static readonly DependencyProperty CommandParameterProperty = DependencyProperty.Register(
"CommandParameter",
typeof(object),
typeof(EventToCommand),
new PropertyMetadata(
null,
(s, e) =>
{
var sender = s as EventToCommand;
if (sender == null)
{
return;
}
if (sender.AssociatedObject == null)
{
return;
}
sender.EnableDisableElement();
}));
/// <summary>
/// Identifies the <see cref="Command" /> dependency property
/// </summary>
public static readonly DependencyProperty CommandProperty = DependencyProperty.Register(
"Command",
typeof(ICommand),
typeof(EventToCommand),
new PropertyMetadata(
null,
(s, e) => OnCommandChanged(s as EventToCommand, e)));
/// <summary>
/// Identifies the <see cref="MustToggleIsEnabled" /> dependency property
/// </summary>
public static readonly DependencyProperty MustToggleIsEnabledProperty = DependencyProperty.Register(
"MustToggleIsEnabled",
typeof(bool),
typeof(EventToCommand),
new PropertyMetadata(
false,
(s, e) =>
{
var sender = s as EventToCommand;
if (sender == null)
{
return;
}
if (sender.AssociatedObject == null)
{
return;
}
sender.EnableDisableElement();
}));
private object _commandParameterValue;
private bool? _mustToggleValue;
/// <summary>
/// Gets or sets the ICommand that this trigger is bound to. This
/// is a DependencyProperty.
/// </summary>
public ICommand Command
{
get
{
return (ICommand) GetValue(CommandProperty);
}
set
{
SetValue(CommandProperty, value);
}
}
/// <summary>
/// Gets or sets an object that will be passed to the <see cref="Command" />
/// attached to this trigger. This is a DependencyProperty.
/// </summary>
public object CommandParameter
{
get
{
return this.GetValue(CommandParameterProperty);
}
set
{
SetValue(CommandParameterProperty, value);
}
}
/// <summary>
/// Gets or sets an object that will be passed to the <see cref="Command" />
/// attached to this trigger. This property is here for compatibility
/// with the Silverlight version. This is NOT a DependencyProperty.
/// For databinding, use the <see cref="CommandParameter" /> property.
/// </summary>
public object CommandParameterValue
{
get
{
return this._commandParameterValue ?? this.CommandParameter;
}
set
{
_commandParameterValue = value;
EnableDisableElement();
}
}
/// <summary>
/// Gets or sets a value indicating whether the attached element must be
/// disabled when the <see cref="Command" /> property's CanExecuteChanged
/// event fires. If this property is true, and the command's CanExecute
/// method returns false, the element will be disabled. If this property
/// is false, the element will not be disabled when the command's
/// CanExecute method changes. This is a DependencyProperty.
/// </summary>
public bool MustToggleIsEnabled
{
get
{
return (bool) this.GetValue(MustToggleIsEnabledProperty);
}
set
{
SetValue(MustToggleIsEnabledProperty, value);
}
}
/// <summary>
/// Gets or sets a value indicating whether the attached element must be
/// disabled when the <see cref="Command" /> property's CanExecuteChanged
/// event fires. If this property is true, and the command's CanExecute
/// method returns false, the element will be disabled. This property is here for
/// compatibility with the Silverlight version. This is NOT a DependencyProperty.
/// For databinding, use the <see cref="MustToggleIsEnabled" /> property.
/// </summary>
public bool MustToggleIsEnabledValue
{
get
{
return this._mustToggleValue == null
? this.MustToggleIsEnabled : this._mustToggleValue.Value;
}
set
{
_mustToggleValue = value;
EnableDisableElement();
}
}
/// <summary>
/// Called when this trigger is attached to a FrameworkElement.
/// </summary>
protected override void OnAttached()
{
base.OnAttached();
EnableDisableElement();
}
/// <summary>
/// This method is here for compatibility
/// with the Silverlight version.
/// </summary>
/// <returns>The FrameworkElement to which this trigger
/// is attached.</returns>
private FrameworkElement GetAssociatedObject()
{
return AssociatedObject;
}
/// <summary>
/// This method is here for compatibility
/// with the Silverlight version.
/// </summary>
/// <returns>The command that must be executed when
/// this trigger is invoked.</returns>
private ICommand GetCommand()
{
return Command;
}
}
}

Просмотреть файл

@ -29,17 +29,26 @@ namespace GalaSoft.MvvmLight.Command
/// Typically, this element is used in XAML to connect the attached element
/// to a command located in a ViewModel. This trigger can only be attached
/// to a FrameworkElement or a class deriving from FrameworkElement.
/// <para>To access the EventArgs of the fired event, use a RelayCommand&lt;EventArgs&gt;
/// and leave the CommandParameter and CommandParameterValue empty!</para>
/// </summary>
////[ClassInfo(typeof(EventToCommand),
//// VersionString = "3.0.0.0/BL0001",
//// VersionString = "3.0.0.0/BL0001A",
//// DateString = "200911032343",
//// Description = "A Trigger used to bind any event to an ICommand.",
//// UrlContacts = "http://www.galasoft.ch/contact_en.html",
//// Email = "laurent@galasoft.ch")]
public partial class EventToCommand : TriggerAction<FrameworkElement>
{
public bool PassEventArgsToCommand
{
get;
set;
}
/// <summary>
/// Provides a simple way to invoke this trigger programatically.
/// Provides a simple way to invoke this trigger programatically
/// without any EventArgs.
/// </summary>
public void Invoke()
{
@ -48,8 +57,10 @@ namespace GalaSoft.MvvmLight.Command
/// <summary>
/// Executes the trigger.
/// <para>To access the EventArgs of the fired event, use a RelayCommand&lt;EventArgs&gt;
/// and leave the CommandParameter and CommandParameterValue empty!</para>
/// </summary>
/// <param name="parameter">This parameter is always ignored.</param>
/// <param name="parameter">The EventArgs of the fired event.</param>
protected override void Invoke(object parameter)
{
if (AssociatedElementIsDisabled())
@ -60,6 +71,12 @@ namespace GalaSoft.MvvmLight.Command
var command = GetCommand();
var commandParameter = CommandParameterValue;
if (commandParameter == null
&& PassEventArgsToCommand)
{
commandParameter = parameter;
}
if (command != null
&& command.CanExecute(commandParameter))
{

Просмотреть файл

@ -0,0 +1,47 @@
<StyleCopSettings Version="4.3">
<Parsers>
<Parser ParserId="Microsoft.StyleCop.CSharp.CsParser">
<ParserSettings>
<BooleanProperty Name="AnalyzeDesignerFiles">False</BooleanProperty>
</ParserSettings>
</Parser>
</Parsers>
<Analyzers>
<Analyzer AnalyzerId="Microsoft.StyleCop.CSharp.DocumentationRules">
<AnalyzerSettings>
<BooleanProperty Name="IgnorePrivates">True</BooleanProperty>
<BooleanProperty Name="IgnoreInternals">True</BooleanProperty>
</AnalyzerSettings>
</Analyzer>
<Analyzer AnalyzerId="Microsoft.StyleCop.CSharp.NamingRules">
<Rules>
<Rule Name="FieldNamesMustNotBeginWithUnderscore">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
</Rules>
<AnalyzerSettings />
</Analyzer>
<Analyzer AnalyzerId="Microsoft.StyleCop.CSharp.OrderingRules">
<Rules>
<Rule Name="UsingDirectivesMustBePlacedWithinNamespace">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
</Rules>
<AnalyzerSettings />
</Analyzer>
<Analyzer AnalyzerId="Microsoft.StyleCop.CSharp.ReadabilityRules">
<Rules>
<Rule Name="PrefixLocalCallsWithThis">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
</Rules>
<AnalyzerSettings />
</Analyzer>
</Analyzers>
</StyleCopSettings>

Просмотреть файл

@ -6,6 +6,7 @@ using System.Windows.Shapes;
using GalaSoft.MvvmLight.Command;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Windows.Input;
using System;
namespace GalaSoft.MvvmLight.Test.Command
{
@ -63,6 +64,32 @@ namespace GalaSoft.MvvmLight.Test.Command
Assert.AreEqual(ParameterSent, vm.ParameterReceived);
}
[TestMethod]
public void TestInvokeWithValueParameterNull()
{
var rectangle = new Rectangle();
var trigger = new EventToCommandStub();
((IAttachedObject)trigger).Attach(rectangle);
var vm = new TestViewModel();
var binding = new Binding
{
Source = vm.ParameterCommand
};
#if SILVERLIGHT
trigger.Command = binding;
#else
BindingOperations.SetBinding(trigger, EventToCommand.CommandProperty, binding);
#endif
trigger.CommandParameterValue = null;
trigger.InvokeWithEventArgs(new StringEventArgs("Test"));
Assert.IsTrue(vm.CommandExecuted);
Assert.AreEqual(null, vm.ParameterReceived);
}
[TestMethod]
public void TestInvokeWithBoundParameter()
{
@ -383,6 +410,180 @@ namespace GalaSoft.MvvmLight.Test.Command
#endif
}
[TestMethod]
public void TestInvokeSimpleCommandWithEventArgs()
{
var trigger = new EventToCommandStub();
var rectangle = new Rectangle();
((IAttachedObject)trigger).Attach(rectangle);
trigger.PassEventArgsToCommand = true;
var vm = new TestViewModel();
var binding = new Binding
{
Source = vm.SimpleCommand
};
#if SILVERLIGHT
trigger.Command = binding;
#else
BindingOperations.SetBinding(trigger, EventToCommand.CommandProperty, binding);
#endif
var args = new StringEventArgs("StringEventArgs");
trigger.InvokeWithEventArgs(args);
Assert.IsTrue(vm.CommandExecuted);
Assert.AreEqual(null, vm.ParameterReceived);
}
[TestMethod]
[ExpectedException(typeof(InvalidCastException))]
public void TestInvokeParameterCommandWithEventArgs()
{
var trigger = new EventToCommandStub();
var rectangle = new Rectangle();
((IAttachedObject)trigger).Attach(rectangle);
trigger.PassEventArgsToCommand = true;
var vm = new TestViewModel();
var binding = new Binding
{
Source = vm.ParameterCommand
};
#if SILVERLIGHT
trigger.Command = binding;
#else
BindingOperations.SetBinding(trigger, EventToCommand.CommandProperty, binding);
#endif
var args = new StringEventArgs("StringEventArgs");
trigger.InvokeWithEventArgs(args);
Assert.IsTrue(vm.CommandExecuted);
Assert.AreEqual(args.Parameter, vm.ParameterReceived);
}
[TestMethod]
public void TestInvokeWithEventArgsAndNoParameter()
{
var trigger = new EventToCommandStub();
var rectangle = new Rectangle();
((IAttachedObject)trigger).Attach(rectangle);
trigger.PassEventArgsToCommand = true;
var vm = new TestViewModel();
var binding = new Binding
{
Source = vm.CommandWithEventArgs
};
#if SILVERLIGHT
trigger.Command = binding;
#else
BindingOperations.SetBinding(trigger, EventToCommand.CommandProperty, binding);
#endif
var args = new StringEventArgs("StringEventArgs");
trigger.InvokeWithEventArgs(args);
Assert.IsTrue(vm.CommandExecuted);
Assert.AreEqual(args.Parameter, vm.ParameterReceived);
}
[TestMethod]
public void TestInvokeWithEventArgsAndParameterValue()
{
var trigger = new EventToCommandStub();
var rectangle = new Rectangle();
((IAttachedObject)trigger).Attach(rectangle);
trigger.PassEventArgsToCommand = true;
var vm = new TestViewModel();
var binding = new Binding
{
Source = vm.ParameterCommand
};
#if SILVERLIGHT
trigger.Command = binding;
#else
BindingOperations.SetBinding(trigger, EventToCommand.CommandProperty, binding);
#endif
var commandParameter = "CommandParameter";
trigger.CommandParameterValue = commandParameter;
var args = new StringEventArgs("StringEventArgs");
trigger.InvokeWithEventArgs(args);
Assert.IsTrue(vm.CommandExecuted);
Assert.AreEqual(commandParameter, vm.ParameterReceived);
}
[TestMethod]
public void TestInvokeWithEventArgsAndBoundParameter()
{
var trigger = new EventToCommandStub();
var rectangle = new Rectangle();
((IAttachedObject)trigger).Attach(rectangle);
trigger.PassEventArgsToCommand = true;
var vm = new TestViewModel();
var binding = new Binding
{
Source = vm.ParameterCommand
};
var textBox = new TextBox
{
Text = "BoundParameter"
};
var bindingParameter = new Binding
{
Source = textBox,
Path = new PropertyPath("Text")
};
#if SILVERLIGHT
trigger.Command = binding;
trigger.CommandParameter = bindingParameter;
#else
BindingOperations.SetBinding(trigger, EventToCommand.CommandProperty, binding);
BindingOperations.SetBinding(trigger, EventToCommand.CommandParameterProperty, bindingParameter);
#endif
var args = new StringEventArgs("StringEventArgs");
trigger.InvokeWithEventArgs(args);
Assert.IsTrue(vm.CommandExecuted);
Assert.AreEqual(textBox.Text, vm.ParameterReceived);
}
private class StringEventArgs : EventArgs
{
public string Parameter
{
get;
private set;
}
public StringEventArgs(string parameter)
{
Parameter = parameter;
}
}
private class EventToCommandStub : EventToCommand
{
public void InvokeWithEventArgs(EventArgs args)
{
base.Invoke(args);
}
}
private class TestViewModel : ViewModelBase
{
public bool CommandExecuted
@ -421,6 +622,8 @@ namespace GalaSoft.MvvmLight.Test.Command
set;
}
public RelayCommand<EventArgs> CommandWithEventArgs;
private bool _enableToggledCommand;
public bool EnableToggledCommand
{
@ -456,6 +659,12 @@ namespace GalaSoft.MvvmLight.Test.Command
ParameterReceived = p;
},
p => (p != null && p.StartsWith("Hello")));
CommandWithEventArgs = new RelayCommand<EventArgs>(e =>
{
CommandExecuted = true;
ParameterReceived = ((StringEventArgs)e).Parameter;
});
}
}
}

Просмотреть файл

@ -11,7 +11,7 @@ namespace GalaSoft.MvvmLight.Test.Messaging
public class MessengerSendWithTokenTest
{
[TestMethod]
public void SendWithTokenTest()
public void TestSendWithToken()
{
string receivedContent1 = null;
string receivedContent2 = null;
@ -50,7 +50,7 @@ namespace GalaSoft.MvvmLight.Test.Messaging
}
[TestMethod]
public void SendMessageBaseWithTokenTest()
public void TestSendMessageBaseWithToken()
{
Exception receivedContent1 = null;
Exception receivedContent2 = null;
@ -73,5 +73,30 @@ namespace GalaSoft.MvvmLight.Test.Messaging
Assert.AreEqual(message, receivedContent2);
Assert.IsNull(receivedContent3);
}
[TestMethod]
public void TestSendWithIntToken()
{
InvalidOperationException receivedContent1 = null;
InvalidOperationException receivedContent2 = null;
InvalidOperationException receivedContent3 = null;
Messenger.Reset();
var token1 = 123;
var token2 = 456;
Messenger.Default.Register<InvalidOperationException>(this, m => receivedContent1 = m);
Messenger.Default.Register<InvalidOperationException>(this, token1, m => receivedContent2 = m);
Messenger.Default.Register<InvalidOperationException>(this, token2, m => receivedContent3 = m);
var message = new InvalidOperationException();
Messenger.Default.Send(message, token1);
Assert.IsNull(receivedContent1);
Assert.AreEqual(message, receivedContent2);
Assert.IsNull(receivedContent3);
}
}
}

Просмотреть файл

@ -19,9 +19,23 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GalaSoft.MvvmLight.Extras",
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GalaSoft.MvvmLight.Extras (SL)", "GalaSoft.MvvmLight.Extras (SL)\GalaSoft.MvvmLight.Extras (SL).csproj", "{8ABB3CDF-47C4-468E-9C8A-56491C5F1C7D}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "External", "External", "{02A4F36A-A453-4AA0-B0FD-ED3FFA5FDFB7}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Silverlight", "Silverlight", "{38B6B51B-0A49-460E-ACFE-6944D91221C2}"
ProjectSection(SolutionItems) = preProject
External\Silverlight\Microsoft.Silverlight.Testing.dll = External\Silverlight\Microsoft.Silverlight.Testing.dll
External\Silverlight\Microsoft.VisualStudio.QualityTools.UnitTesting.Silverlight.dll = External\Silverlight\Microsoft.VisualStudio.QualityTools.UnitTesting.Silverlight.dll
External\Silverlight\System.Windows.Interactivity.dll = External\Silverlight\System.Windows.Interactivity.dll
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "WPF", "WPF", "{DA63512E-8316-48D0-BAB8-A41F26ADED6B}"
ProjectSection(SolutionItems) = preProject
External\WPF\System.Windows.Interactivity.dll = External\WPF\System.Windows.Interactivity.dll
EndProjectSection
EndProject
Global
GlobalSection(TeamFoundationVersionControl) = preSolution
SccNumberOfProjects = 5
SccNumberOfProjects = 7
SccEnterpriseProvider = {4CA58AB2-18FA-4F8D-95D4-32DDF27D184C}
SccTeamFoundationServer = https://tfs08.codeplex.com/
SccLocalPath0 = .
@ -37,6 +51,12 @@ Global
SccProjectUniqueName4 = GalaSoft.MvvmLight.Test\\GalaSoft.MvvmLight.Test.csproj
SccProjectName4 = GalaSoft.MvvmLight.Test
SccLocalPath4 = GalaSoft.MvvmLight.Test
SccProjectUniqueName5 = GalaSoft.MvvmLight.Extras\\GalaSoft.MvvmLight.Extras.csproj
SccProjectName5 = GalaSoft.MvvmLight.Extras
SccLocalPath5 = GalaSoft.MvvmLight.Extras
SccProjectUniqueName6 = GalaSoft.MvvmLight.Extras\u0020(SL)\\GalaSoft.MvvmLight.Extras\u0020(SL).csproj
SccProjectName6 = GalaSoft.MvvmLight.Extras\u0020(SL)
SccLocalPath6 = GalaSoft.MvvmLight.Extras\u0020(SL)
EndGlobalSection
GlobalSection(TestCaseManagementSettings) = postSolution
CategoryFile = GalaSoft.MvvmLight.vsmdi
@ -66,8 +86,14 @@ Global
{78EECC01-BAE7-4914-BE2D-6BAB1059F29B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{78EECC01-BAE7-4914-BE2D-6BAB1059F29B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{78EECC01-BAE7-4914-BE2D-6BAB1059F29B}.Release|Any CPU.Build.0 = Release|Any CPU
{8ABB3CDF-47C4-468E-9C8A-56491C5F1C7D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8ABB3CDF-47C4-468E-9C8A-56491C5F1C7D}.Release|Any CPU.ActiveCfg = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{38B6B51B-0A49-460E-ACFE-6944D91221C2} = {02A4F36A-A453-4AA0-B0FD-ED3FFA5FDFB7}
{DA63512E-8316-48D0-BAB8-A41F26ADED6B} = {02A4F36A-A453-4AA0-B0FD-ED3FFA5FDFB7}
EndGlobalSection
EndGlobal

Просмотреть файл

@ -12,7 +12,7 @@
<AssemblyName>GalaSoft.MvvmLight</AssemblyName>
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<SignAssembly>true</SignAssembly>
<SignAssembly>false</SignAssembly>
<AssemblyOriginatorKeyFile>GalaSoft.MvvmLight.snk</AssemblyOriginatorKeyFile>
<SccProjectName>SAK</SccProjectName>
<SccLocalPath>SAK</SccLocalPath>

Просмотреть файл

@ -28,7 +28,7 @@ namespace GalaSoft.MvvmLight.Messaging
/// The Messenger is a class allowing objects to exchange messages.
/// </summary>
////[ClassInfo(typeof(Messenger),
//// VersionString = "3.0.0.0/BL0009",
//// VersionString = "3.0.0.0/BL0009A",
//// DateString = "200910251258",
//// Description = "A messenger class allowing a class to send a message to multiple recipients",
//// UrlContacts = "http://www.galasoft.ch/contact_en.html",
@ -344,7 +344,8 @@ namespace GalaSoft.MvvmLight.Messaging
&& (messageTargetType == null
|| item.Action.Target.GetType() == messageTargetType
|| Implements(item.Action.Target.GetType(), messageTargetType))
&& item.Token == token)
&& ((item.Token == null && token == null)
|| item.Token != null && item.Token.Equals(token)))
{
executeAction.ExecuteWithObject(message);
}