From 7fe21eb40b8048114c153056916076b4097cbaeb Mon Sep 17 00:00:00 2001 From: Antony Male Date: Thu, 24 Sep 2015 15:43:06 +0100 Subject: [PATCH] Turn s:ViewModel into a proper binding, making it vaguely useful --- Stylet/Stylet.csproj | 2 +- Stylet/Xaml/View.cs | 17 +++-- Stylet/Xaml/ViewModelBindingExtension.cs | 96 ++++++++++++++++++++++++ Stylet/Xaml/ViewModelExtension.cs | 35 --------- StyletIntegrationTests/ShellView.xaml | 2 +- 5 files changed, 109 insertions(+), 43 deletions(-) create mode 100644 Stylet/Xaml/ViewModelBindingExtension.cs delete mode 100644 Stylet/Xaml/ViewModelExtension.cs diff --git a/Stylet/Stylet.csproj b/Stylet/Stylet.csproj index 8507806..8b669b3 100644 --- a/Stylet/Stylet.csproj +++ b/Stylet/Stylet.csproj @@ -131,7 +131,7 @@ - + diff --git a/Stylet/Xaml/View.cs b/Stylet/Xaml/View.cs index 396f610..35b0dd0 100644 --- a/Stylet/Xaml/View.cs +++ b/Stylet/Xaml/View.cs @@ -150,6 +150,15 @@ namespace Stylet.Xaml view.Resources[ViewModelProxyResourceKey] = bindingProxy; } + internal static void EnsureViewModelProxyValueSetUp(DependencyObject view) + { + if (view.GetValue(ViewModelProxyProperty) == null) + { + var resource = new DynamicResourceExtension(ViewModelProxyResourceKey).ProvideValue(null); + view.SetValue(ViewModelProxyProperty, resource); + } + } + /// /// Fetch a binding which can be used to retrieve the ViewModel associated with a View /// @@ -157,11 +166,7 @@ namespace Stylet.Xaml /// Binding which can retrieve the ViewModel public static Binding GetBindingToViewModel(DependencyObject view) { - if (view.GetValue(ViewModelProxyProperty) == null) - { - var resource = new DynamicResourceExtension(ViewModelProxyResourceKey).ProvideValue(null); - view.SetValue(ViewModelProxyProperty, resource); - } + EnsureViewModelProxyValueSetUp(view); var binding = new Binding() { @@ -174,7 +179,7 @@ namespace Stylet.Xaml return binding; } - private static readonly DependencyProperty ViewModelProxyProperty = + internal static readonly DependencyProperty ViewModelProxyProperty = DependencyProperty.RegisterAttached("ViewModelProxy", typeof(BindingProxy), typeof(View), new PropertyMetadata(null)); /// diff --git a/Stylet/Xaml/ViewModelBindingExtension.cs b/Stylet/Xaml/ViewModelBindingExtension.cs new file mode 100644 index 0000000..cbe9af3 --- /dev/null +++ b/Stylet/Xaml/ViewModelBindingExtension.cs @@ -0,0 +1,96 @@ +using System; +using System.Globalization; +using System.Windows; +using System.Windows.Data; +using System.Windows.Markup; + +namespace Stylet.Xaml +{ + /// + /// MarkupExtension which can retrieve the ViewModel for the current View, if available + /// + public class ViewModelBindingExtension : MarkupExtension + { + /// + /// Gets or sets the path to the property + /// + public string Path { get; set; } + + /// + /// Gets or sets the converter to use. + /// + public IValueConverter Converter { get; set; } + + /// + /// Gets or sets the culture in which to evaluate the converter. + /// + public CultureInfo ConverterCulture { get; set; } + + /// + /// Gets or sets the parameter to pass to the Converter. + /// + public object ConverterParameter { get; set; } + + /// + /// Gets or sets the value to use when the binding is unable to return a value + /// + public object FallbackValue { get; set; } + + /// + /// Gets or sets a string that specifies how to format the binding if it displays the bound value as a string + /// + public string StringFormat { get; set; } + + /// + /// Gets or sets the value that is used in the target when the value of the source is null + /// + public object TargetNullValue { get; set; } + + /// + /// Instantiates a new instance of the class + /// + public ViewModelBindingExtension() + { + } + + /// + /// Initializes a new instance of the Binding class with an initial path + /// + /// The initial Path for the binding + public ViewModelBindingExtension(string path) + { + this.Path = path; + } + + /// + /// When implemented in a derived class, returns an object that is provided as the + /// value of the target property for this markup extension. + /// + /// A service provider helper that can provide services for the markup extension. + /// The object value to set on the property where the extension is applied. + public override object ProvideValue(IServiceProvider serviceProvider) + { + var valueService = (IProvideValueTarget)serviceProvider.GetService(typeof(IProvideValueTarget)); + var targetObjectAsDependencyObject = valueService.TargetObject as DependencyObject; + if (targetObjectAsDependencyObject == null) + return this; + + View.EnsureViewModelProxyValueSetUp(targetObjectAsDependencyObject); + + var binding = new Binding() + { + Source = targetObjectAsDependencyObject, + Path = new PropertyPath("(0).(1)." + this.Path, View.ViewModelProxyProperty, BindingProxy.DataProperty), + Mode = BindingMode.OneWay, + Converter = this.Converter, + ConverterCulture = this.ConverterCulture, + ConverterParameter = this.ConverterParameter, + FallbackValue = this.FallbackValue, + StringFormat = this.StringFormat, + TargetNullValue = this.TargetNullValue, + }; + + return binding.ProvideValue(serviceProvider); + } + } +} diff --git a/Stylet/Xaml/ViewModelExtension.cs b/Stylet/Xaml/ViewModelExtension.cs deleted file mode 100644 index de499b5..0000000 --- a/Stylet/Xaml/ViewModelExtension.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System; -using System.Windows; -using System.Windows.Markup; - -namespace Stylet.Xaml -{ - /// - /// MarkupExtension which can retrieve the ViewModel for the current View, if available - /// - public class ViewModelExtension : MarkupExtension - { - /// - /// Instantiates a new instance of the class - /// - public ViewModelExtension() - { - } - - /// - /// When implemented in a derived class, returns an object that is provided as the - /// value of the target property for this markup extension. - /// - /// A service provider helper that can provide services for the markup extension. - /// The object value to set on the property where the extension is applied. - public override object ProvideValue(IServiceProvider serviceProvider) - { - var valueService = (IProvideValueTarget)serviceProvider.GetService(typeof(IProvideValueTarget)); - var targetObjectAsDependencyObject = valueService.TargetObject as DependencyObject; - if (targetObjectAsDependencyObject == null) - return this; - - return View.GetBindingToViewModel(targetObjectAsDependencyObject).ProvideValue(serviceProvider); - } - } -} diff --git a/StyletIntegrationTests/ShellView.xaml b/StyletIntegrationTests/ShellView.xaml index bfb0d60..c02b565 100644 --- a/StyletIntegrationTests/ShellView.xaml +++ b/StyletIntegrationTests/ShellView.xaml @@ -51,7 +51,7 @@ Ensure that the label below displays the text "Pass": - +