mirror of https://github.com/AMT-Cheif/Stylet.git
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:
commit
5c5449a0eb
|
@ -1,6 +1,14 @@
|
||||||
Stylet Changelog
|
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
|
v0.9.3
|
||||||
------
|
------
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
<package xmlns="http://schemas.microsoft.com/packaging/2011/10/nuspec.xsd">
|
<package xmlns="http://schemas.microsoft.com/packaging/2011/10/nuspec.xsd">
|
||||||
<metadata>
|
<metadata>
|
||||||
<id>Stylet</id>
|
<id>Stylet</id>
|
||||||
<version>0.9.3</version>
|
<version>0.9.4</version>
|
||||||
<title>Stylet</title>
|
<title>Stylet</title>
|
||||||
<authors>Antony Male</authors>
|
<authors>Antony Male</authors>
|
||||||
<owners>Antony Male</owners>
|
<owners>Antony Male</owners>
|
||||||
|
|
55
README.md
55
README.md
|
@ -1,6 +1,57 @@
|
||||||
StyletIoC
|
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.
|
|
@ -1,7 +1,7 @@
|
||||||
<Window x:Class="Stylet.Samples.Hello.ShellView"
|
<Window x:Class="Stylet.Samples.Hello.ShellView"
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
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">
|
Height="300" Width="300">
|
||||||
<StackPanel>
|
<StackPanel>
|
||||||
<TextBox Text="{Binding Name, UpdateSourceTrigger=PropertyChanged}"/>
|
<TextBox Text="{Binding Name, UpdateSourceTrigger=PropertyChanged}"/>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<Window x:Class="Stylet.Samples.HelloDialog.Dialog1View"
|
<Window x:Class="Stylet.Samples.HelloDialog.Dialog1View"
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
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">
|
Title="Dialog1View" Height="145" Width="300">
|
||||||
<DockPanel LastChildFill="False" Margin="10">
|
<DockPanel LastChildFill="False" Margin="10">
|
||||||
<DockPanel DockPanel.Dock="Top">
|
<DockPanel DockPanel.Dock="Top">
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<Window x:Class="Stylet.Samples.HelloDialog.ShellView"
|
<Window x:Class="Stylet.Samples.HelloDialog.ShellView"
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
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">
|
Title="ShellView" Height="300" Width="300">
|
||||||
<DockPanel LastChildFill="False" Margin="10">
|
<DockPanel LastChildFill="False" Margin="10">
|
||||||
<DockPanel DockPanel.Dock="Top">
|
<DockPanel DockPanel.Dock="Top">
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<Window x:Class="Stylet.Samples.MasterDetail.ShellView"
|
<Window x:Class="Stylet.Samples.MasterDetail.ShellView"
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
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">
|
Title="ShellView" Height="200" Width="400">
|
||||||
<DockPanel>
|
<DockPanel>
|
||||||
<DockPanel DockPanel.Dock="Left">
|
<DockPanel DockPanel.Dock="Left">
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:redditapi="clr-namespace:Stylet.Samples.RedditBrowser.RedditApi"
|
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"
|
xmlns:uc="clr-namespace:Stylet.Samples.RedditBrowser.UserControls"
|
||||||
mc:Ignorable="d"
|
mc:Ignorable="d"
|
||||||
d:DesignHeight="300" d:DesignWidth="300">
|
d:DesignHeight="300" d:DesignWidth="300">
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
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"
|
mc:Ignorable="d"
|
||||||
d:DesignHeight="300" d:DesignWidth="300">
|
d:DesignHeight="300" d:DesignWidth="300">
|
||||||
<DockPanel>
|
<DockPanel>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<Window x:Class="Stylet.Samples.RedditBrowser.Pages.ShellView"
|
<Window x:Class="Stylet.Samples.RedditBrowser.Pages.ShellView"
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
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">
|
Title="ShellView" Height="500" Width="500">
|
||||||
<DockPanel>
|
<DockPanel>
|
||||||
<GroupBox DockPanel.Dock="Top" Header="Navigate to">
|
<GroupBox DockPanel.Dock="Top" Header="Navigate to">
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
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"
|
mc:Ignorable="d"
|
||||||
d:DesignHeight="300" d:DesignWidth="300">
|
d:DesignHeight="300" d:DesignWidth="300">
|
||||||
<Grid>
|
<Grid>
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
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"
|
mc:Ignorable="d"
|
||||||
d:DesignHeight="300" d:DesignWidth="300">
|
d:DesignHeight="300" d:DesignWidth="300">
|
||||||
<DockPanel LastChildFill="False">
|
<DockPanel LastChildFill="False">
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<Window x:Class="Stylet.Samples.TabNavigation.ShellView"
|
<Window x:Class="Stylet.Samples.TabNavigation.ShellView"
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
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">
|
Title="ShellView" Height="300" Width="300">
|
||||||
<Grid>
|
<Grid>
|
||||||
<TabControl Style="{StaticResource StyletConductorTabControl}"/>
|
<TabControl Style="{StaticResource StyletConductorTabControl}"/>
|
||||||
|
|
|
@ -82,7 +82,8 @@ namespace Stylet
|
||||||
this.isNotifying = previousNotificationSetting;
|
this.isNotifying = previousNotificationSetting;
|
||||||
this.OnPropertyChanged(new PropertyChangedEventArgs("Count"));
|
this.OnPropertyChanged(new PropertyChangedEventArgs("Count"));
|
||||||
this.OnPropertyChanged(new PropertyChangedEventArgs("Item[]"));
|
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>
|
/// <summary>
|
||||||
|
@ -104,7 +105,8 @@ namespace Stylet
|
||||||
this.isNotifying = previousNotificationSetting;
|
this.isNotifying = previousNotificationSetting;
|
||||||
this.OnPropertyChanged(new PropertyChangedEventArgs("Count"));
|
this.OnPropertyChanged(new PropertyChangedEventArgs("Count"));
|
||||||
this.OnPropertyChanged(new PropertyChangedEventArgs("Item[]"));
|
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>
|
/// <summary>
|
||||||
|
|
|
@ -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
|
// 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: 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:
|
// 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
|
// You can specify all the values or you can default the Build and Revision Numbers
|
||||||
// by using the '*' as shown below:
|
// by using the '*' as shown below:
|
||||||
// [assembly: AssemblyVersion("1.0.*")]
|
// [assembly: AssemblyVersion("1.0.*")]
|
||||||
//[assembly: AssemblyVersion("1.0.0.0")]
|
[assembly: AssemblyVersion("0.9.4.0")]
|
||||||
//[assembly: AssemblyFileVersion("1.0.0.0")]
|
[assembly: AssemblyFileVersion("0.9.4.0")]
|
||||||
|
|
|
@ -18,6 +18,7 @@ namespace Stylet
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Dispatcher to use to dispatch PropertyChanged events. Defaults to Execute.DefaultPropertyChangedDispatcher
|
/// Dispatcher to use to dispatch PropertyChanged events. Defaults to Execute.DefaultPropertyChangedDispatcher
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
[System.Xml.Serialization.XmlIgnore]
|
||||||
public virtual Action<Action> PropertyChangedDispatcher
|
public virtual Action<Action> PropertyChangedDispatcher
|
||||||
{
|
{
|
||||||
get { return this._propertyChangedDispatcher; }
|
get { return this._propertyChangedDispatcher; }
|
||||||
|
|
|
@ -12,14 +12,14 @@ namespace Stylet
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A binding to a PropertyChanged event, which can be used to unbind the binding
|
/// A binding to a PropertyChanged event, which can be used to unbind the binding
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IPropertyChangedBinding
|
public interface IEventBinding
|
||||||
{
|
{
|
||||||
void Unbind();
|
void Unbind();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class PropertyChangedExtensions
|
public static class PropertyChangedExtensions
|
||||||
{
|
{
|
||||||
internal class StrongPropertyChangedBinding : IPropertyChangedBinding
|
internal class StrongPropertyChangedBinding : IEventBinding
|
||||||
{
|
{
|
||||||
private WeakReference<INotifyPropertyChanged> inpc;
|
private WeakReference<INotifyPropertyChanged> inpc;
|
||||||
private PropertyChangedEventHandler handler;
|
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="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>
|
/// <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>
|
/// <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 propertyName = targetSelector.NameForProperty();
|
||||||
var propertyAccess = targetSelector.Compile();
|
var propertyAccess = targetSelector.Compile();
|
||||||
|
|
|
@ -32,7 +32,7 @@ namespace Stylet
|
||||||
/// <param name="selector">Expression for selecting the property to observe, e.g. x => x.PropertyName</param>
|
/// <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>
|
/// <param name="handler">Handler to be called when that property changes</param>
|
||||||
/// <returns>A resource which can be used to undo the binding</returns>
|
/// <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
|
where TSource : class, INotifyPropertyChanged
|
||||||
{
|
{
|
||||||
return this.weakEventManager.BindWeak(source, selector, handler);
|
return this.weakEventManager.BindWeak(source, selector, handler);
|
||||||
|
|
|
@ -10,20 +10,20 @@ namespace Stylet
|
||||||
{
|
{
|
||||||
public interface IWeakEventManager
|
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;
|
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
|
// Make sure we don't end up retaining the source
|
||||||
private readonly WeakReference<TSource> source;
|
private readonly WeakReference<TSource> source;
|
||||||
private readonly string propertyName;
|
private readonly string propertyName;
|
||||||
private readonly Func<TSource, TProperty> valueSelector;
|
private readonly Func<TSource, TProperty> valueSelector;
|
||||||
private readonly Action<TProperty> handler;
|
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.source = new WeakReference<TSource>(source);
|
||||||
this.propertyName = selector.NameForProperty();
|
this.propertyName = selector.NameForProperty();
|
||||||
|
@ -55,9 +55,9 @@ namespace Stylet
|
||||||
public class WeakEventManager : IWeakEventManager
|
public class WeakEventManager : IWeakEventManager
|
||||||
{
|
{
|
||||||
private object bindingsLock = new object();
|
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
|
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
|
// 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;
|
return binding;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void Remove(IPropertyChangedBinding binding)
|
internal void Remove(IEventBinding binding)
|
||||||
{
|
{
|
||||||
lock (this.bindingsLock)
|
lock (this.bindingsLock)
|
||||||
{
|
{
|
||||||
|
|
|
@ -10,6 +10,13 @@ using System.Windows.Markup;
|
||||||
|
|
||||||
namespace Stylet
|
namespace Stylet
|
||||||
{
|
{
|
||||||
|
public enum ActionUnavailableBehaviour
|
||||||
|
{
|
||||||
|
Enable,
|
||||||
|
Disable,
|
||||||
|
Throw
|
||||||
|
};
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// MarkupExtension used for binding Commands and Events to methods on the View.ActionTarget
|
/// MarkupExtension used for binding Commands and Events to methods on the View.ActionTarget
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -20,6 +27,16 @@ namespace Stylet
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string Method { get; set; }
|
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>
|
/// <summary>
|
||||||
/// Create a new ActionExtension
|
/// Create a new ActionExtension
|
||||||
/// </summary>
|
/// </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.
|
// 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
|
// 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;
|
return this;
|
||||||
|
|
||||||
var propertyAsDependencyProperty = valueService.TargetProperty as DependencyProperty;
|
var propertyAsDependencyProperty = valueService.TargetProperty as DependencyProperty;
|
||||||
if (propertyAsDependencyProperty != null && propertyAsDependencyProperty.PropertyType == typeof(ICommand))
|
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;
|
var propertyAsEventInfo = valueService.TargetProperty as EventInfo;
|
||||||
if (propertyAsEventInfo != null)
|
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();
|
return ec.GetDelegate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,7 @@ namespace Stylet
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// View to grab the View.ActionTarget from
|
/// View to grab the View.ActionTarget from
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public FrameworkElement Subject { get; private set; }
|
public DependencyObject Subject { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Method name. E.g. if someone's gone Buttom Command="{s:Action MyMethod}", this is MyMethod.
|
/// 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 object target;
|
||||||
|
|
||||||
|
private ActionUnavailableBehaviour targetNullBehaviour;
|
||||||
|
private ActionUnavailableBehaviour actionNonExistentBehaviour;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Create a new ActionCommand
|
/// Create a new ActionCommand
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="subject">View to grab the View.ActionTarget from</param>
|
/// <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>
|
/// <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.Subject = subject;
|
||||||
this.MethodName = methodName;
|
this.MethodName = methodName;
|
||||||
|
this.targetNullBehaviour = targetNullBehaviour;
|
||||||
|
this.actionNonExistentBehaviour = actionNonExistentBehaviour;
|
||||||
|
|
||||||
this.UpdateGuardAndMethod();
|
this.UpdateGuardAndMethod();
|
||||||
|
|
||||||
|
@ -72,7 +77,13 @@ namespace Stylet
|
||||||
MethodInfo targetMethodInfo = null;
|
MethodInfo targetMethodInfo = null;
|
||||||
|
|
||||||
this.guardPropertyGetter = 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();
|
var newTargetType = newTarget.GetType();
|
||||||
|
|
||||||
|
@ -86,11 +97,16 @@ namespace Stylet
|
||||||
|
|
||||||
targetMethodInfo = newTargetType.GetMethod(this.MethodName);
|
targetMethodInfo = newTargetType.GetMethod(this.MethodName);
|
||||||
if (targetMethodInfo == null)
|
if (targetMethodInfo == null)
|
||||||
throw new ArgumentException(String.Format("Unable to find method {0} on {1}", this.MethodName, newTargetType.Name));
|
{
|
||||||
|
if (this.actionNonExistentBehaviour == ActionUnavailableBehaviour.Throw)
|
||||||
var methodParameters = targetMethodInfo.GetParameters();
|
throw new ArgumentException(String.Format("Unable to find method {0} on {1}", this.MethodName, newTargetType.Name));
|
||||||
if (methodParameters.Length > 1)
|
}
|
||||||
throw new ArgumentException(String.Format("Method {0} on {1} must have zero or one parameters", 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;
|
var oldTarget = this.target as INotifyPropertyChanged;
|
||||||
|
@ -125,9 +141,21 @@ namespace Stylet
|
||||||
|
|
||||||
public bool CanExecute(object parameter)
|
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;
|
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)
|
if (this.guardPropertyGetter == null)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
@ -138,10 +166,11 @@ namespace Stylet
|
||||||
|
|
||||||
public void Execute(object parameter)
|
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
|
// Any throwing would have been handled prior to this
|
||||||
if (this.target == null)
|
if (this.target == null || this.targetMethodInfo == null)
|
||||||
throw new ArgumentException("Target not set");
|
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;
|
var parameters = this.targetMethodInfo.GetParameters().Length == 1 ? new[] { parameter } : null;
|
||||||
this.targetMethodInfo.Invoke(this.target, parameters);
|
this.targetMethodInfo.Invoke(this.target, parameters);
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,7 @@ namespace Stylet
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// View whose View.ActionTarget we watch
|
/// View whose View.ActionTarget we watch
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private FrameworkElement subject;
|
private DependencyObject subject;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Property on the WPF element we're returning a delegate for
|
/// Property on the WPF element we're returning a delegate for
|
||||||
|
@ -36,17 +36,27 @@ namespace Stylet
|
||||||
|
|
||||||
private object target;
|
private object target;
|
||||||
|
|
||||||
|
private ActionUnavailableBehaviour nullTargetBehaviour;
|
||||||
|
private ActionUnavailableBehaviour actionNonExistentBehaviour;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Create a new EventAction
|
/// Create a new EventAction
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="subject">View whose View.ActionTarget we watch</param>
|
/// <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="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>
|
/// <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.subject = subject;
|
||||||
this.targetProperty = targetProperty;
|
this.targetProperty = targetProperty;
|
||||||
this.methodName = methodName;
|
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
|
// 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());
|
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);
|
var newTarget = View.GetActionTarget(this.subject);
|
||||||
MethodInfo targetMethodInfo = null;
|
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();
|
var newTargetType = newTarget.GetType();
|
||||||
targetMethodInfo = newTargetType.GetMethod(this.methodName);
|
targetMethodInfo = newTargetType.GetMethod(this.methodName);
|
||||||
if (targetMethodInfo == null)
|
if (targetMethodInfo == null)
|
||||||
throw new ArgumentException(String.Format("Unable to find method {0} on {1}", this.methodName, newTargetType.Name));
|
{
|
||||||
|
if (this.actionNonExistentBehaviour == ActionUnavailableBehaviour.Throw)
|
||||||
var methodParameters = targetMethodInfo.GetParameters();
|
throw new ArgumentException(String.Format("Unable to find method {0} on {1}", this.methodName, newTargetType.Name));
|
||||||
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));
|
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;
|
this.target = newTarget;
|
||||||
|
@ -86,7 +106,8 @@ namespace Stylet
|
||||||
|
|
||||||
private void InvokeCommand(object sender, RoutedEventArgs e)
|
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;
|
return;
|
||||||
|
|
||||||
var parameters = this.targetMethodInfo.GetParameters().Length == 1 ? new object[] { e } : null;
|
var parameters = this.targetMethodInfo.GetParameters().Length == 1 ? new object[] { e } : null;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<Window x:Class="StyletIntegrationTests.Actions.ActionsView"
|
<Window x:Class="StyletIntegrationTests.Actions.ActionsView"
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
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">
|
Title="ActionsView" Height="300" Width="300">
|
||||||
<DockPanel LastChildFill="False">
|
<DockPanel LastChildFill="False">
|
||||||
<GroupBox DockPanel.Dock="Top" Header="CommandAction" Padding="10">
|
<GroupBox DockPanel.Dock="Top" Header="CommandAction" Padding="10">
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<Window x:Class="StyletIntegrationTests.ShellView"
|
<Window x:Class="StyletIntegrationTests.ShellView"
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
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">
|
Title="ShellView" Height="500" Width="500">
|
||||||
<DockPanel LastChildFill="False">
|
<DockPanel LastChildFill="False">
|
||||||
<GroupBox DockPanel.Dock="Top" Header="ShowDialog and DialogResult" Padding="10">
|
<GroupBox DockPanel.Dock="Top" Header="ShowDialog and DialogResult" Padding="10">
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<Window x:Class="StyletIntegrationTests.ShowDialogAndDialogResult.DialogView"
|
<Window x:Class="StyletIntegrationTests.ShowDialogAndDialogResult.DialogView"
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
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">
|
Title="DialogView" Height="200" Width="300">
|
||||||
<DockPanel Margin="20" LastChildFill="False">
|
<DockPanel Margin="20" LastChildFill="False">
|
||||||
<TextBlock DockPanel.Dock="Top" TextWrapping="Wrap">Choose the desired DialogResult, then close the dialog.</TextBlock>
|
<TextBlock DockPanel.Dock="Top" TextWrapping="Wrap">Choose the desired DialogResult, then close the dialog.</TextBlock>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<Window x:Class="StyletIntegrationTests.WindowDisplayNameBound.WindowView"
|
<Window x:Class="StyletIntegrationTests.WindowDisplayNameBound.WindowView"
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
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">
|
Title="WindowView" Height="300" Width="300">
|
||||||
<DockPanel Margin="10" LastChildFill="False">
|
<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>
|
<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>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<Window x:Class="StyletIntegrationTests.WindowGuardClose.WindowView"
|
<Window x:Class="StyletIntegrationTests.WindowGuardClose.WindowView"
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
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">
|
Title="WindowView" Height="300" Width="300">
|
||||||
<DockPanel Margin="10">
|
<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>
|
<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>
|
||||||
|
|
|
@ -66,8 +66,7 @@ namespace StyletUnitTests
|
||||||
|
|
||||||
Assert.AreEqual(1, changedEvents.Count);
|
Assert.AreEqual(1, changedEvents.Count);
|
||||||
var changedEvent = changedEvents[0];
|
var changedEvent = changedEvents[0];
|
||||||
Assert.AreEqual(NotifyCollectionChangedAction.Add, changedEvent.Action);
|
Assert.AreEqual(NotifyCollectionChangedAction.Reset, changedEvent.Action);
|
||||||
Assert.AreEqual(elementsToAdd, changedEvent.NewItems);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
|
@ -97,8 +96,7 @@ namespace StyletUnitTests
|
||||||
|
|
||||||
Assert.AreEqual(1, changedEvents.Count);
|
Assert.AreEqual(1, changedEvents.Count);
|
||||||
var changedEvent = changedEvents[0];
|
var changedEvent = changedEvents[0];
|
||||||
Assert.AreEqual(NotifyCollectionChangedAction.Add, changedEvent.Action);
|
Assert.AreEqual(NotifyCollectionChangedAction.Reset, changedEvent.Action);
|
||||||
Assert.AreEqual(itemsToRemove, changedEvent.NewItems);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
|
|
|
@ -38,13 +38,13 @@ namespace StyletUnitTests
|
||||||
public string LastFoo;
|
public string LastFoo;
|
||||||
private WeakEventManager weakEventManager = new WeakEventManager();
|
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
|
// 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);
|
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);
|
return this.weakEventManager.BindWeak(notifying, x => x.Foo, x => this.LastFoo = x);
|
||||||
}
|
}
|
||||||
|
@ -84,22 +84,6 @@ namespace StyletUnitTests
|
||||||
Assert.AreEqual("bar", newVal);
|
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]
|
[Test]
|
||||||
public void StrongBindingDoesNotRetainNotifier()
|
public void StrongBindingDoesNotRetainNotifier()
|
||||||
{
|
{
|
||||||
|
@ -180,23 +164,6 @@ namespace StyletUnitTests
|
||||||
Assert.IsFalse(weakBinding.TryGetTarget(out binding));
|
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]
|
[Test]
|
||||||
public void WeakBindingDoesNotRetainNotifier()
|
public void WeakBindingDoesNotRetainNotifier()
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue