Browse Source

Merge remote-tracking branch 'refs/remotes/origin/master' into leaks

pull/366/head
Steven Kirk 11 years ago
parent
commit
6adc946ed4
  1. 2
      nuget/build.ps1
  2. 5
      samples/BindingTest/BindingTest.csproj
  3. 8
      samples/BindingTest/MainWindow.paml
  4. 3
      samples/BindingTest/TestUserControl.paml
  5. 18
      samples/BindingTest/TestUserControl.paml.cs
  6. 1
      samples/BindingTest/ViewModels/MainWindowViewModel.cs
  7. 9
      samples/BindingTest/ViewModels/TestUserControlViewModel.cs
  8. 22
      src/Markup/Perspex.Markup.Xaml/Data/Binding.cs
  9. 2
      src/Markup/Perspex.Markup.Xaml/OmniXAML
  10. 2
      src/Markup/Perspex.Markup/Data/ExpressionObserver.cs
  11. 68
      src/Perspex.Controls/Presenters/ScrollContentPresenter.cs
  12. 7
      src/Perspex.SceneGraph/IVisual.cs
  13. 19
      src/Perspex.SceneGraph/Visual.cs
  14. 1
      src/Perspex.Themes.Default/DefaultTheme.paml
  15. 3
      src/Perspex.Themes.Default/Perspex.Themes.Default.csproj
  16. 16
      src/Perspex.Themes.Default/ToolTip.paml
  17. 50
      src/Windows/Perspex.Designer/AppHost/WindowHost.cs
  18. 2
      src/Windows/Perspex.Designer/InProcDesigner/InProcDesignerView.xaml.cs
  19. 2
      src/Windows/Perspex.Designer/PerspexDesigner.xaml
  20. 36
      src/Windows/Perspex.Designer/PerspexDesigner.xaml.cs
  21. 21
      tests/Perspex.Markup.Xaml.UnitTests/Data/BindingTests.cs

2
nuget/build.ps1

@ -1 +1 @@
.\build-version.ps1 0.1.1-alpha2
.\build-version.ps1 0.2.0-alpha3

5
samples/BindingTest/BindingTest.csproj

@ -79,6 +79,10 @@
<DependentUpon>MainWindow.paml</DependentUpon>
</Compile>
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="TestUserControl.paml.cs">
<DependentUpon>TestUserControl.paml</DependentUpon>
</Compile>
<Compile Include="ViewModels\TestUserControlViewModel.cs" />
<Compile Include="ViewModels\MainWindowViewModel.cs" />
<Compile Include="ViewModels\TestItem.cs" />
</ItemGroup>
@ -89,6 +93,7 @@
<Generator>MSBuild:Compile</Generator>
</EmbeddedResource>
<None Include="packages.config" />
<EmbeddedResource Include="TestUserControl.paml" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\Markup\Perspex.Markup.Xaml\Perspex.Markup.Xaml.csproj">

8
samples/BindingTest/MainWindow.paml

@ -1,5 +1,6 @@
<Window xmlns="https://github.com/perspex"
xmlns:vm="clr-namespace:BindingTest.ViewModels;assembly=BindingTest">
xmlns:vm="clr-namespace:BindingTest.ViewModels;assembly=BindingTest"
xmlns:local="clr-namespace:BindingTest;assembly=BindingTest">
<TabControl>
<TabItem Header="Basic">
<StackPanel Orientation="Vertical">
@ -55,5 +56,10 @@
</StackPanel>
</StackPanel>
</TabItem>
<TabItem Header="UserControl">
<local:TestUserControl DataContext="{Binding UserControl}"
HorizontalAlignment="Center"
VerticalAlignment="Center"/>
</TabItem>
</TabControl>
</Window>

3
samples/BindingTest/TestUserControl.paml

@ -0,0 +1,3 @@
<UserControl xmlns="https://github.com/perspex">
<TextBlock Text="{Binding Content}"/>
</UserControl>

18
samples/BindingTest/TestUserControl.paml.cs

@ -0,0 +1,18 @@
using Perspex.Controls;
using Perspex.Markup.Xaml;
namespace BindingTest
{
public class TestUserControl : UserControl
{
public TestUserControl()
{
this.InitializeComponent();
}
private void InitializeComponent()
{
PerspexXamlLoader.Load(this);
}
}
}

1
samples/BindingTest/ViewModels/MainWindowViewModel.cs

@ -32,6 +32,7 @@ namespace BindingTest.ViewModels
public ObservableCollection<TestItem> Items { get; }
public ObservableCollection<TestItem> SelectedItems { get; }
public ReactiveCommand<object> ShuffleItems { get; }
public TestUserControlViewModel UserControl { get; } = new TestUserControlViewModel();
public string BooleanString
{

9
samples/BindingTest/ViewModels/TestUserControlViewModel.cs

@ -0,0 +1,9 @@
using ReactiveUI;
namespace BindingTest.ViewModels
{
public class TestUserControlViewModel : ReactiveObject
{
public string Content { get; } = "User Control Content";
}
}

22
src/Markup/Perspex.Markup.Xaml/Data/Binding.cs

@ -214,22 +214,28 @@ namespace Perspex.Markup.Xaml.Data
{
Contract.Requires<ArgumentNullException>(target != null);
var dataContextHost = targetIsDataContext ?
target.InheritanceParent as IObservablePropertyBag : target;
if (dataContextHost != null)
if (!targetIsDataContext)
{
var result = new ExpressionObserver(
() => dataContextHost.GetValue(Control.DataContextProperty),
() => target.GetValue(Control.DataContextProperty),
path);
dataContextHost.GetObservable(Control.DataContextProperty).Subscribe(x =>
/// TODO: Instead of doing this, make the ExpressionObserver accept an "update"
/// observable as doing it this way can will cause a leak in Binding as this
/// observable is never unsubscribed.
target.GetObservable(Control.DataContextProperty).Subscribe(x =>
result.UpdateRoot());
return result;
}
else
{
throw new InvalidOperationException(
"Cannot bind to DataContext of object with no parent.");
return new ExpressionObserver(
target.GetObservable(Visual.VisualParentProperty)
.OfType<IObservablePropertyBag>()
.Select(x => x.GetObservable(Control.DataContextProperty))
.Switch(),
path);
}
}

2
src/Markup/Perspex.Markup.Xaml/OmniXAML

@ -1 +1 @@
Subproject commit 3e3b46ba66941da925092e2977003d0553cfc907
Subproject commit f2673838c0422ff0f6fdb3e4b34a5302971f59b5

2
src/Markup/Perspex.Markup/Data/ExpressionObserver.cs

@ -172,6 +172,8 @@ namespace Perspex.Markup.Data
/// <summary>
/// Causes the root object to be re-read from the root getter.
/// </summary>
/// TODO: Instead of doing this, make the object accept an "update" observable
/// as doing it this way can cause a leak in Binding.
public void UpdateRoot()
{
if (_count > 0 && _rootGetter != null)

68
src/Perspex.Controls/Presenters/ScrollContentPresenter.cs

@ -98,48 +98,52 @@ namespace Perspex.Controls.Presenters
/// <returns>True if the scroll offset was changed; otherwise false.</returns>
public bool BringDescendentIntoView(IVisual target, Rect targetRect)
{
if (Child != null)
if (Child == null)
{
var transform = target.TransformToVisual(Child);
var rect = targetRect * transform;
var offset = Offset;
var result = false;
return false;
}
if (rect.Bottom > offset.Y + Viewport.Height)
{
offset = offset.WithY((rect.Bottom - Viewport.Height) + Child.Margin.Top);
result = true;
}
var transform = target.TransformToVisual(Child);
if (rect.Y < offset.Y)
{
offset = offset.WithY(rect.Y);
result = true;
}
if (transform == null)
{
return false;
}
if (rect.Right > offset.X + Viewport.Width)
{
offset = offset.WithX((rect.Right - Viewport.Width) + Child.Margin.Left);
result = true;
}
var rect = targetRect * transform.Value;
var offset = Offset;
var result = false;
if (rect.X < offset.X)
{
offset = offset.WithX(rect.X);
result = true;
}
if (rect.Bottom > offset.Y + Viewport.Height)
{
offset = offset.WithY((rect.Bottom - Viewport.Height) + Child.Margin.Top);
result = true;
}
if (result)
{
Offset = offset;
}
if (rect.Y < offset.Y)
{
offset = offset.WithY(rect.Y);
result = true;
}
return result;
if (rect.Right > offset.X + Viewport.Width)
{
offset = offset.WithX((rect.Right - Viewport.Width) + Child.Margin.Left);
result = true;
}
else
if (rect.X < offset.X)
{
return false;
offset = offset.WithX(rect.X);
result = true;
}
if (result)
{
Offset = offset;
}
return result;
}
/// <inheritdoc/>

7
src/Perspex.SceneGraph/IVisual.cs

@ -97,7 +97,10 @@ namespace Perspex
/// of the specified <paramref name="visual"/>.
/// </summary>
/// <param name="visual">The visual to translate the coordinates to.</param>
/// <returns>A <see cref="Matrix"/> containing the transform.</returns>
Matrix TransformToVisual(IVisual visual);
/// <returns>
/// A <see cref="Matrix"/> containing the transform or null if the visuals don't share a
/// common ancestor.
/// </returns>
Matrix? TransformToVisual(IVisual visual);
}
}

19
src/Perspex.SceneGraph/Visual.cs

@ -300,13 +300,22 @@ namespace Perspex
/// of the specified <paramref name="visual"/>.
/// </summary>
/// <param name="visual">The visual to translate the coordinates to.</param>
/// <returns>A <see cref="Matrix"/> containing the transform.</returns>
public Matrix TransformToVisual(IVisual visual)
/// <returns>
/// A <see cref="Matrix"/> containing the transform or null if the visuals don't share a
/// common ancestor.
/// </returns>
public Matrix? TransformToVisual(IVisual visual)
{
var common = this.FindCommonVisualAncestor(visual);
var thisOffset = GetOffsetFrom(common, this);
var thatOffset = GetOffsetFrom(common, visual);
return Matrix.CreateTranslation(-thatOffset) * Matrix.CreateTranslation(thisOffset);
if (common != null)
{
var thisOffset = GetOffsetFrom(common, this);
var thatOffset = GetOffsetFrom(common, visual);
return Matrix.CreateTranslation(-thatOffset) * Matrix.CreateTranslation(thisOffset);
}
return null;
}
/// <summary>

1
src/Perspex.Themes.Default/DefaultTheme.paml

@ -23,6 +23,7 @@
<StyleInclude Source="resource://application/Perspex.Themes.Default/Perspex.Themes.Default.TabStrip.paml"/>
<StyleInclude Source="resource://application/Perspex.Themes.Default/Perspex.Themes.Default.TextBox.paml"/>
<StyleInclude Source="resource://application/Perspex.Themes.Default/Perspex.Themes.Default.ToggleButton.paml"/>
<StyleInclude Source="resource://application/Perspex.Themes.Default/Perspex.Themes.Default.ToolTip.paml"/>
<StyleInclude Source="resource://application/Perspex.Themes.Default/Perspex.Themes.Default.TreeView.paml"/>
<StyleInclude Source="resource://application/Perspex.Themes.Default/Perspex.Themes.Default.TreeViewItem.paml"/>
<StyleInclude Source="resource://application/Perspex.Themes.Default/Perspex.Themes.Default.Window.paml"/>

3
src/Perspex.Themes.Default/Perspex.Themes.Default.csproj

@ -140,6 +140,9 @@
<EmbeddedResource Include="ProgressBar.paml">
<SubType>Designer</SubType>
</EmbeddedResource>
<EmbeddedResource Include="ToolTip.paml">
<SubType>Designer</SubType>
</EmbeddedResource>
<None Include="packages.config" />
<EmbeddedResource Include="PopupRoot.paml">
<SubType>Designer</SubType>

16
src/Perspex.Themes.Default/ToolTip.paml

@ -0,0 +1,16 @@
<Style xmlns="https://github.com/perspex" Selector="ToolTip">
<Setter Property="BorderBrush" Value="Gray"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="Padding" Value="4,2"/>
<Setter Property="Template">
<ControlTemplate>
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<ContentPresenter Name="PART_ContentPresenter"
Content="{TemplateBinding Content}"
Margin="{TemplateBinding Padding}"/>
</Border>
</ControlTemplate>
</Setter>
</Style>

50
src/Windows/Perspex.Designer/AppHost/WindowHost.cs

@ -11,15 +11,22 @@ namespace Perspex.Designer.AppHost
{
class WindowHost : UserControl
{
public WindowHost()
private readonly bool _supportScroll;
public WindowHost(bool supportScroll)
{
AutoScroll = true;
VerticalScroll.Enabled = true;
HorizontalScroll.Enabled = true;
_supportScroll = supportScroll;
if (_supportScroll)
{
AutoScroll = true;
VerticalScroll.Enabled = true;
HorizontalScroll.Enabled = true;
}
SetStyle(ControlStyles.AllPaintingInWmPaint, true);
Text = "ScrollableArea";
Controls.Add(_windowHost);
_windowHost.Anchor = AnchorStyles.None;
if (!supportScroll)
_windowHost.Visible = false;
_timer.Tick += delegate
{
ReloadSettings();
@ -93,7 +100,7 @@ namespace Perspex.Designer.AppHost
_hWnd = hWnd;
if (_hWnd != IntPtr.Zero)
{
WinApi.SetParent(hWnd, _windowHost.Handle);
WinApi.SetParent(hWnd, _supportScroll ? _windowHost.Handle : Handle);
FixWindow();
}
}
@ -102,25 +109,34 @@ namespace Perspex.Designer.AppHost
{
if (_hWnd != IntPtr.Zero)
{
WinApi.RECT rc;
WinApi.GetWindowRect(_hWnd, out rc);
_desiredWidth = rc.Right - rc.Left;
_desiredHeight = rc.Bottom - rc.Top;
var pt = _windowHost.PointToClient(new Point(rc.Left, rc.Top));
if (_supportScroll)
{
WinApi.RECT rc;
WinApi.GetWindowRect(_hWnd, out rc);
_desiredWidth = rc.Right - rc.Left;
_desiredHeight = rc.Bottom - rc.Top;
var pt = _windowHost.PointToClient(new Point(rc.Left, rc.Top));
if (!(pt.Y == 0 && pt.X == 0 && _desiredWidth == _windowHost.Width && _desiredHeight == _windowHost.Height))
if (
!(pt.Y == 0 && pt.X == 0 && _desiredWidth == _windowHost.Width &&
_desiredHeight == _windowHost.Height))
{
_windowHost.Width = _desiredWidth;
_windowHost.Height = _desiredHeight;
WinApi.MoveWindow(_hWnd, 0, 0, _desiredWidth, _desiredHeight, true);
}
FixPosition();
}
else
{
_windowHost.Width = _desiredWidth;
_windowHost.Height = _desiredHeight;
WinApi.MoveWindow(_hWnd, 0, 0, _desiredWidth, _desiredHeight, true);
WinApi.MoveWindow(_hWnd, 0, 0, Width, Height, true);
}
FixPosition();
}
}
protected override void OnResize(EventArgs e)
{
FixPosition();
FixWindow();
base.OnResize(e);
}
}

2
src/Windows/Perspex.Designer/InProcDesigner/InProcDesignerView.xaml.cs

@ -33,7 +33,7 @@ namespace Perspex.Designer.InProcDesigner
InitializeComponent();
DataContext = _appModel;
_appModel.PropertyChanged += ModelPropertyChanged;
WindowHostControl.Child = _host = new WindowHost();
WindowHostControl.Child = _host = new WindowHost(true);
HandleVisibility();
HandleWindow();

2
src/Windows/Perspex.Designer/PerspexDesigner.xaml

@ -6,7 +6,7 @@
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<ContentControl x:Name="NativeContainer" Panel.ZIndex="1"/>
<WindowsFormsHost Background="White" x:Name="NativeContainer" Panel.ZIndex="1"/>
<ScrollViewer VerticalScrollBarVisibility="Auto" Panel.ZIndex="0">
<TextBox IsReadOnly="True" TextWrapping="WrapWithOverflow" x:Name="State"/>
</ScrollViewer>

36
src/Windows/Perspex.Designer/PerspexDesigner.xaml.cs

@ -73,41 +73,21 @@ namespace Perspex.Designer
{
if (e.PropertyName == nameof(ProcessHost.WindowHandle))
{
if (NativeContainer.Content != null)
if (NativeContainer.Child != null)
{
var wndHost = ((HwndHost) NativeContainer.Content);
NativeContainer.Content = null;
wndHost?.Dispose();
var child = NativeContainer.Child;
NativeContainer.Child = null;
child.Dispose();
}
if (_host.WindowHandle != IntPtr.Zero)
{
var host = new NativeWindowHost(_host.WindowHandle);
NativeContainer.Content = host;
}
}
}
NativeContainer.Child = new WindowHost(false);
var wndHost = ((WindowHost) NativeContainer.Child);
wndHost.SetWindow(_host.WindowHandle);
class NativeWindowHost :HwndHost
{
private readonly IntPtr _hWnd;
public NativeWindowHost(IntPtr hWnd)
{
_hWnd = hWnd;
}
protected override HandleRef BuildWindowCore(HandleRef hwndParent)
{
WinApi.SetParent(_hWnd, hwndParent.Handle);
return new HandleRef(this, _hWnd);
}
protected override void DestroyWindowCore(HandleRef hwnd)
{
WinApi.SendMessage(hwnd.Handle, WinApi.WM_CLOSE, IntPtr.Zero, IntPtr.Zero);
}
}
public void KillProcess()
{
_host.Kill();

21
tests/Perspex.Markup.Xaml.UnitTests/Data/BindingTests.cs

@ -140,6 +140,27 @@ namespace Perspex.Markup.Xaml.UnitTests.Data
Assert.Equal("Bar", parent.Child.DataContext);
}
[Fact]
public void DataContext_Binding_Should_Track_Parent()
{
var parent = new Decorator
{
DataContext = new { Foo = "foo" },
};
var child = new Control();
var binding = new Binding
{
Path = "Foo",
};
binding.Bind(child, Control.DataContextProperty);
Assert.Null(child.DataContext);
parent.Child = child;
Assert.Equal("foo", child.DataContext);
}
[Fact]
public void Should_Use_DefaultValueConverter_When_No_Converter_Specified()
{

Loading…
Cancel
Save