mirror of https://github.com/AMT-Cheif/Stylet.git
Refactor to add {s:ViewModel}, and use that for actions
This commit is contained in:
parent
540482a5f4
commit
4d767f0364
|
@ -131,6 +131,7 @@
|
|||
<Compile Include="Xaml\View.cs" />
|
||||
<Compile Include="ViewManager.cs" />
|
||||
<Compile Include="WindowManager.cs" />
|
||||
<Compile Include="Xaml\ViewModelExtension.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Page Include="MessageBoxView.xaml">
|
||||
|
|
|
@ -245,8 +245,9 @@ namespace Stylet
|
|||
var viewAsFrameworkElement = view as FrameworkElement;
|
||||
if (viewAsFrameworkElement != null)
|
||||
{
|
||||
logger.Info("Setting {0}'s DataContext to {1}", view, viewModel);
|
||||
logger.Info("Setting {0}'s DataContext and ViewModel proxy to {1}", view, viewModel);
|
||||
viewAsFrameworkElement.DataContext = viewModel;
|
||||
View.SetViewModel(viewAsFrameworkElement, viewModel);
|
||||
}
|
||||
|
||||
var viewModelAsViewAware = viewModel as IViewAware;
|
||||
|
|
|
@ -78,13 +78,7 @@ namespace Stylet.Xaml
|
|||
Mode = BindingMode.OneWay,
|
||||
Source = this.Subject,
|
||||
});
|
||||
multiBinding.Bindings.Add(new Binding()
|
||||
{
|
||||
Path = new PropertyPath(View.BackupActionTargetBindingProxyProperty),
|
||||
Mode = BindingMode.OneWay,
|
||||
Source = this.Subject,
|
||||
Converter = new BindingProxyToValueConverter(),
|
||||
});
|
||||
multiBinding.Bindings.Add(View.GetBindingToViewModel(this.Subject));
|
||||
|
||||
//var binding = new Binding()
|
||||
//{
|
||||
|
|
|
@ -107,11 +107,6 @@ namespace Stylet.Xaml
|
|||
if (targetObjectAsDependencyObject == null)
|
||||
return this;
|
||||
|
||||
// In some cases, the View.ActionTarget attached property won't be propagated - think popups, context menus, KeyBindings, etc
|
||||
// In this case, we can grab a reference to the last-set View.ActionTarget using the dynamic resources mechanism
|
||||
var resourceReference = new DynamicResourceExtension(View.ActionTargetProxyResourceKey).ProvideValue(serviceProvider);
|
||||
targetObjectAsDependencyObject.SetValue(View.BackupActionTargetBindingProxyProperty, resourceReference);
|
||||
|
||||
var propertyAsDependencyProperty = valueService.TargetProperty as DependencyProperty;
|
||||
if (propertyAsDependencyProperty != null && propertyAsDependencyProperty.PropertyType == typeof(ICommand))
|
||||
{
|
||||
|
|
|
@ -28,6 +28,8 @@ namespace Stylet.Xaml
|
|||
|
||||
internal class BindingProxyToValueConverter : IValueConverter
|
||||
{
|
||||
public static readonly BindingProxyToValueConverter Instance = new BindingProxyToValueConverter();
|
||||
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
var proxy = value as BindingProxy;
|
||||
|
|
|
@ -17,7 +17,7 @@ namespace Stylet.Xaml
|
|||
|
||||
internal const string ViewManagerResourceKey = "b9a38199-8cb3-4103-8526-c6cfcd089df7";
|
||||
|
||||
internal const string ActionTargetProxyResourceKey = "8b7cb732-8a14-4813-a580-b1f3cccea7b7";
|
||||
internal const string ViewModelProxyResourceKey = "8b7cb732-8a14-4813-a580-b1f3cccea7b7";
|
||||
|
||||
/// <summary>
|
||||
/// Initial value of the ActionTarget property.
|
||||
|
@ -49,28 +49,7 @@ namespace Stylet.Xaml
|
|||
/// The object's ActionTarget. This is used to determine what object to call Actions on by the ActionExtension markup extension.
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty ActionTargetProperty =
|
||||
DependencyProperty.RegisterAttached("ActionTarget", typeof(object), typeof(View), new FrameworkPropertyMetadata(InitialActionTarget, FrameworkPropertyMetadataOptions.Inherits, (d, e) =>
|
||||
{
|
||||
// Also set a binding proxy if we can, in case there's something weird in the way
|
||||
var frameworkElement = d as FrameworkElement;
|
||||
if (frameworkElement == null)
|
||||
return;
|
||||
|
||||
// Don't set if it's been set already
|
||||
var currentValue = (BindingProxy)d.GetValue(BackupActionTargetBindingProxyProperty);
|
||||
if (currentValue != null && currentValue.Data == e.NewValue)
|
||||
return;
|
||||
|
||||
var bindingProxy = new BindingProxy()
|
||||
{
|
||||
Data = e.NewValue,
|
||||
};
|
||||
frameworkElement.Resources[ActionTargetProxyResourceKey] = bindingProxy;
|
||||
}));
|
||||
|
||||
internal static readonly DependencyProperty BackupActionTargetBindingProxyProperty =
|
||||
DependencyProperty.RegisterAttached("BackupActionTargetBindingProxy", typeof(BindingProxy), typeof(View), new PropertyMetadata(null));
|
||||
|
||||
DependencyProperty.RegisterAttached("ActionTarget", typeof(object), typeof(View), new FrameworkPropertyMetadata(InitialActionTarget));
|
||||
|
||||
/// <summary>
|
||||
/// Fetch the ViewModel currently associated with a given object
|
||||
|
@ -129,6 +108,47 @@ namespace Stylet.Xaml
|
|||
}
|
||||
}));
|
||||
|
||||
/// <summary>
|
||||
/// Set the ViewModel which can be subsequently retrieved using {s:ViewModel}
|
||||
/// </summary>
|
||||
/// <param name="view">View to store the ViewModel for</param>
|
||||
/// <param name="viewModel">ViewModel to store</param>
|
||||
public static void SetViewModel(FrameworkElement view, object viewModel)
|
||||
{
|
||||
var bindingProxy = new BindingProxy()
|
||||
{
|
||||
Data = viewModel,
|
||||
};
|
||||
view.Resources[ViewModelProxyResourceKey] = bindingProxy;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fetch a binding which can be used to retrieve the ViewModel associated with a View
|
||||
/// </summary>
|
||||
/// <param name="view">View to fetch the ViewModel for</param>
|
||||
/// <returns>Binding which can retrieve the ViewModel</returns>
|
||||
public static Binding GetBindingToViewModel(DependencyObject view)
|
||||
{
|
||||
if (view.GetValue(ViewModelProxyProperty) == null)
|
||||
{
|
||||
var resource = new DynamicResourceExtension(ViewModelProxyResourceKey).ProvideValue(null);
|
||||
view.SetValue(ViewModelProxyProperty, resource);
|
||||
}
|
||||
|
||||
var binding = new Binding()
|
||||
{
|
||||
Source = view,
|
||||
Path = new PropertyPath(View.ViewModelProxyProperty),
|
||||
Mode = BindingMode.OneWay,
|
||||
Converter = BindingProxyToValueConverter.Instance,
|
||||
};
|
||||
|
||||
return binding;
|
||||
}
|
||||
|
||||
internal static readonly DependencyProperty ViewModelProxyProperty =
|
||||
DependencyProperty.RegisterAttached("ViewModelProxy", typeof(BindingProxy), typeof(View), new PropertyMetadata(null));
|
||||
|
||||
/// <summary>
|
||||
/// Helper to set the Content property of a given object to a particular View
|
||||
/// </summary>
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Markup;
|
||||
|
||||
namespace Stylet.Xaml
|
||||
{
|
||||
/// <summary>
|
||||
/// MarkupExtension which can retrieve the ViewModel for the current View, if available
|
||||
/// </summary>
|
||||
public class ViewModelExtension : MarkupExtension
|
||||
{
|
||||
/// <summary>
|
||||
/// Instantiates a new instsance of the <see cref="ViewModelExtension"/> class
|
||||
/// </summary>
|
||||
public ViewModelExtension()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// When implemented in a derived class, returns an object that is provided as the
|
||||
/// value of the target property for this markup extension.
|
||||
/// </summary>
|
||||
/// <param name="serviceProvider">A service provider helper that can provide services for the markup extension.</param>
|
||||
/// <returns>The object value to set on the property where the extension is applied.</returns>
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -41,7 +41,7 @@
|
|||
</TextBox.InputBindings>
|
||||
<TextBox.ContextMenu>
|
||||
<ContextMenu>
|
||||
<MenuItem Header="Click Here" Command="{s:Action ShowActionTargetSaved}"/>
|
||||
<MenuItem Header="{Binding Foo}" DataContext="{s:ViewModel}" Command="{s:Action ShowActionTargetSaved}"/>
|
||||
</ContextMenu>
|
||||
</TextBox.ContextMenu>
|
||||
</TextBox>
|
||||
|
|
|
@ -12,6 +12,8 @@ namespace StyletIntegrationTests
|
|||
{
|
||||
private IWindowManager windowManager;
|
||||
|
||||
public string Foo => "Foo";
|
||||
|
||||
public ShellViewModel(IWindowManager windowManager)
|
||||
{
|
||||
this.windowManager = windowManager;
|
||||
|
|
Loading…
Reference in New Issue