Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix visibility bindings of undocked panels in specific cases #60

Merged
merged 2 commits into from
Aug 10, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
namespace Xceed.Wpf.AvalonDock.Test
{
using System;
using System.Windows.Controls;

using Microsoft.VisualStudio.TestTools.UnitTesting;

using Xceed.Wpf.AvalonDock.Layout;

[TestClass]
public sealed class DockingUtilitiesTest
{
[TestMethod]
public void CalculatedDockMinWidthHeightTest()
{
double defaultDockMinHeight = 25;
double defaultDockMinWidth = 25;

const double documentPaneDockMinHeight = 200;
const double documentPaneDockMinWidth = 400;
LayoutDocumentPane layoutDocumentPane = new LayoutDocumentPane { DockMinHeight = documentPaneDockMinHeight, DockMinWidth = documentPaneDockMinWidth };
layoutDocumentPane.InsertChildAt( 0, new LayoutDocument { ContentId = "Document" } );

LayoutDocumentPaneGroup layoutDocumentPaneGroup = new LayoutDocumentPaneGroup();
layoutDocumentPaneGroup.InsertChildAt( 0, layoutDocumentPane );

const double anchorablePaneDockMinHeight = 80;
const double anchorablePaneDockMinWidth = 160;
LayoutAnchorablePane layoutAnchorablePane = new LayoutAnchorablePane { DockMinHeight = anchorablePaneDockMinHeight, DockMinWidth = anchorablePaneDockMinWidth };
layoutAnchorablePane.InsertChildAt( 0, new LayoutAnchorable { ContentId = "Anchorable" } );

LayoutAnchorablePaneGroup layoutAnchorablePaneGroup = new LayoutAnchorablePaneGroup();
layoutAnchorablePaneGroup.InsertChildAt( 0, layoutAnchorablePane );

LayoutPanel layoutPanel = new LayoutPanel();
layoutPanel.InsertChildAt( 0, layoutDocumentPaneGroup );
layoutPanel.InsertChildAt( 1, layoutAnchorablePaneGroup );

Assert.AreEqual( defaultDockMinWidth, layoutPanel.DockMinWidth );
Assert.AreEqual( defaultDockMinHeight, layoutPanel.DockMinHeight );
Assert.AreEqual( documentPaneDockMinWidth + anchorablePaneDockMinWidth, layoutPanel.CalculatedDockMinWidth() );
Assert.AreEqual( Math.Max(documentPaneDockMinHeight, anchorablePaneDockMinHeight), layoutPanel.CalculatedDockMinHeight() );

Assert.AreEqual( documentPaneDockMinWidth, layoutDocumentPane.DockMinWidth );
Assert.AreEqual( documentPaneDockMinHeight, layoutDocumentPane.DockMinHeight );
Assert.AreEqual( layoutDocumentPane.DockMinWidth, layoutDocumentPane.CalculatedDockMinWidth() );
Assert.AreEqual( layoutDocumentPane.DockMinHeight, layoutDocumentPane.CalculatedDockMinHeight() );

Assert.AreEqual( defaultDockMinWidth, layoutDocumentPaneGroup.DockMinWidth );
Assert.AreEqual( defaultDockMinWidth, layoutDocumentPaneGroup.DockMinHeight );
Assert.AreEqual( documentPaneDockMinWidth, layoutDocumentPaneGroup.CalculatedDockMinWidth() );
Assert.AreEqual( documentPaneDockMinHeight, layoutDocumentPaneGroup.CalculatedDockMinHeight() );

Assert.AreEqual( anchorablePaneDockMinWidth, layoutAnchorablePane.DockMinWidth );
Assert.AreEqual( anchorablePaneDockMinHeight, layoutAnchorablePane.DockMinHeight );
Assert.AreEqual( layoutAnchorablePane.DockMinWidth, layoutAnchorablePane.CalculatedDockMinWidth() );
Assert.AreEqual( layoutAnchorablePane.DockMinHeight, layoutAnchorablePane.CalculatedDockMinHeight() );

Assert.AreEqual( defaultDockMinWidth, layoutAnchorablePaneGroup.DockMinWidth );
Assert.AreEqual( defaultDockMinWidth, layoutAnchorablePaneGroup.DockMinHeight );
Assert.AreEqual( anchorablePaneDockMinWidth, layoutAnchorablePaneGroup.CalculatedDockMinWidth() );
Assert.AreEqual( anchorablePaneDockMinHeight, layoutAnchorablePaneGroup.CalculatedDockMinHeight() );

layoutPanel.RemoveChild( layoutDocumentPaneGroup );
Assert.AreEqual( anchorablePaneDockMinWidth, layoutPanel.CalculatedDockMinWidth() );
Assert.AreEqual( anchorablePaneDockMinHeight, layoutPanel.CalculatedDockMinHeight() );
}

[TestMethod]
public void UpdateDocMinWidthHeightTest()
{
double documentPaneDockMinHeight = 100;
double documentPaneDockMinWidth = 101;
LayoutDocumentPane layoutDocumentPane = new LayoutDocumentPane { DockMinHeight = documentPaneDockMinHeight, DockMinWidth = documentPaneDockMinWidth };
layoutDocumentPane.InsertChildAt( 0, new LayoutDocument { ContentId = "Document" } );

LayoutDocumentPaneGroup layoutDocumentPaneGroup = new LayoutDocumentPaneGroup();
layoutDocumentPaneGroup.InsertChildAt( 0, layoutDocumentPane );

double anchorablePane1DockMinHeight = 150;
double anchorablePane1DockMinWidth = 151;
LayoutAnchorablePane layoutAnchorablePane1 = new LayoutAnchorablePane { DockMinHeight = anchorablePane1DockMinHeight, DockMinWidth = anchorablePane1DockMinWidth };
layoutAnchorablePane1.InsertChildAt( 0, new LayoutAnchorable { ContentId = "Anchorable1" } );

double anchorablePane2DockMinHeight = 200;
double anchorablePane2DockMinWidth = 201;
LayoutAnchorablePane layoutAnchorablePane2 = new LayoutAnchorablePane { DockMinHeight = anchorablePane2DockMinHeight, DockMinWidth = anchorablePane2DockMinWidth };
layoutAnchorablePane2.InsertChildAt( 0, new LayoutAnchorable { ContentId = "Anchorable2" } );

LayoutAnchorablePaneGroup layoutAnchorablePaneGroup = new LayoutAnchorablePaneGroup { Orientation = Orientation.Horizontal };
layoutAnchorablePaneGroup.InsertChildAt( 0, layoutAnchorablePane1 );
layoutAnchorablePaneGroup.InsertChildAt( 0, layoutAnchorablePane2 );

LayoutPanel layoutPanel = new LayoutPanel { Orientation = Orientation.Vertical };
layoutPanel.InsertChildAt( 0, layoutDocumentPaneGroup );
layoutPanel.InsertChildAt( 1, layoutAnchorablePaneGroup );

Assert.AreEqual( anchorablePane2DockMinWidth + anchorablePane1DockMinWidth, layoutAnchorablePaneGroup.CalculatedDockMinWidth() );
Assert.AreEqual( Math.Max( anchorablePane2DockMinHeight, anchorablePane1DockMinHeight ), layoutAnchorablePaneGroup.CalculatedDockMinHeight() );

Assert.AreEqual( documentPaneDockMinWidth, layoutDocumentPaneGroup.CalculatedDockMinWidth() );
Assert.AreEqual( documentPaneDockMinHeight, layoutDocumentPaneGroup.CalculatedDockMinHeight() );

Assert.AreEqual(
Math.Max( anchorablePane1DockMinWidth + anchorablePane2DockMinWidth, documentPaneDockMinWidth ),
layoutPanel.CalculatedDockMinWidth() );

Assert.AreEqual( documentPaneDockMinHeight + anchorablePane2DockMinHeight, layoutPanel.CalculatedDockMinHeight() );
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
using System.Linq;
using System.Reflection;
using System.Windows;
using System.Windows.Data;

using Microsoft.VisualStudio.TestTools.UnitTesting;

using Xceed.Wpf.AvalonDock.Controls;
using Xceed.Wpf.AvalonDock.Converters;
using Xceed.Wpf.AvalonDock.Layout;

namespace Xceed.Wpf.AvalonDock.Test
{
[TestClass]
public sealed class LayoutAnchorableTest
{
[TestMethod]
public void ClearBindingOfHiddenWindowTest()
{
LayoutAnchorable layoutAnchorable = new LayoutAnchorable
{
FloatingWidth = 50,
FloatingHeight = 100,
ContentId = "Test"
};

LayoutAnchorablePane layoutAnchorablePane = new LayoutAnchorablePane( layoutAnchorable );
LayoutAnchorablePaneGroup layoutAnchorablePaneGroup = new LayoutAnchorablePaneGroup( layoutAnchorablePane );
LayoutAnchorableFloatingWindow layoutFloatingWindow = new LayoutAnchorableFloatingWindow
{
RootPanel = layoutAnchorablePaneGroup
};

var ctor = typeof( LayoutAnchorableFloatingWindowControl )
.GetTypeInfo()
.GetConstructors( BindingFlags.NonPublic | BindingFlags.Instance )
.First( x => x.GetParameters().Length == 1 );

LayoutAnchorableFloatingWindowControl floatingWindowControl = ctor.Invoke( new object[] {layoutFloatingWindow} ) as LayoutAnchorableFloatingWindowControl;
floatingWindowControl.SetBinding(
UIElement.VisibilityProperty,
new Binding( "IsVisible" )
{
Source = floatingWindowControl.Model,
Converter = new BoolToVisibilityConverter(),
Mode = BindingMode.OneWay,
ConverterParameter = Visibility.Hidden
} );

BindingExpression visibilityBinding = floatingWindowControl.GetBindingExpression( UIElement.VisibilityProperty );
Assert.IsNotNull( visibilityBinding );

layoutAnchorable.Show();
layoutAnchorable.Hide();

visibilityBinding = floatingWindowControl.GetBindingExpression( UIElement.VisibilityProperty );
Assert.IsNotNull( visibilityBinding );

floatingWindowControl.Hide();

visibilityBinding = floatingWindowControl.GetBindingExpression( UIElement.VisibilityProperty );
Assert.IsNull( visibilityBinding );
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,13 @@
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xaml" />
<Reference Include="System.XML" />
<Reference Include="WindowsBase" />
</ItemGroup>
<ItemGroup>
<Compile Include="AnchorablePaneTest.cs" />
<Compile Include="DockingUtilitiesTest.cs" />
<Compile Include="LayoutAnchorableTest.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="TestApp.xaml.cs">
<DependentUpon>TestApp.xaml</DependentUpon>
Expand Down Expand Up @@ -102,4 +105,4 @@
<Error Condition="!Exists('..\..\packages\MSTest.TestAdapter.1.4.0\build\net45\MSTest.TestAdapter.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\MSTest.TestAdapter.1.4.0\build\net45\MSTest.TestAdapter.targets'))" />
</Target>
<Import Project="..\..\packages\MSTest.TestAdapter.1.4.0\build\net45\MSTest.TestAdapter.targets" Condition="Exists('..\..\packages\MSTest.TestAdapter.1.4.0\build\net45\MSTest.TestAdapter.targets')" />
</Project>
</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ internal LayoutAnchorableFloatingWindowControl( LayoutAnchorableFloatingWindow m
_model = model;
HideWindowCommand = new RelayCommand( ( p ) => OnExecuteHideWindowCommand( p ), ( p ) => CanExecuteHideWindowCommand( p ) );
CloseWindowCommand = new RelayCommand( ( p ) => OnExecuteCloseWindowCommand( p ), ( p ) => CanExecuteCloseWindowCommand( p ) );
Activated += LayoutAnchorableFloatingWindowControl_Activated;
UpdateThemeResources();
MinWidth = _model.RootPanel.CalculatedDockMinWidth();
MinHeight = _model.RootPanel.CalculatedDockMinHeight();
Expand All @@ -71,6 +72,17 @@ private void OnRootUpdated(object sender, EventArgs e)
}
}

private void LayoutAnchorableFloatingWindowControl_Activated( object sender, EventArgs e )
{
// Issue similar to: http://avalondock.codeplex.com/workitem/15036
var visibilityBinding = GetBindingExpression( VisibilityProperty );

if ( visibilityBinding == null && Visibility == Visibility.Visible )
{
SetVisibilityBinding();
}
}

internal LayoutAnchorableFloatingWindowControl( LayoutAnchorableFloatingWindow model)
: this( model, false )
{
Expand Down Expand Up @@ -147,9 +159,9 @@ protected override void OnInitialized( EventArgs e )
IsVisibleChanged += ( s, args ) =>
{
var visibilityBinding = GetBindingExpression( VisibilityProperty );
if( IsVisible && ( visibilityBinding == null ) )
if( visibilityBinding == null && IsVisible )
{
SetBinding( VisibilityProperty, new Binding( "IsVisible" ) { Source = _model, Converter = new BoolToVisibilityConverter(), Mode = BindingMode.OneWay, ConverterParameter = Visibility.Hidden } );
SetVisibilityBinding();
}
};

Expand Down Expand Up @@ -189,6 +201,8 @@ protected override void OnClosed( EventArgs e )
BindingOperations.ClearBinding(_model, VisibilityProperty);

_model.PropertyChanged -= new System.ComponentModel.PropertyChangedEventHandler( _model_PropertyChanged );

Activated -= LayoutAnchorableFloatingWindowControl_Activated;
}

protected override void OnClosing( System.ComponentModel.CancelEventArgs e )
Expand All @@ -213,7 +227,12 @@ protected override IntPtr FilterMessage( IntPtr hwnd, int msg, IntPtr wParam, In
case Win32Helper.WM_NCLBUTTONDOWN: //Left button down on title -> start dragging over docking manager
if( wParam.ToInt32() == Win32Helper.HT_CAPTION )
{
_model.Descendents().OfType<LayoutAnchorablePane>().First( p => p.ChildrenCount > 0 && p.SelectedContent != null ).SelectedContent.IsActive = true;
var anchorablePane = _model.Descendents().OfType<LayoutAnchorablePane>()
.FirstOrDefault( p => p.ChildrenCount > 0 && p.SelectedContent != null );
if( anchorablePane != null )
{
anchorablePane.SelectedContent.IsActive = true;
}
handled = true;
}
break;
Expand Down Expand Up @@ -308,6 +327,59 @@ private bool IsContextMenuOpen()
return false;
}

private void SetVisibilityBinding()
{
SetBinding(
VisibilityProperty,
new Binding( "IsVisible" )
{
Source = _model,
Converter = new BoolToVisibilityConverter(),
Mode = BindingMode.OneWay,
ConverterParameter = Visibility.Hidden
}
);
}

#endregion

#region Public Methods

public override void EnableBindings()
{
_model.PropertyChanged += _model_PropertyChanged;
SetVisibilityBinding();
var root = Model.Root;
if( root != null )
{
LayoutRoot layoutRoot = root as LayoutRoot;
if ( layoutRoot != null )
{
layoutRoot.Updated += OnRootUpdated;
}
}

base.EnableBindings();
}

public override void DisableBindings()
{
var root = Model.Root;
if( root != null )
{
LayoutRoot layoutRoot = root as LayoutRoot;
if( layoutRoot != null )
{
layoutRoot.Updated -= OnRootUpdated;
}
}

BindingOperations.ClearBinding( _model, VisibilityProperty );
_model.PropertyChanged -= _model_PropertyChanged;

base.DisableBindings();
}

#endregion

#region Commands
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ public class LayoutAnchorableItem : LayoutItem
private ICommand _defaultAutoHideCommand;
private ICommand _defaultDockCommand;
private ReentrantFlag _visibilityReentrantFlag = new ReentrantFlag();
private ReentrantFlag _anchorableVisibilityReentrantFlag = new ReentrantFlag();

#endregion

Expand Down Expand Up @@ -377,9 +378,9 @@ private void _anchorable_IsVisibleChanged( object sender, EventArgs e )
{
if( _anchorable != null && _anchorable.Root != null )
{
if( _visibilityReentrantFlag.CanEnter )
if( _anchorableVisibilityReentrantFlag.CanEnter )
{
using( _visibilityReentrantFlag.Enter() )
using( _anchorableVisibilityReentrantFlag.Enter() )
{
if( _anchorable.IsVisible )
Visibility = Visibility.Visible;
Expand All @@ -390,12 +391,6 @@ private void _anchorable_IsVisibleChanged( object sender, EventArgs e )
}
}







#endregion
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -310,8 +310,8 @@ internal virtual void UpdateThemeResources( Theme oldTheme = null )
}
}

var manager = _model.Root.Manager;
if( manager.Theme != null )
var manager = _model.Root?.Manager;
if( manager?.Theme != null )
{
if( manager.Theme is DictionaryTheme )
{
Expand Down Expand Up @@ -531,6 +531,14 @@ private void UpdateDragPosition()

#endregion

public virtual void EnableBindings()
{
}

public virtual void DisableBindings()
{
}

#region Internal Classes

protected internal class FloatingWindowContentHost : HwndHost
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -641,12 +641,17 @@ private bool IsChildVisible(int index)
{
if( Orientation == Orientation.Horizontal )
{
return ColumnDefinitions[index].Width.IsStar || ColumnDefinitions[index].Width.Value > 0;
if ( index < ColumnDefinitions.Count )
{
return ColumnDefinitions[ index ].Width.IsStar || ColumnDefinitions[ index ].Width.Value > 0;
}
}
else
else if( index < RowDefinitions.Count )
{
return RowDefinitions[ index ].Height.IsStar || RowDefinitions[ index ].Height.Value > 0;
}

return false;
}

private void ShowResizerOverlayWindow( LayoutGridResizerControl splitter )
Expand Down
Loading