From 89ce861dd9e94fb378ff2348188c774deb97b5a2 Mon Sep 17 00:00:00 2001 From: Manuel Naujoks Date: Wed, 11 Nov 2015 22:26:48 +0100 Subject: [PATCH 1/2] command binding to methods --- CalcBinding/CalcBinding.cs | 11 +++++++- CalcBinding/CalcBinding.csproj | 1 + CalcBinding/DataContextMethodCommand.cs | 34 +++++++++++++++++++++++++ Tests/CalcBindingSystemTests.cs | 30 ++++++++++++++++++++++ WpfExample/ExampleViewModel.cs | 18 +++++++++++++ WpfExample/FifthPage.xaml | 20 +++++++++++++++ WpfExample/FifthPage.xaml.cs | 28 ++++++++++++++++++++ WpfExample/MainWindow.xaml | 13 ++++++---- WpfExample/WpfExample.csproj | 7 +++++ 9 files changed, 156 insertions(+), 6 deletions(-) create mode 100644 CalcBinding/DataContextMethodCommand.cs create mode 100644 WpfExample/FifthPage.xaml create mode 100644 WpfExample/FifthPage.xaml.cs diff --git a/CalcBinding/CalcBinding.cs b/CalcBinding/CalcBinding.cs index 3ac7de1..b8f1153 100644 --- a/CalcBinding/CalcBinding.cs +++ b/CalcBinding/CalcBinding.cs @@ -49,7 +49,16 @@ public override object ProvideValue(IServiceProvider serviceProvider) BindingBase resBinding; - if (sourcePropertiesPathesWithPositions.Count() == 1) + if (sourcePropertiesPathesWithPositions.Count == 1 && expressionTemplate == "{0}()") + { + var methodName = sourcePropertiesPathesWithPositions.Single().Item1; + + var targetProvider = (IProvideValueTarget)serviceProvider.GetService(typeof(IProvideValueTarget)); + var targetObject = targetProvider.TargetObject as FrameworkElement; + + return new DataContextMethodCommand(methodName, targetObject); + } + else if (sourcePropertiesPathesWithPositions.Count() == 1) { var binding = new System.Windows.Data.Binding(sourcePropertiesPathesWithPositions.Single().Item1) { diff --git a/CalcBinding/CalcBinding.csproj b/CalcBinding/CalcBinding.csproj index f26a50b..d8e08e8 100644 --- a/CalcBinding/CalcBinding.csproj +++ b/CalcBinding/CalcBinding.csproj @@ -69,6 +69,7 @@ + diff --git a/CalcBinding/DataContextMethodCommand.cs b/CalcBinding/DataContextMethodCommand.cs new file mode 100644 index 0000000..94f5b63 --- /dev/null +++ b/CalcBinding/DataContextMethodCommand.cs @@ -0,0 +1,34 @@ +using System; +using System.Windows; +using System.Windows.Input; + +namespace CalcBinding +{ + public class DataContextMethodCommand : ICommand + { + string _methodName; + FrameworkElement _targetObject; + + public DataContextMethodCommand(string methodName, FrameworkElement targetObject) + { + _methodName = methodName; + _targetObject = targetObject; + } + + public event EventHandler CanExecuteChanged; + + public bool CanExecute(object parameter) + { + return true; + } + + public void Execute(object parameter) + { + //get DataContext as late as possible to execute on the correct instance + var dataContext = _targetObject.DataContext; + var dataContextType = dataContext.GetType(); + var dataContextMethod = dataContextType.GetMethod(_methodName); + dataContextMethod.Invoke(dataContext, null); + } + } +} diff --git a/Tests/CalcBindingSystemTests.cs b/Tests/CalcBindingSystemTests.cs index 08d7c5d..a01a89b 100644 --- a/Tests/CalcBindingSystemTests.cs +++ b/Tests/CalcBindingSystemTests.cs @@ -744,6 +744,36 @@ public void BindingToPropertyContainingDigits() ); } + [TestMethod] + public void BindingToMethod() + { + var viewModel1 = new ExampleViewModel(); + var viewModel2 = new ExampleViewModel(); + Assert.IsFalse(viewModel1.ClickMethodInvoked); + Assert.IsFalse(viewModel2.ClickMethodInvoked); + + var button = new Button(); + button.DataContext = viewModel1; + + var calcBinding = new CalcBinding.Binding("ClickMethod()"); + var bindingExpression = calcBinding.ProvideValue(new ServiceProviderMock(button, Button.CommandProperty)); + + button.SetValue(Button.CommandProperty, bindingExpression); + var command = button.GetValue(Button.CommandProperty) as System.Windows.Input.ICommand; + command.Execute(null); + + Assert.IsTrue(viewModel1.ClickMethodInvoked); + Assert.IsFalse(viewModel2.ClickMethodInvoked); + + button.DataContext = viewModel2; + command = button.GetValue(Button.CommandProperty) as System.Windows.Input.ICommand; + command.Execute(null); + + Assert.IsTrue(viewModel1.ClickMethodInvoked); + Assert.IsTrue(viewModel2.ClickMethodInvoked); + } + + #region Convert public void StringAndObjectBindingAssert(string path, INotifyPropertyChanged source, diff --git a/WpfExample/ExampleViewModel.cs b/WpfExample/ExampleViewModel.cs index 4a9fb98..187064c 100644 --- a/WpfExample/ExampleViewModel.cs +++ b/WpfExample/ExampleViewModel.cs @@ -170,6 +170,24 @@ public ConcreteViewModel2(int a) /// public class ExampleViewModel : BaseViewModel { + private bool clickMethodInvoked; + public bool ClickMethodInvoked + { + get { return clickMethodInvoked; } + set + { + clickMethodInvoked = value; + + new object().TraceTime( + () => RaisePropertyChanged(() => ClickMethodInvoked) + ); + } + } + public void ClickMethod() + { + ClickMethodInvoked = !ClickMethodInvoked; + } + private double a = 10; public double A { diff --git a/WpfExample/FifthPage.xaml b/WpfExample/FifthPage.xaml new file mode 100644 index 0000000..d092230 --- /dev/null +++ b/WpfExample/FifthPage.xaml @@ -0,0 +1,20 @@ + + + + + + + + + +