mirror of https://github.com/AMT-Cheif/Stylet.git
Playing around with BindingProxy
This commit is contained in:
parent
fc7f164c53
commit
a703659095
|
@ -101,6 +101,7 @@
|
|||
<Compile Include="Xaml\ActionExtension.cs" />
|
||||
<Compile Include="BindableCollection.cs" />
|
||||
<Compile Include="BootstrapperBase.cs" />
|
||||
<Compile Include="Xaml\BindingProxy.cs" />
|
||||
<Compile Include="Xaml\BoolToVisibilityConverter.cs" />
|
||||
<Compile Include="Xaml\CommandAction.cs" />
|
||||
<Compile Include="Conductor.cs" />
|
||||
|
|
|
@ -246,7 +246,7 @@ namespace Stylet
|
|||
if (viewAsFrameworkElement != null)
|
||||
{
|
||||
logger.Info("Setting {0}'s DataContext to {1}", view, viewModel);
|
||||
viewAsFrameworkElement.DataContext = viewModel;
|
||||
View.SetDataContext(viewAsFrameworkElement, viewModel);
|
||||
}
|
||||
|
||||
var viewModelAsViewAware = viewModel as IViewAware;
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
|
||||
namespace Stylet.Xaml
|
||||
{
|
||||
internal class BindingProxy : Freezable
|
||||
{
|
||||
protected override Freezable CreateInstanceCore()
|
||||
{
|
||||
return new BindingProxy();
|
||||
}
|
||||
|
||||
public object Data
|
||||
{
|
||||
get { return (object)GetValue(DataProperty); }
|
||||
set { SetValue(DataProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty DataProperty =
|
||||
DependencyProperty.Register("Data", typeof(object), typeof(BindingProxy), new PropertyMetadata(null));
|
||||
}
|
||||
}
|
|
@ -4,6 +4,7 @@ using System.Windows;
|
|||
using System.Windows.Data;
|
||||
using System.Windows.Markup;
|
||||
using System.Reflection;
|
||||
using Stylet.Logging;
|
||||
|
||||
namespace Stylet.Xaml
|
||||
{
|
||||
|
@ -12,10 +13,13 @@ namespace Stylet.Xaml
|
|||
/// </summary>
|
||||
public static class View
|
||||
{
|
||||
/// <summary>
|
||||
/// Key which will be used to retrieve the ViewManager associated with the current application, from application's resources
|
||||
/// </summary>
|
||||
public const string ViewManagerResourceKey = "b9a38199-8cb3-4103-8526-c6cfcd089df7";
|
||||
private static readonly ILogger logger = LogManager.GetLogger(typeof(View));
|
||||
|
||||
internal const string ViewManagerResourceKey = "b9a38199-8cb3-4103-8526-c6cfcd089df7";
|
||||
|
||||
internal const string ActionTargetProxyResourceKey = "8b7cb732-8a14-4813-a580-b1f3cccea7b7";
|
||||
|
||||
internal const string DataContextProxyResourceKey = "982a3cb4-68b8-464f-9f65-8835d86d94dd";
|
||||
|
||||
/// <summary>
|
||||
/// Initial value of the ActionTarget property.
|
||||
|
@ -30,7 +34,23 @@ namespace Stylet.Xaml
|
|||
/// <returns>ActionTarget associated with the given object</returns>
|
||||
public static object GetActionTarget(DependencyObject obj)
|
||||
{
|
||||
return obj.GetValue(ActionTargetProperty);
|
||||
var actionTarget = obj.GetValue(ActionTargetProperty);
|
||||
|
||||
if (actionTarget == InitialActionTarget)
|
||||
{
|
||||
var frameworkElement = obj as FrameworkElement;
|
||||
if (frameworkElement != null)
|
||||
{
|
||||
var bindingProxy = frameworkElement.TryFindResource(ActionTargetProxyResourceKey) as BindingProxy;
|
||||
if (bindingProxy != null)
|
||||
{
|
||||
logger.Info("ActionTarget not set on object {0}, but a BindingProxy containing an ActionTarget was, so using that", obj);
|
||||
actionTarget = bindingProxy.Data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return actionTarget;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -47,7 +67,20 @@ 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));
|
||||
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;
|
||||
|
||||
var bindingProxy = new BindingProxy()
|
||||
{
|
||||
Data = e.NewValue,
|
||||
};
|
||||
bindingProxy.Freeze();
|
||||
frameworkElement.Resources[ActionTargetProxyResourceKey] = bindingProxy;
|
||||
}));
|
||||
|
||||
/// <summary>
|
||||
/// Fetch the ViewModel currently associated with a given object
|
||||
|
@ -106,6 +139,44 @@ namespace Stylet.Xaml
|
|||
}
|
||||
}));
|
||||
|
||||
|
||||
internal static void SetDataContext(FrameworkElement obj, object value)
|
||||
{
|
||||
obj.DataContext = value;
|
||||
var bindingProxy = new BindingProxy()
|
||||
{
|
||||
Data = value,
|
||||
};
|
||||
obj.Resources[DataContextProxyResourceKey] = bindingProxy;
|
||||
}
|
||||
|
||||
public static bool GetRestoreDataContext(DependencyObject obj)
|
||||
{
|
||||
return (bool)obj.GetValue(RestoreDataContextProperty);
|
||||
}
|
||||
|
||||
public static void SetRestoreDataContext(DependencyObject obj, bool value)
|
||||
{
|
||||
obj.SetValue(RestoreDataContextProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty RestoreDataContextProperty =
|
||||
DependencyProperty.RegisterAttached("RestoreDataContext", typeof(bool), typeof(View), new PropertyMetadata(false, (d, e) =>
|
||||
{
|
||||
if (!(e.NewValue is bool) || !(bool)e.NewValue)
|
||||
return;
|
||||
|
||||
var frameworkElement = d as FrameworkElement;
|
||||
if (frameworkElement == null)
|
||||
return;
|
||||
|
||||
var bindingProxy = frameworkElement.Resources[DataContextProxyResourceKey] as BindingProxy;
|
||||
if (bindingProxy == null)
|
||||
return;
|
||||
|
||||
frameworkElement.DataContext = bindingProxy.Data;
|
||||
}));
|
||||
|
||||
/// <summary>
|
||||
/// Helper to set the Content property of a given object to a particular View
|
||||
/// </summary>
|
||||
|
|
|
@ -6,7 +6,13 @@
|
|||
<DockPanel LastChildFill="False">
|
||||
<GroupBox DockPanel.Dock="Top" Header="ShowDialog and DialogResult" Padding="10">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Button Command="{s:Action ShowDialogAndDialogResult}">Show Dialog</Button>
|
||||
<Button Command="{s:Action ShowDialogAndDialogResult}" Content="Show Dialog">
|
||||
<Button.ContextMenu>
|
||||
<ContextMenu>
|
||||
<MenuItem Header="Foo" Command="{s:Action Foo}"/>
|
||||
</ContextMenu>
|
||||
</Button.ContextMenu>
|
||||
</Button>
|
||||
<TextBlock Margin="50,0,0,0">Result: </TextBlock>
|
||||
<TextBlock Margin="10,0,0,0" Text="{Binding ShowDialogAndDialogResultDialogResult}"/>
|
||||
</StackPanel>
|
||||
|
|
|
@ -5,6 +5,7 @@ using Stylet.Xaml;
|
|||
using System;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Controls.Primitives;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace StyletUnitTests
|
||||
|
@ -51,7 +52,7 @@ namespace StyletUnitTests
|
|||
public void ModelStores()
|
||||
{
|
||||
var obj = new FrameworkElement();
|
||||
obj.Resources.Add(View.ViewManagerResourceKey, this.viewManager.Object);
|
||||
obj.Resources.Add("b9a38199-8cb3-4103-8526-c6cfcd089df7", this.viewManager.Object);
|
||||
View.SetModel(obj, 5);
|
||||
Assert.AreEqual(5, View.GetModel(obj));
|
||||
}
|
||||
|
@ -60,7 +61,7 @@ namespace StyletUnitTests
|
|||
public void ChangingModelCallsOnModelChanged()
|
||||
{
|
||||
var obj = new FrameworkElement();
|
||||
obj.Resources.Add(View.ViewManagerResourceKey, this.viewManager.Object);
|
||||
obj.Resources.Add("b9a38199-8cb3-4103-8526-c6cfcd089df7", this.viewManager.Object);
|
||||
var model = new object();
|
||||
View.SetModel(obj, null);
|
||||
|
||||
|
@ -155,5 +156,26 @@ namespace StyletUnitTests
|
|||
var content = (TextBlock)element.Content;
|
||||
Assert.AreEqual("View for TestViewModel.SubViewModel", content.Text);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ActionTargetIsRestoredAcrossPopupBoundaries()
|
||||
{
|
||||
Execute.InDesignMode = true;
|
||||
|
||||
var userControl = new UserControl();
|
||||
var grid = new Grid();
|
||||
userControl.Content = grid;
|
||||
|
||||
var button = new Button();
|
||||
grid.Children.Add(button);
|
||||
|
||||
var contextMenu = new ContextMenu();
|
||||
button.ContextMenu = contextMenu;
|
||||
|
||||
var actionTarget = new object();
|
||||
|
||||
View.SetActionTarget(userControl, actionTarget);
|
||||
Assert.AreEqual(actionTarget, View.GetActionTarget(button));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue