Merge branch 'release/0.9.4'

* release/0.9.4:
  Bump version
  Update changelog
  Re-instate AssemblyVersion and AssemblyFileVersion
  Change stylet namespace to https://github.com/canton7/Stylet
  Rename IPropertyChangedBinding -> IEventBinding
  Remove tests which were no longer relevant, since Bind/BindWeak refactor
  We can't use NotifyCollectionChangedAction.Add or Remove with a list of items, apparently
  Update Actions to support things like Hyperlinks
  Add options to ActionExtension to control the behaviour if target/action are null
  PropertyChangeBase: Don't try to serialize the PropertyChangedDispatcher
  First stab at a proper README
This commit is contained in:
Antony Male 2014-04-23 20:29:40 +01:00
commit 5c5449a0eb
29 changed files with 191 additions and 97 deletions

View File

@ -1,6 +1,14 @@
Stylet Changelog
================
v0.9.4
------
- Fix BindableCollection issues
- ActionExtension has configurable behaviour if target/action are null/not found
- ActionExtension works with things like Hyperlinks
- Misc tweaks and fixes
v0.9.3
------

View File

@ -2,7 +2,7 @@
<package xmlns="http://schemas.microsoft.com/packaging/2011/10/nuspec.xsd">
<metadata>
<id>Stylet</id>
<version>0.9.3</version>
<version>0.9.4</version>
<title>Stylet</title>
<authors>Antony Male</authors>
<owners>Antony Male</owners>

View File

@ -1,6 +1,57 @@
StyletIoC
=========
This project is still in development.
Introduction
------------
[The wiki](https://github.com/canton7/Stylet/wiki/_pages) is the official (incomplete) documentation source.
Blah blah
Installation
------------
You can either grab Stylet through NuGet, or build it from source yourself.
Stylet does rely on .NET 4.5 (Visual Studio 2012 or higher).
### NuGet
[Stylet is available on NuGet](https://www.nuget.org/packages/Stylet).
Either open the package console and type:
```
PM> Install-Package Stylet
```
Or right-click your project -> Manage NuGet Packages... -> Online -> search for Stylet in the top right.
Don't forget to right-click your solution, and click "Enable NuGet package restore"!
I also publish symbols on [SymbolSource](http://www.symbolsource.org/Public), so you can use the NuGet package but still have access to Stylet's source when debugging. If you haven't yet set up Visual Studio to use SymbolSource, do that now:
In Visual Studio, go to Debug -> Options and Settings, and make the following changes:
- Under General, turn **off** "Enable Just My Code"
- Under General, turn **on** "Enable source server support". You may have to Ok a security warning.
- Under Symbols, add "http://srv.symbolsource.org/pdb/Public" to the list.
### Source
I maintain a subtree split of just the Stylet project, [called Stylet-Core](https://github.com/canton7/Stylet-Core).
Head over there, clone/download the repo, and add the .csproj to your solution.
Documentation
-------------
[The wiki is the official documentation source](https://github.com/canton7/Stylet/wiki).
There's a lot of documentation there (it was longer than my dissertation last time I checked), and it's being added to all the time.
Go check it out!
Contributing
------------
Contributions are always welcome.
If you've got a problem or a question, [raise an issue](https://github.com/canton7/Stylet/issues).
If you've got code you want to contribute, create a feature branch off the `develop` branch, add your changes there, and submit it as a pull request.

View File

@ -1,7 +1,7 @@
<Window x:Class="Stylet.Samples.Hello.ShellView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:s="http://github.com/canton7/Stylet"
xmlns:s="https://github.com/canton7/Stylet"
Height="300" Width="300">
<StackPanel>
<TextBox Text="{Binding Name, UpdateSourceTrigger=PropertyChanged}"/>

View File

@ -1,7 +1,7 @@
<Window x:Class="Stylet.Samples.HelloDialog.Dialog1View"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:s="http://github.com/canton7/Stylet"
xmlns:s="https://github.com/canton7/Stylet"
Title="Dialog1View" Height="145" Width="300">
<DockPanel LastChildFill="False" Margin="10">
<DockPanel DockPanel.Dock="Top">

View File

@ -1,7 +1,7 @@
<Window x:Class="Stylet.Samples.HelloDialog.ShellView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:s="http://github.com/canton7/Stylet"
xmlns:s="https://github.com/canton7/Stylet"
Title="ShellView" Height="300" Width="300">
<DockPanel LastChildFill="False" Margin="10">
<DockPanel DockPanel.Dock="Top">

View File

@ -1,7 +1,7 @@
<Window x:Class="Stylet.Samples.MasterDetail.ShellView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:s="http://github.com/canton7/Stylet"
xmlns:s="https://github.com/canton7/Stylet"
Title="ShellView" Height="200" Width="400">
<DockPanel>
<DockPanel DockPanel.Dock="Left">

View File

@ -4,7 +4,7 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:redditapi="clr-namespace:Stylet.Samples.RedditBrowser.RedditApi"
xmlns:s="http://github.com/canton7/Stylet"
xmlns:s="https://github.com/canton7/Stylet"
xmlns:uc="clr-namespace:Stylet.Samples.RedditBrowser.UserControls"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">

View File

@ -3,7 +3,7 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:s="http://github.com/canton7/Stylet"
xmlns:s="https://github.com/canton7/Stylet"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<DockPanel>

View File

@ -1,7 +1,7 @@
<Window x:Class="Stylet.Samples.RedditBrowser.Pages.ShellView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:s="http://github.com/canton7/Stylet"
xmlns:s="https://github.com/canton7/Stylet"
Title="ShellView" Height="500" Width="500">
<DockPanel>
<GroupBox DockPanel.Dock="Top" Header="Navigate to">

View File

@ -3,7 +3,7 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:s="http://github.com/canton7/Stylet"
xmlns:s="https://github.com/canton7/Stylet"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>

View File

@ -3,7 +3,7 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:s="http://github.com/canton7/Stylet"
xmlns:s="https://github.com/canton7/Stylet"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<DockPanel LastChildFill="False">

View File

@ -1,7 +1,7 @@
<Window x:Class="Stylet.Samples.TabNavigation.ShellView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:s="http://github.com/canton7/Stylet"
xmlns:s="https://github.com/canton7/Stylet"
Title="ShellView" Height="300" Width="300">
<Grid>
<TabControl Style="{StaticResource StyletConductorTabControl}"/>

View File

@ -82,7 +82,8 @@ namespace Stylet
this.isNotifying = previousNotificationSetting;
this.OnPropertyChanged(new PropertyChangedEventArgs("Count"));
this.OnPropertyChanged(new PropertyChangedEventArgs("Item[]"));
this.OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, items.ToList()));
// Can't add with a range, or it throws an exception
this.OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
}
/// <summary>
@ -104,7 +105,8 @@ namespace Stylet
this.isNotifying = previousNotificationSetting;
this.OnPropertyChanged(new PropertyChangedEventArgs("Count"));
this.OnPropertyChanged(new PropertyChangedEventArgs("Item[]"));
this.OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, items.ToList()));
// Can't remove with a range, or it throws an exception
this.OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
}
/// <summary>

View File

@ -23,7 +23,7 @@ using System.Windows.Markup;
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("a557a739-6b61-44d2-a431-889bc11aac9e")]
[assembly: XmlnsDefinition("http://github.com/canton7/Stylet", "Stylet")]
[assembly: XmlnsDefinition("https://github.com/canton7/Stylet", "Stylet")]
// Version information for an assembly consists of the following four values:
//
@ -35,5 +35,5 @@ using System.Windows.Markup;
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
//[assembly: AssemblyVersion("1.0.0.0")]
//[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyVersion("0.9.4.0")]
[assembly: AssemblyFileVersion("0.9.4.0")]

View File

@ -18,6 +18,7 @@ namespace Stylet
/// <summary>
/// Dispatcher to use to dispatch PropertyChanged events. Defaults to Execute.DefaultPropertyChangedDispatcher
/// </summary>
[System.Xml.Serialization.XmlIgnore]
public virtual Action<Action> PropertyChangedDispatcher
{
get { return this._propertyChangedDispatcher; }

View File

@ -12,14 +12,14 @@ namespace Stylet
/// <summary>
/// A binding to a PropertyChanged event, which can be used to unbind the binding
/// </summary>
public interface IPropertyChangedBinding
public interface IEventBinding
{
void Unbind();
}
public static class PropertyChangedExtensions
{
internal class StrongPropertyChangedBinding : IPropertyChangedBinding
internal class StrongPropertyChangedBinding : IEventBinding
{
private WeakReference<INotifyPropertyChanged> inpc;
private PropertyChangedEventHandler handler;
@ -48,7 +48,7 @@ namespace Stylet
/// <param name="targetSelector">MemberExpression selecting the property to observe for changes (e.g x => x.PropertyName)</param>
/// <param name="handler">Handler called whenever that property changed</param>
/// <returns>Something which can be used to undo the binding. You can discard it if you want</returns>
public static IPropertyChangedBinding Bind<TBindTo, TMember>(this TBindTo target, Expression<Func<TBindTo, TMember>> targetSelector, Action<TMember> handler) where TBindTo : class, INotifyPropertyChanged
public static IEventBinding Bind<TBindTo, TMember>(this TBindTo target, Expression<Func<TBindTo, TMember>> targetSelector, Action<TMember> handler) where TBindTo : class, INotifyPropertyChanged
{
var propertyName = targetSelector.NameForProperty();
var propertyAccess = targetSelector.Compile();

View File

@ -32,7 +32,7 @@ namespace Stylet
/// <param name="selector">Expression for selecting the property to observe, e.g. x => x.PropertyName</param>
/// <param name="handler">Handler to be called when that property changes</param>
/// <returns>A resource which can be used to undo the binding</returns>
protected IPropertyChangedBinding BindWeak<TSource, TProperty>(TSource source, Expression<Func<TSource, TProperty>> selector, Action<TProperty> handler)
protected IEventBinding BindWeak<TSource, TProperty>(TSource source, Expression<Func<TSource, TProperty>> selector, Action<TProperty> handler)
where TSource : class, INotifyPropertyChanged
{
return this.weakEventManager.BindWeak(source, selector, handler);

View File

@ -10,20 +10,20 @@ namespace Stylet
{
public interface IWeakEventManager
{
IPropertyChangedBinding BindWeak<TSource, TProperty>(TSource source, Expression<Func<TSource, TProperty>> selector, Action<TProperty> handler)
IEventBinding BindWeak<TSource, TProperty>(TSource source, Expression<Func<TSource, TProperty>> selector, Action<TProperty> handler)
where TSource : class, INotifyPropertyChanged;
}
internal class WeakPropertyBinding<TSource, TProperty> : IPropertyChangedBinding where TSource : class, INotifyPropertyChanged
internal class WeakPropertyBinding<TSource, TProperty> : IEventBinding where TSource : class, INotifyPropertyChanged
{
// Make sure we don't end up retaining the source
private readonly WeakReference<TSource> source;
private readonly string propertyName;
private readonly Func<TSource, TProperty> valueSelector;
private readonly Action<TProperty> handler;
private readonly Action<IPropertyChangedBinding> remover;
private readonly Action<IEventBinding> remover;
public WeakPropertyBinding(TSource source, Expression<Func<TSource, TProperty>> selector, Action<TProperty> handler, Action<IPropertyChangedBinding> remover)
public WeakPropertyBinding(TSource source, Expression<Func<TSource, TProperty>> selector, Action<TProperty> handler, Action<IEventBinding> remover)
{
this.source = new WeakReference<TSource>(source);
this.propertyName = selector.NameForProperty();
@ -55,9 +55,9 @@ namespace Stylet
public class WeakEventManager : IWeakEventManager
{
private object bindingsLock = new object();
private List<IPropertyChangedBinding> bindings = new List<IPropertyChangedBinding>();
private List<IEventBinding> bindings = new List<IEventBinding>();
public IPropertyChangedBinding BindWeak<TSource, TProperty>(TSource source, Expression<Func<TSource, TProperty>> selector, Action<TProperty> handler)
public IEventBinding BindWeak<TSource, TProperty>(TSource source, Expression<Func<TSource, TProperty>> selector, Action<TProperty> handler)
where TSource : class, INotifyPropertyChanged
{
// So, the handler's target might point to the class that owns us, or it might point to a compiler-generated class
@ -82,7 +82,7 @@ namespace Stylet
return binding;
}
internal void Remove(IPropertyChangedBinding binding)
internal void Remove(IEventBinding binding)
{
lock (this.bindingsLock)
{

View File

@ -10,6 +10,13 @@ using System.Windows.Markup;
namespace Stylet
{
public enum ActionUnavailableBehaviour
{
Enable,
Disable,
Throw
};
/// <summary>
/// MarkupExtension used for binding Commands and Events to methods on the View.ActionTarget
/// </summary>
@ -20,6 +27,16 @@ namespace Stylet
/// </summary>
public string Method { get; set; }
/// <summary>
/// Behaviour if the View.ActionTarget is nulil
/// </summary>
public ActionUnavailableBehaviour? NullTarget { get; set; }
/// <summary>
/// Behaviour if the action itself isn't found on the View.ActionTarget
/// </summary>
public ActionUnavailableBehaviour? ActionNotFound { get; set; }
/// <summary>
/// Create a new ActionExtension
/// </summary>
@ -35,19 +52,19 @@ namespace Stylet
// Seems this is the case when we're in a template. We'll get called again properly in a second.
// http://social.msdn.microsoft.com/Forums/vstudio/en-US/a9ead3d5-a4e4-4f9c-b507-b7a7d530c6a9/gaining-access-to-target-object-instead-of-shareddp-in-custom-markupextensions-providevalue-method?forum=wpf
if (!(valueService.TargetObject is FrameworkElement))
if (!(valueService.TargetObject is DependencyObject))
return this;
var propertyAsDependencyProperty = valueService.TargetProperty as DependencyProperty;
if (propertyAsDependencyProperty != null && propertyAsDependencyProperty.PropertyType == typeof(ICommand))
{
return new CommandAction((FrameworkElement)valueService.TargetObject, this.Method);
return new CommandAction((DependencyObject)valueService.TargetObject, this.Method, this.NullTarget.GetValueOrDefault(ActionUnavailableBehaviour.Disable), this.ActionNotFound.GetValueOrDefault(ActionUnavailableBehaviour.Throw));
}
var propertyAsEventInfo = valueService.TargetProperty as EventInfo;
if (propertyAsEventInfo != null)
{
var ec = new EventAction((FrameworkElement)valueService.TargetObject, propertyAsEventInfo, this.Method);
var ec = new EventAction((DependencyObject)valueService.TargetObject, propertyAsEventInfo, this.Method, this.NullTarget.GetValueOrDefault(ActionUnavailableBehaviour.Throw), this.ActionNotFound.GetValueOrDefault(ActionUnavailableBehaviour.Throw));
return ec.GetDelegate();
}

View File

@ -26,7 +26,7 @@ namespace Stylet
/// <summary>
/// View to grab the View.ActionTarget from
/// </summary>
public FrameworkElement Subject { get; private set; }
public DependencyObject Subject { get; private set; }
/// <summary>
/// Method name. E.g. if someone's gone Buttom Command="{s:Action MyMethod}", this is MyMethod.
@ -45,15 +45,20 @@ namespace Stylet
private object target;
private ActionUnavailableBehaviour targetNullBehaviour;
private ActionUnavailableBehaviour actionNonExistentBehaviour;
/// <summary>
/// Create a new ActionCommand
/// </summary>
/// <param name="subject">View to grab the View.ActionTarget from</param>
/// <param name="methodName">Method name. the MyMethod in Buttom Command="{s:Action MyMethod}".</param>
public CommandAction(FrameworkElement subject, string methodName)
public CommandAction(DependencyObject subject, string methodName, ActionUnavailableBehaviour targetNullBehaviour, ActionUnavailableBehaviour actionNonExistentBehaviour)
{
this.Subject = subject;
this.MethodName = methodName;
this.targetNullBehaviour = targetNullBehaviour;
this.actionNonExistentBehaviour = actionNonExistentBehaviour;
this.UpdateGuardAndMethod();
@ -72,7 +77,13 @@ namespace Stylet
MethodInfo targetMethodInfo = null;
this.guardPropertyGetter = null;
if (newTarget != null)
if (newTarget == null)
{
// If it's Enable or Disable we don't do anything - CanExecute will handle this
if (this.targetNullBehaviour == ActionUnavailableBehaviour.Throw)
throw new Exception(String.Format("Method {0} has a target set which is null", this.MethodName));
}
else
{
var newTargetType = newTarget.GetType();
@ -86,11 +97,16 @@ namespace Stylet
targetMethodInfo = newTargetType.GetMethod(this.MethodName);
if (targetMethodInfo == null)
throw new ArgumentException(String.Format("Unable to find method {0} on {1}", this.MethodName, newTargetType.Name));
var methodParameters = targetMethodInfo.GetParameters();
if (methodParameters.Length > 1)
throw new ArgumentException(String.Format("Method {0} on {1} must have zero or one parameters", this.MethodName, newTargetType.Name));
{
if (this.actionNonExistentBehaviour == ActionUnavailableBehaviour.Throw)
throw new ArgumentException(String.Format("Unable to find method {0} on {1}", this.MethodName, newTargetType.Name));
}
else
{
var methodParameters = targetMethodInfo.GetParameters();
if (methodParameters.Length > 1)
throw new ArgumentException(String.Format("Method {0} on {1} must have zero or one parameters", this.MethodName, newTargetType.Name));
}
}
var oldTarget = this.target as INotifyPropertyChanged;
@ -125,9 +141,21 @@ namespace Stylet
public bool CanExecute(object parameter)
{
if (this.target == null)
// It's enabled only if both the targetNull and actionNonExistent tests pass
// Throw is handled when the target is set
if (this.target == null && this.targetNullBehaviour == ActionUnavailableBehaviour.Disable)
return false;
// Throw is handled when the target is set
if (this.targetMethodInfo == null)
{
if (this.actionNonExistentBehaviour == ActionUnavailableBehaviour.Disable)
return false;
else
return true;
}
if (this.guardPropertyGetter == null)
return true;
@ -138,10 +166,11 @@ namespace Stylet
public void Execute(object parameter)
{
// This is not going to be called very often, so don't bother to generate a delegate, in the way that we do for the method guard
if (this.target == null)
throw new ArgumentException("Target not set");
// Any throwing would have been handled prior to this
if (this.target == null || this.targetMethodInfo == null)
return;
// This is not going to be called very often, so don't bother to generate a delegate, in the way that we do for the method guard
var parameters = this.targetMethodInfo.GetParameters().Length == 1 ? new[] { parameter } : null;
this.targetMethodInfo.Invoke(this.target, parameters);
}

View File

@ -17,7 +17,7 @@ namespace Stylet
/// <summary>
/// View whose View.ActionTarget we watch
/// </summary>
private FrameworkElement subject;
private DependencyObject subject;
/// <summary>
/// Property on the WPF element we're returning a delegate for
@ -36,17 +36,27 @@ namespace Stylet
private object target;
private ActionUnavailableBehaviour nullTargetBehaviour;
private ActionUnavailableBehaviour actionNonExistentBehaviour;
/// <summary>
/// Create a new EventAction
/// </summary>
/// <param name="subject">View whose View.ActionTarget we watch</param>
/// <param name="targetProperty">Property on the WPF element we're returning a delegate for</param>
/// <param name="methodName">The MyMethod in {s:Action MyMethod}, this is what we call when the event's fired</param>
public EventAction(FrameworkElement subject, EventInfo targetProperty, string methodName)
public EventAction(DependencyObject subject, EventInfo targetProperty, string methodName, ActionUnavailableBehaviour nullTargetBehaviour, ActionUnavailableBehaviour actionNonExistentBehaviour)
{
if (nullTargetBehaviour == ActionUnavailableBehaviour.Disable)
throw new ArgumentException("Setting NullTarget = Disable is unsupported when used on an Event");
if (actionNonExistentBehaviour == ActionUnavailableBehaviour.Disable)
throw new ArgumentException("Setting ActionNotFound = Disable is unsupported when used on an Event");
this.subject = subject;
this.targetProperty = targetProperty;
this.methodName = methodName;
this.nullTargetBehaviour = nullTargetBehaviour;
this.actionNonExistentBehaviour = actionNonExistentBehaviour;
// Observe the View.ActionTarget for changes, and re-bind the guard property and MethodInfo if it changes
DependencyPropertyDescriptor.FromProperty(View.ActionTargetProperty, typeof(View)).AddValueChanged(this.subject, (o, e) => this.UpdateMethod());
@ -57,16 +67,26 @@ namespace Stylet
var newTarget = View.GetActionTarget(this.subject);
MethodInfo targetMethodInfo = null;
if (newTarget != null)
if (newTarget == null)
{
if (this.nullTargetBehaviour == ActionUnavailableBehaviour.Throw)
throw new Exception(String.Format("Method {0} has a target set which is null", this.methodName));
}
else
{
var newTargetType = newTarget.GetType();
targetMethodInfo = newTargetType.GetMethod(this.methodName);
if (targetMethodInfo == null)
throw new ArgumentException(String.Format("Unable to find method {0} on {1}", this.methodName, newTargetType.Name));
var methodParameters = targetMethodInfo.GetParameters();
if (methodParameters.Length > 1 || (methodParameters.Length == 1 && !methodParameters[0].ParameterType.IsAssignableFrom(typeof(RoutedEventArgs))))
throw new ArgumentException(String.Format("Method {0} on {1} must have zero parameters, or a single parameter accepting a RoutedEventArgs", this.methodName, newTargetType.Name));
{
if (this.actionNonExistentBehaviour == ActionUnavailableBehaviour.Throw)
throw new ArgumentException(String.Format("Unable to find method {0} on {1}", this.methodName, newTargetType.Name));
}
else
{
var methodParameters = targetMethodInfo.GetParameters();
if (methodParameters.Length > 1 || (methodParameters.Length == 1 && !methodParameters[0].ParameterType.IsAssignableFrom(typeof(RoutedEventArgs))))
throw new ArgumentException(String.Format("Method {0} on {1} must have zero parameters, or a single parameter accepting a RoutedEventArgs", this.methodName, newTargetType.Name));
}
}
this.target = newTarget;
@ -86,7 +106,8 @@ namespace Stylet
private void InvokeCommand(object sender, RoutedEventArgs e)
{
if (this.target == null)
// Any throwing will have been handled above
if (this.target == null || this.targetMethodInfo == null)
return;
var parameters = this.targetMethodInfo.GetParameters().Length == 1 ? new object[] { e } : null;

View File

@ -1,7 +1,7 @@
<Window x:Class="StyletIntegrationTests.Actions.ActionsView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:s="http://github.com/canton7/Stylet"
xmlns:s="https://github.com/canton7/Stylet"
Title="ActionsView" Height="300" Width="300">
<DockPanel LastChildFill="False">
<GroupBox DockPanel.Dock="Top" Header="CommandAction" Padding="10">

View File

@ -1,7 +1,7 @@
<Window x:Class="StyletIntegrationTests.ShellView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:s="http://github.com/canton7/Stylet"
xmlns:s="https://github.com/canton7/Stylet"
Title="ShellView" Height="500" Width="500">
<DockPanel LastChildFill="False">
<GroupBox DockPanel.Dock="Top" Header="ShowDialog and DialogResult" Padding="10">

View File

@ -1,7 +1,7 @@
<Window x:Class="StyletIntegrationTests.ShowDialogAndDialogResult.DialogView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:s="http://github.com/canton7/Stylet"
xmlns:s="https://github.com/canton7/Stylet"
Title="DialogView" Height="200" Width="300">
<DockPanel Margin="20" LastChildFill="False">
<TextBlock DockPanel.Dock="Top" TextWrapping="Wrap">Choose the desired DialogResult, then close the dialog.</TextBlock>

View File

@ -1,7 +1,7 @@
<Window x:Class="StyletIntegrationTests.WindowDisplayNameBound.WindowView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:s="http://github.com/canton7/Stylet"
xmlns:s="https://github.com/canton7/Stylet"
Title="WindowView" Height="300" Width="300">
<DockPanel Margin="10" LastChildFill="False">
<TextBlock DockPanel.Dock="Top" TextWrapping="WrapWithOverflow">Press the button, and verify that the count in the window title increases. When you are done, close the window.</TextBlock>

View File

@ -1,7 +1,7 @@
<Window x:Class="StyletIntegrationTests.WindowGuardClose.WindowView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:s="http://github.com/canton7/Stylet"
xmlns:s="https://github.com/canton7/Stylet"
Title="WindowView" Height="300" Width="300">
<DockPanel Margin="10">
<TextBlock DockPanel.Dock="Top" TextWrapping="WrapWithOverflow">Leave the checkbox unchecked, then close the window using the red X at the top. It should not close.</TextBlock>

View File

@ -66,8 +66,7 @@ namespace StyletUnitTests
Assert.AreEqual(1, changedEvents.Count);
var changedEvent = changedEvents[0];
Assert.AreEqual(NotifyCollectionChangedAction.Add, changedEvent.Action);
Assert.AreEqual(elementsToAdd, changedEvent.NewItems);
Assert.AreEqual(NotifyCollectionChangedAction.Reset, changedEvent.Action);
}
[Test]
@ -97,8 +96,7 @@ namespace StyletUnitTests
Assert.AreEqual(1, changedEvents.Count);
var changedEvent = changedEvents[0];
Assert.AreEqual(NotifyCollectionChangedAction.Add, changedEvent.Action);
Assert.AreEqual(itemsToRemove, changedEvent.NewItems);
Assert.AreEqual(NotifyCollectionChangedAction.Reset, changedEvent.Action);
}
[Test]

View File

@ -38,13 +38,13 @@ namespace StyletUnitTests
public string LastFoo;
private WeakEventManager weakEventManager = new WeakEventManager();
public IPropertyChangedBinding BindStrong(NotifyingClass notifying)
public IEventBinding BindStrong(NotifyingClass notifying)
{
// Must make sure the compiler doesn't generate an inner class for this, otherwise we're not testing the right thing
return notifying.Bind(x => x.Foo, x => this.LastFoo = x);
}
public IPropertyChangedBinding BindWeak(NotifyingClass notifying)
public IEventBinding BindWeak(NotifyingClass notifying)
{
return this.weakEventManager.BindWeak(notifying, x => x.Foo, x => this.LastFoo = x);
}
@ -84,22 +84,6 @@ namespace StyletUnitTests
Assert.AreEqual("bar", newVal);
}
[Test]
public void StrongBindingRetainsBindingClass()
{
var binding = new BindingClass();
// Means of determining whether the class has been disposed
var weakBinding = new WeakReference<BindingClass>(binding);
var notifying = new NotifyingClass();
binding.BindStrong(notifying);
binding = null;
GC.Collect();
Assert.IsTrue(weakBinding.TryGetTarget(out binding));
}
[Test]
public void StrongBindingDoesNotRetainNotifier()
{
@ -180,23 +164,6 @@ namespace StyletUnitTests
Assert.IsFalse(weakBinding.TryGetTarget(out binding));
}
[Test]
public void WeakBindingRetainsClassIfIPropertyChangedBindingRetained()
{
var binding = new BindingClass();
// Means of determining whether the class has been disposed
var weakBinding = new WeakReference<BindingClass>(binding);
var notifying = new NotifyingClass();
// Retain this
var binder = binding.BindWeak(notifying);
binding = null;
GC.Collect();
Assert.IsTrue(weakBinding.TryGetTarget(out binding));
}
[Test]
public void WeakBindingDoesNotRetainNotifier()
{