All the controls missing in WPF. Over 1 million downloads.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1383 lines
38 KiB

/*************************************************************************************
Extended WPF Toolkit
Copyright (C) 2007-2013 Xceed Software Inc.
This program is provided to you under the terms of the Microsoft Public
License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license
For more features, controls, and fast professional support,
pick up the Plus Edition at http://xceed.com/wpf_toolkit
Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids
***********************************************************************************/
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Threading;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Documents;
using System.Windows.Media;
using System.Windows.Threading;
using Xceed.Wpf.Toolkit.Primitives;
using Xceed.Wpf.Toolkit.Media.Animation;
using Xceed.Wpf.Toolkit.Core.Utilities;
namespace Xceed.Wpf.Toolkit.Panels
{
public class SwitchPanel : PanelBase, IScrollInfo
{
#region Static Fields
private static readonly Vector ZeroVector = new Vector();
#endregion
#region Constructors
public SwitchPanel()
{
this.SetLayouts( new ObservableCollection<AnimationPanel>() );
this.Loaded += new RoutedEventHandler( this.OnLoaded );
}
#endregion
#region AreLayoutSwitchesAnimated Property
public static readonly DependencyProperty AreLayoutSwitchesAnimatedProperty =
DependencyProperty.Register( "AreLayoutSwitchesAnimated", typeof( bool ), typeof( SwitchPanel ),
new FrameworkPropertyMetadata( true ) );
public bool AreLayoutSwitchesAnimated
{
get
{
return ( bool )this.GetValue( SwitchPanel.AreLayoutSwitchesAnimatedProperty );
}
set
{
this.SetValue( SwitchPanel.AreLayoutSwitchesAnimatedProperty, value );
}
}
#endregion
#region ActiveLayout Property
private static readonly DependencyPropertyKey ActiveLayoutPropertyKey =
DependencyProperty.RegisterReadOnly( "ActiveLayout", typeof( AnimationPanel ), typeof( SwitchPanel ),
new FrameworkPropertyMetadata( null, FrameworkPropertyMetadataOptions.AffectsMeasure,
new PropertyChangedCallback( SwitchPanel.OnActiveLayoutChanged ) ) );
public static readonly DependencyProperty ActiveLayoutProperty = SwitchPanel.ActiveLayoutPropertyKey.DependencyProperty;
public AnimationPanel ActiveLayout
{
get
{
return ( AnimationPanel )this.GetValue( SwitchPanel.ActiveLayoutProperty );
}
}
protected void SetActiveLayout( AnimationPanel value )
{
this.SetValue( SwitchPanel.ActiveLayoutPropertyKey, value );
}
private static void OnActiveLayoutChanged( DependencyObject d, DependencyPropertyChangedEventArgs e )
{
( ( SwitchPanel )d ).OnActiveLayoutChanged( e );
}
protected virtual void OnActiveLayoutChanged( DependencyPropertyChangedEventArgs e )
{
if( _currentLayoutPanel != null )
{
_currentLayoutPanel.DeactivateLayout();
}
_currentLayoutPanel = e.NewValue as AnimationPanel;
if( _currentLayoutPanel != null )
{
IScrollInfo info = _currentLayoutPanel as IScrollInfo;
if( info != null && info.ScrollOwner != null )
{
info.ScrollOwner.InvalidateScrollInfo();
}
_currentLayoutPanel.ActivateLayout();
}
this.RaiseActiveLayoutChangedEvent();
this.Dispatcher.BeginInvoke(
DispatcherPriority.Normal,
( ThreadStart )delegate()
{
this.UpdateSwitchTemplate();
} );
}
#endregion
#region ActiveLayoutIndex Property
public static readonly DependencyProperty ActiveLayoutIndexProperty =
DependencyProperty.Register( "ActiveLayoutIndex", typeof( int ), typeof( SwitchPanel ),
new FrameworkPropertyMetadata( -1,
new PropertyChangedCallback( SwitchPanel.OnActiveLayoutIndexChanged ), new CoerceValueCallback( SwitchPanel.CoerceActiveLayoutIndexValue ) ) );
public int ActiveLayoutIndex
{
get
{
return ( int )this.GetValue( SwitchPanel.ActiveLayoutIndexProperty );
}
set
{
this.SetValue( SwitchPanel.ActiveLayoutIndexProperty, value );
}
}
private static void OnActiveLayoutIndexChanged( DependencyObject d, DependencyPropertyChangedEventArgs e )
{
( ( SwitchPanel )d ).OnActiveLayoutIndexChanged( e );
}
protected virtual void OnActiveLayoutIndexChanged( DependencyPropertyChangedEventArgs e )
{
this.SetActiveLayout( ( this.Layouts.Count == 0 ) ? null : this.Layouts[ ActiveLayoutIndex ] );
}
private static object CoerceActiveLayoutIndexValue( DependencyObject d, object value )
{
int panelCount = ( d as SwitchPanel ).Layouts.Count;
int result = ( int )value;
if( result < 0 && panelCount > 0 )
{
result = 0;
}
else if( result >= panelCount )
{
result = panelCount - 1;
}
return result;
}
#endregion
#region ActiveSwitchTemplate Property
private static readonly DependencyPropertyKey ActiveSwitchTemplatePropertyKey =
DependencyProperty.RegisterReadOnly( "ActiveSwitchTemplate", typeof( DataTemplate ), typeof( SwitchPanel ),
new FrameworkPropertyMetadata( null, new PropertyChangedCallback( SwitchPanel.OnActiveSwitchTemplateChanged ) ) );
public static readonly DependencyProperty ActiveSwitchTemplateProperty = SwitchPanel.ActiveSwitchTemplatePropertyKey.DependencyProperty;
public DataTemplate ActiveSwitchTemplate
{
get
{
return ( DataTemplate )this.GetValue( SwitchPanel.ActiveSwitchTemplateProperty );
}
}
protected void SetActiveSwitchTemplate( DataTemplate value )
{
this.SetValue( SwitchPanel.ActiveSwitchTemplatePropertyKey, value );
}
private static void OnActiveSwitchTemplateChanged( DependencyObject d, DependencyPropertyChangedEventArgs e )
{
( ( SwitchPanel )d ).OnActiveSwitchTemplateChanged( e );
}
protected virtual void OnActiveSwitchTemplateChanged( DependencyPropertyChangedEventArgs e )
{
if( _presenters.Count > 0 )
{
DataTemplate template = e.NewValue as DataTemplate;
List<UIElement> currentChildren = new List<UIElement>( this.InternalChildren.Count );
foreach( UIElement child in this.InternalChildren )
{
if( child == null )
continue;
currentChildren.Add( child );
}
foreach( SwitchPresenter presenter in _presenters )
{
if( presenter._switchRoot != null && currentChildren.Contains( presenter._switchRoot ) )
{
presenter.SwapTheTemplate( template, this.AreLayoutSwitchesAnimated );
}
}
}
}
#endregion
#region DefaultAnimationRate Property
public static readonly DependencyProperty DefaultAnimationRateProperty =
AnimationPanel.DefaultAnimationRateProperty.AddOwner( typeof( SwitchPanel ) );
public AnimationRate DefaultAnimationRate
{
get
{
return ( AnimationRate )this.GetValue( SwitchPanel.DefaultAnimationRateProperty );
}
set
{
this.SetValue( SwitchPanel.DefaultAnimationRateProperty, value );
}
}
#endregion
#region DefaultAnimator Property
public static readonly DependencyProperty DefaultAnimatorProperty =
AnimationPanel.DefaultAnimatorProperty.AddOwner( typeof( SwitchPanel ) );
public IterativeAnimator DefaultAnimator
{
get
{
return ( IterativeAnimator )this.GetValue( SwitchPanel.DefaultAnimatorProperty );
}
set
{
this.SetValue( SwitchPanel.DefaultAnimatorProperty, value );
}
}
#endregion
#region EnterAnimationRate Property
public static readonly DependencyProperty EnterAnimationRateProperty =
AnimationPanel.EnterAnimationRateProperty.AddOwner( typeof( SwitchPanel ),
new FrameworkPropertyMetadata( AnimationRate.Default ) );
public AnimationRate EnterAnimationRate
{
get
{
return ( AnimationRate )this.GetValue( SwitchPanel.EnterAnimationRateProperty );
}
set
{
this.SetValue( SwitchPanel.EnterAnimationRateProperty, value );
}
}
#endregion
#region EnterAnimator Property
public static readonly DependencyProperty EnterAnimatorProperty =
AnimationPanel.EnterAnimatorProperty.AddOwner( typeof( SwitchPanel ),
new FrameworkPropertyMetadata( IterativeAnimator.Default ) );
public IterativeAnimator EnterAnimator
{
get
{
return ( IterativeAnimator )this.GetValue( SwitchPanel.EnterAnimatorProperty );
}
set
{
this.SetValue( SwitchPanel.EnterAnimatorProperty, value );
}
}
#endregion
#region ExitAnimationRate Property
public static readonly DependencyProperty ExitAnimationRateProperty =
AnimationPanel.ExitAnimationRateProperty.AddOwner( typeof( SwitchPanel ),
new FrameworkPropertyMetadata( AnimationRate.Default ) );
public AnimationRate ExitAnimationRate
{
get
{
return ( AnimationRate )this.GetValue( SwitchPanel.ExitAnimationRateProperty );
}
set
{
this.SetValue( SwitchPanel.ExitAnimationRateProperty, value );
}
}
#endregion
#region ExitAnimator Property
public static readonly DependencyProperty ExitAnimatorProperty =
AnimationPanel.ExitAnimatorProperty.AddOwner( typeof( SwitchPanel ),
new FrameworkPropertyMetadata( IterativeAnimator.Default ) );
public IterativeAnimator ExitAnimator
{
get
{
return ( IterativeAnimator )this.GetValue( SwitchPanel.ExitAnimatorProperty );
}
set
{
this.SetValue( SwitchPanel.ExitAnimatorProperty, value );
}
}
#endregion
#region LayoutAnimationRate Property
public static readonly DependencyProperty LayoutAnimationRateProperty =
AnimationPanel.LayoutAnimationRateProperty.AddOwner( typeof( SwitchPanel ),
new FrameworkPropertyMetadata( AnimationRate.Default ) );
public AnimationRate LayoutAnimationRate
{
get
{
return ( AnimationRate )this.GetValue( SwitchPanel.LayoutAnimationRateProperty );
}
set
{
this.SetValue( SwitchPanel.LayoutAnimationRateProperty, value );
}
}
#endregion
#region LayoutAnimator Property
public static readonly DependencyProperty LayoutAnimatorProperty =
AnimationPanel.LayoutAnimatorProperty.AddOwner( typeof( SwitchPanel ),
new FrameworkPropertyMetadata( IterativeAnimator.Default ) );
public IterativeAnimator LayoutAnimator
{
get
{
return ( IterativeAnimator )this.GetValue( SwitchPanel.LayoutAnimatorProperty );
}
set
{
this.SetValue( SwitchPanel.LayoutAnimatorProperty, value );
}
}
#endregion
#region Layouts Property
private static readonly DependencyPropertyKey LayoutsPropertyKey =
DependencyProperty.RegisterReadOnly( "Layouts", typeof( ObservableCollection<AnimationPanel> ), typeof( SwitchPanel ),
new FrameworkPropertyMetadata( null, FrameworkPropertyMetadataOptions.AffectsArrange,
new PropertyChangedCallback( SwitchPanel.OnLayoutsChanged ) ) );
public static readonly DependencyProperty LayoutsProperty = SwitchPanel.LayoutsPropertyKey.DependencyProperty;
public ObservableCollection<AnimationPanel> Layouts
{
get
{
return ( ObservableCollection<AnimationPanel> )this.GetValue( SwitchPanel.LayoutsProperty );
}
}
protected void SetLayouts( ObservableCollection<AnimationPanel> value )
{
this.SetValue( SwitchPanel.LayoutsPropertyKey, value );
}
private static void OnLayoutsChanged( DependencyObject d, DependencyPropertyChangedEventArgs e )
{
( ( SwitchPanel )d ).OnLayoutsChanged( e );
}
protected virtual void OnLayoutsChanged( DependencyPropertyChangedEventArgs e )
{
if( e.NewValue != null )
{
( e.NewValue as ObservableCollection<AnimationPanel> ).CollectionChanged
+= new NotifyCollectionChangedEventHandler( LayoutsCollectionChanged );
}
if( e.OldValue != null )
{
( e.OldValue as ObservableCollection<AnimationPanel> ).CollectionChanged
-= new NotifyCollectionChangedEventHandler( LayoutsCollectionChanged );
}
}
#endregion
#region SwitchAnimationRate Property
public static readonly DependencyProperty SwitchAnimationRateProperty =
AnimationPanel.SwitchAnimationRateProperty.AddOwner( typeof( SwitchPanel ),
new FrameworkPropertyMetadata( AnimationRate.Default ) );
public AnimationRate SwitchAnimationRate
{
get
{
return ( AnimationRate )this.GetValue( SwitchPanel.SwitchAnimationRateProperty );
}
set
{
this.SetValue( SwitchPanel.SwitchAnimationRateProperty, value );
}
}
#endregion
#region SwitchAnimator Property
public static readonly DependencyProperty SwitchAnimatorProperty =
AnimationPanel.SwitchAnimatorProperty.AddOwner( typeof( SwitchPanel ),
new FrameworkPropertyMetadata( IterativeAnimator.Default ) );
public IterativeAnimator SwitchAnimator
{
get
{
return ( IterativeAnimator )this.GetValue( SwitchPanel.SwitchAnimatorProperty );
}
set
{
this.SetValue( SwitchPanel.SwitchAnimatorProperty, value );
}
}
#endregion
#region SwitchTemplate Property
public static readonly DependencyProperty SwitchTemplateProperty =
DependencyProperty.Register( "SwitchTemplate", typeof( DataTemplate ), typeof( SwitchPanel ),
new FrameworkPropertyMetadata( null,
new PropertyChangedCallback( SwitchPanel.OnSwitchTemplateChanged ) ) );
public DataTemplate SwitchTemplate
{
get
{
return ( DataTemplate )this.GetValue( SwitchPanel.SwitchTemplateProperty );
}
set
{
this.SetValue( SwitchPanel.SwitchTemplateProperty, value );
}
}
private static void OnSwitchTemplateChanged( DependencyObject d, DependencyPropertyChangedEventArgs e )
{
( ( SwitchPanel )d ).OnSwitchTemplateChanged( e );
}
protected virtual void OnSwitchTemplateChanged( DependencyPropertyChangedEventArgs e )
{
this.UpdateSwitchTemplate();
}
#endregion
#region TemplateAnimationRate Property
public static readonly DependencyProperty TemplateAnimationRateProperty =
AnimationPanel.TemplateAnimationRateProperty.AddOwner( typeof( SwitchPanel ),
new FrameworkPropertyMetadata( AnimationRate.Default ) );
public AnimationRate TemplateAnimationRate
{
get
{
return ( AnimationRate )this.GetValue( SwitchPanel.TemplateAnimationRateProperty );
}
set
{
this.SetValue( SwitchPanel.TemplateAnimationRateProperty, value );
}
}
#endregion
#region TemplateAnimator Property
public static readonly DependencyProperty TemplateAnimatorProperty =
AnimationPanel.TemplateAnimatorProperty.AddOwner( typeof( SwitchPanel ),
new FrameworkPropertyMetadata( IterativeAnimator.Default ) );
public IterativeAnimator TemplateAnimator
{
get
{
return ( IterativeAnimator )this.GetValue( SwitchPanel.TemplateAnimatorProperty );
}
set
{
this.SetValue( SwitchPanel.TemplateAnimatorProperty, value );
}
}
#endregion
#region VisualChildrenCount Protected Property
protected override int VisualChildrenCount
{
get
{
int result = 0;
if( this.HasLoaded && _currentLayoutPanel != null )
{
result = _currentLayoutPanel.VisualChildrenCountInternal;
}
else
{
result = base.VisualChildrenCount;
}
return result;
}
}
#endregion
#region ExitingChildren Internal Property
internal List<UIElement> ExitingChildren
{
get
{
return _exitingChildren;
}
}
private readonly List<UIElement> _exitingChildren = new List<UIElement>();
#endregion
#region ChildrenInternal Internal Property
internal UIElementCollection ChildrenInternal
{
get
{
return this.InternalChildren;
}
}
#endregion
#region HasLoaded Internal Property
internal bool HasLoaded
{
get
{
return _cacheBits[ ( int )CacheBits.HasLoaded ];
}
set
{
_cacheBits[ ( int )CacheBits.HasLoaded ] = value;
}
}
#endregion
#region IsScrollingPhysically Private Property
private bool IsScrollingPhysically
{
get
{
bool isScrollingPhys = false;
if( _scrollOwner != null )
{
isScrollingPhys = true;
if( this.ActiveLayout != null && this.ActiveLayout is IScrollInfo )
{
isScrollingPhys = ( ( IScrollInfo )this.ActiveLayout ).ScrollOwner == null;
}
}
return isScrollingPhys;
}
}
#endregion
#region ActiveLayoutChanged Event
public static readonly RoutedEvent ActiveLayoutChangedEvent =
EventManager.RegisterRoutedEvent( "ActiveLayoutChanged", RoutingStrategy.Bubble, typeof( RoutedEventHandler ), typeof( SwitchPanel ) );
public event RoutedEventHandler ActiveLayoutChanged
{
add
{
this.AddHandler( SwitchPanel.ActiveLayoutChangedEvent, value );
}
remove
{
this.RemoveHandler( SwitchPanel.ActiveLayoutChangedEvent, value );
}
}
protected RoutedEventArgs RaiseActiveLayoutChangedEvent()
{
return SwitchPanel.RaiseActiveLayoutChangedEvent( this );
}
internal static RoutedEventArgs RaiseActiveLayoutChangedEvent( UIElement target )
{
if( target == null )
return null;
RoutedEventArgs args = new RoutedEventArgs();
args.RoutedEvent = SwitchPanel.ActiveLayoutChangedEvent;
RoutedEventHelper.RaiseEvent( target, args );
return args;
}
#endregion
#region SwitchAnimationBegun Event
public static readonly RoutedEvent SwitchAnimationBegunEvent =
EventManager.RegisterRoutedEvent( "SwitchAnimationBegun", RoutingStrategy.Bubble, typeof( RoutedEventHandler ), typeof( SwitchPanel ) );
public event RoutedEventHandler SwitchAnimationBegun
{
add
{
this.AddHandler( SwitchPanel.SwitchAnimationBegunEvent, value );
}
remove
{
this.RemoveHandler( SwitchPanel.SwitchAnimationBegunEvent, value );
}
}
protected RoutedEventArgs RaiseSwitchAnimationBegunEvent()
{
return SwitchPanel.RaiseSwitchAnimationBegunEvent( this );
}
private static RoutedEventArgs RaiseSwitchAnimationBegunEvent( UIElement target )
{
if( target == null )
return null;
RoutedEventArgs args = new RoutedEventArgs();
args.RoutedEvent = SwitchPanel.SwitchAnimationBegunEvent;
RoutedEventHelper.RaiseEvent( target, args );
return args;
}
#endregion
#region SwitchAnimationCompleted Event
public static readonly RoutedEvent SwitchAnimationCompletedEvent =
EventManager.RegisterRoutedEvent( "SwitchAnimationCompleted", RoutingStrategy.Bubble, typeof( RoutedEventHandler ), typeof( SwitchPanel ) );
public event RoutedEventHandler SwitchAnimationCompleted
{
add
{
this.AddHandler( SwitchPanel.SwitchAnimationCompletedEvent, value );
}
remove
{
this.RemoveHandler( SwitchPanel.SwitchAnimationCompletedEvent, value );
}
}
protected RoutedEventArgs RaiseSwitchAnimationCompletedEvent()
{
return SwitchPanel.RaiseSwitchAnimationCompletedEvent( this );
}
private static RoutedEventArgs RaiseSwitchAnimationCompletedEvent( UIElement target )
{
if( target == null )
return null;
RoutedEventArgs args = new RoutedEventArgs();
args.RoutedEvent = SwitchPanel.SwitchAnimationCompletedEvent;
RoutedEventHelper.RaiseEvent( target, args );
return args;
}
#endregion
protected override Size MeasureOverride( Size availableSize )
{
AnimationPanel layout = ( Layouts.Count == 0 ) ? _defaultLayoutCanvas : this.ActiveLayout;
Size measureSize = layout.MeasureChildrenCore( this.InternalChildren, availableSize );
if( this.IsScrollingPhysically )
{
Size viewport = availableSize;
Size extent = measureSize;
//
// Make sure our offset works with the new size of the panel. We don't want to show
// any whitespace if the user scrolled all the way down and then increased the size of the panel.
//
Vector newOffset = new Vector(
Math.Max( 0, Math.Min( _offset.X, extent.Width - viewport.Width ) ),
Math.Max( 0, Math.Min( _offset.Y, extent.Height - viewport.Height ) ) );
this.SetScrollingData( viewport, extent, newOffset );
}
return measureSize;
}
protected override Size ArrangeOverride( Size finalSize )
{
AnimationPanel layout = ( Layouts.Count == 0 ) ? _defaultLayoutCanvas : this.ActiveLayout;
if( this.IsScrollingPhysically )
{
layout.PhysicalScrollOffset = _offset;
}
else
{
layout.PhysicalScrollOffset = ZeroVector;
}
return layout.ArrangeChildrenCore( InternalChildren, finalSize );
}
protected override Visual GetVisualChild( int index )
{
if( this.HasLoaded && _currentLayoutPanel != null )
return _currentLayoutPanel.GetVisualChildInternal( index );
return base.GetVisualChild( index );
}
protected override void OnVisualChildrenChanged( DependencyObject visualAdded, DependencyObject visualRemoved )
{
// The OnNotifyVisualChildAdded/Removed methods get called for all animation panels within a
// SwitchPanel.Layouts collection, regardless of whether they are the active layout for the SwitchPanel.
if( visualAdded is UIElement )
{
// do not issue notification for a child that is exiting
if( _currentLayoutPanel == null || !_currentLayoutPanel.IsRemovingInternalChild )
{
foreach( AnimationPanel panel in Layouts )
{
panel.OnNotifyVisualChildAddedInternal( visualAdded as UIElement );
}
}
}
else if( visualRemoved is UIElement )
{
foreach( AnimationPanel panel in Layouts )
{
panel.OnNotifyVisualChildRemovedInternal( visualRemoved as UIElement );
}
}
if( _currentLayoutPanel != null )
{
_currentLayoutPanel.OnSwitchParentVisualChildrenChanged( visualAdded, visualRemoved );
}
else
{
base.OnVisualChildrenChanged( visualAdded, visualRemoved );
}
}
internal void AddVisualChildInternal( Visual child )
{
this.AddVisualChild( child );
}
internal void BeginLayoutSwitch()
{
this.RaiseSwitchAnimationBegunEvent();
}
internal void EndLayoutSwitch()
{
this.RaiseSwitchAnimationCompletedEvent();
}
internal Visual GetVisualChildInternal( int index )
{
// called from AnimationPanel to access base class method
return base.GetVisualChild( index );
}
internal void OnVisualChildrenChangedInternal( DependencyObject visualAdded, DependencyObject visualRemoved )
{
base.OnVisualChildrenChanged( visualAdded, visualRemoved );
}
internal UIElement RegisterPresenter( SwitchPresenter presenter )
{
UIElement result = null;
AnimationPanel ignore;
result = AnimationPanel.FindAncestorChildOfAnimationPanel( presenter, out ignore );
if( result != null )
{
_presenters.Add( presenter );
presenter.SwapTheTemplate( ActiveSwitchTemplate, false );
}
return result;
}
internal void RemoveVisualChildInternal( Visual child )
{
this.RemoveVisualChild( child );
}
internal void UnregisterPresenter( SwitchPresenter presenter, DependencyObject container )
{
if( container != null )
{
_presenters.Remove( presenter );
presenter.SwapTheTemplate( null, false );
}
}
internal void UpdateSwitchTemplate()
{
this.SetActiveSwitchTemplate( ( this.ActiveLayout == null ) || ( this.ActiveLayout.SwitchTemplate == null )
? this.SwitchTemplate : this.ActiveLayout.SwitchTemplate );
}
private void OnLoaded( object sender, RoutedEventArgs e )
{
this.HasLoaded = true;
// invalidate arrange to give enter animations a chance to run
this.InvalidateArrange();
}
private void LayoutsCollectionChanged( object sender, NotifyCollectionChangedEventArgs e )
{
if( e.Action != NotifyCollectionChangedAction.Move )
{
if( e.NewItems != null )
{
foreach( AnimationPanel panel in e.NewItems )
{
this.AddLogicalChild( panel );
panel.SetSwitchParent( this );
if( panel is IScrollInfo )
{
( ( IScrollInfo )panel ).ScrollOwner = this.ScrollOwner;
}
if( this.IsLoaded )
{
foreach( UIElement child in this.InternalChildren )
{
if( child == null )
continue;
panel.OnNotifyVisualChildAddedInternal( child );
}
}
}
}
if( e.OldItems != null )
{
foreach( AnimationPanel panel in e.OldItems )
{
if( IsLoaded )
{
foreach( UIElement child in this.InternalChildren )
{
if( child == null )
continue;
panel.OnNotifyVisualChildRemovedInternal( child );
}
}
this.RemoveLogicalChild( panel );
panel.SetSwitchParent( null );
if( panel is IScrollInfo )
{
( ( IScrollInfo )panel ).ScrollOwner = null;
}
}
}
}
// ensure valid ActiveLayoutIndex value
this.CoerceValue( SwitchPanel.ActiveLayoutIndexProperty );
this.SetActiveLayout( ( this.Layouts.Count == 0 ) ? null : this.Layouts[ ActiveLayoutIndex ] );
}
private void ResetScrollInfo()
{
_offset = new Vector();
_viewport = _extent = new Size( 0, 0 );
}
private void OnScrollChange()
{
if( this.ScrollOwner != null )
{
this.ScrollOwner.InvalidateScrollInfo();
}
}
private void SetScrollingData( Size viewport, Size extent, Vector offset )
{
_offset = offset;
if( DoubleHelper.AreVirtuallyEqual( viewport, _viewport ) == false || DoubleHelper.AreVirtuallyEqual( extent, _extent ) == false ||
DoubleHelper.AreVirtuallyEqual( offset, _computedOffset ) == false )
{
_viewport = viewport;
_extent = extent;
_computedOffset = offset;
this.OnScrollChange();
}
}
private double ValidateInputOffset( double offset, string parameterName )
{
if( double.IsNaN( offset ) )
throw new ArgumentOutOfRangeException( parameterName );
return Math.Max( 0d, offset );
}
private int FindChildFromVisual( Visual vis )
{
int index = -1;
DependencyObject parent = vis;
DependencyObject child = null;
do
{
child = parent;
parent = VisualTreeHelper.GetParent( child );
}
while( parent != null && parent != this );
if( parent == this )
{
index = this.Children.IndexOf( ( UIElement )child );
}
return index;
}
#region IScrollInfo Members
public bool CanHorizontallyScroll
{
get
{
if( this.ActiveLayout != null && this.ActiveLayout is IScrollInfo )
return ( ( IScrollInfo )this.ActiveLayout ).CanHorizontallyScroll;
return _allowHorizontal;
}
set
{
if( this.ActiveLayout != null && this.ActiveLayout is IScrollInfo )
{
( ( IScrollInfo )this.ActiveLayout ).CanHorizontallyScroll = value;
}
else
{
_allowHorizontal = value;
}
}
}
public bool CanVerticallyScroll
{
get
{
if( this.ActiveLayout != null && this.ActiveLayout is IScrollInfo )
return ( ( IScrollInfo )this.ActiveLayout ).CanVerticallyScroll;
return _allowVertical;
}
set
{
if( this.ActiveLayout != null && this.ActiveLayout is IScrollInfo )
{
( ( IScrollInfo )this.ActiveLayout ).CanVerticallyScroll = value;
}
else
{
_allowVertical = value;
}
}
}
public double ExtentHeight
{
get
{
if( this.ActiveLayout != null && this.ActiveLayout is IScrollInfo )
return ( ( IScrollInfo )this.ActiveLayout ).ExtentHeight;
return _extent.Height;
}
}
public double ExtentWidth
{
get
{
if( this.ActiveLayout != null && this.ActiveLayout is IScrollInfo )
return ( ( IScrollInfo )this.ActiveLayout ).ExtentWidth;
return _extent.Width;
}
}
public double HorizontalOffset
{
get
{
if( this.ActiveLayout != null && this.ActiveLayout is IScrollInfo )
return ( ( IScrollInfo )this.ActiveLayout ).HorizontalOffset;
return _offset.X;
}
}
public void LineDown()
{
if( this.ActiveLayout != null && this.ActiveLayout is IScrollInfo )
{
( ( IScrollInfo )this.ActiveLayout ).LineDown();
}
else
{
this.SetVerticalOffset( this.VerticalOffset + 1d );
}
}
public void LineLeft()
{
if( this.ActiveLayout != null && this.ActiveLayout is IScrollInfo )
{
( ( IScrollInfo )this.ActiveLayout ).LineLeft();
}
else
{
this.SetHorizontalOffset( this.VerticalOffset - 1d );
}
}
public void LineRight()
{
if( this.ActiveLayout != null && this.ActiveLayout is IScrollInfo )
{
( ( IScrollInfo )this.ActiveLayout ).LineRight();
}
else
{
this.SetHorizontalOffset( this.VerticalOffset + 1d );
}
}
public void LineUp()
{
if( this.ActiveLayout != null && this.ActiveLayout is IScrollInfo )
{
( ( IScrollInfo )this.ActiveLayout ).LineUp();
}
else
{
this.SetVerticalOffset( this.VerticalOffset + 1d );
}
}
public Rect MakeVisible( Visual visual, Rect rectangle )
{
if( this.ActiveLayout != null && this.ActiveLayout is IScrollInfo )
return ( ( IScrollInfo )this.ActiveLayout ).MakeVisible( visual, rectangle );
if( ( rectangle.IsEmpty || ( visual == null ) ) || ( ( visual == this ) || !this.IsAncestorOf( visual ) ) )
return Rect.Empty;
rectangle = visual.TransformToAncestor( ( Visual )this ).TransformBounds( rectangle );
if( this.IsScrollingPhysically == false )
return rectangle;
//
// Make sure we can find the child...
//
int index = this.FindChildFromVisual( visual );
if( index == -1 )
throw new ArgumentException( "visual" );
//
// Since our _Offset pushes the items down we need to correct it here to
// give a true rectangle of the child.
//
Rect itemRect = rectangle;
itemRect.Offset( _offset );
Rect viewRect = new Rect( new Point( _offset.X, _offset.Y ), _viewport );
Vector newPhysOffset;
if( ScrollHelper.ScrollLeastAmount( viewRect, itemRect, out newPhysOffset ) )
{
this.SetHorizontalOffset( newPhysOffset.X );
this.SetVerticalOffset( newPhysOffset.Y );
}
return rectangle;
}
public void MouseWheelDown()
{
if( this.ActiveLayout != null && this.ActiveLayout is IScrollInfo )
{
( ( IScrollInfo )ActiveLayout ).MouseWheelDown();
}
else
{
this.SetVerticalOffset( this.VerticalOffset + SystemParameters.WheelScrollLines );
}
}
public void MouseWheelLeft()
{
if( this.ActiveLayout != null && this.ActiveLayout is IScrollInfo )
{
( ( IScrollInfo )this.ActiveLayout ).MouseWheelLeft();
}
else
{
this.SetVerticalOffset( this.VerticalOffset - 3d );
}
}
public void MouseWheelRight()
{
if( this.ActiveLayout != null && this.ActiveLayout is IScrollInfo )
{
( ( IScrollInfo )this.ActiveLayout ).MouseWheelRight();
}
else
{
this.SetVerticalOffset( this.VerticalOffset + 3d );
}
}
public void MouseWheelUp()
{
if( this.ActiveLayout != null && this.ActiveLayout is IScrollInfo )
{
( ( IScrollInfo )this.ActiveLayout ).MouseWheelUp();
}
else
{
this.SetVerticalOffset( this.VerticalOffset - SystemParameters.WheelScrollLines );
}
}
public void PageDown()
{
if( this.ActiveLayout != null && this.ActiveLayout is IScrollInfo )
{
( ( IScrollInfo )this.ActiveLayout ).PageDown();
}
else
{
this.SetVerticalOffset( this.VerticalOffset + this.ViewportHeight );
}
}
public void PageLeft()
{
if( this.ActiveLayout != null && this.ActiveLayout is IScrollInfo )
{
( ( IScrollInfo )this.ActiveLayout ).PageLeft();
}
else
{
this.SetHorizontalOffset( this.HorizontalOffset - this.ViewportWidth );
}
}
public void PageRight()
{
if( this.ActiveLayout != null && this.ActiveLayout is IScrollInfo )
{
( ( IScrollInfo )this.ActiveLayout ).PageRight();
}
else
{
this.SetHorizontalOffset( this.HorizontalOffset + this.ViewportWidth );
}
}
public void PageUp()
{
if( this.ActiveLayout != null && this.ActiveLayout is IScrollInfo )
{
( ( IScrollInfo )this.ActiveLayout ).PageUp();
}
else
{
this.SetVerticalOffset( this.VerticalOffset - this.ViewportHeight );
}
}
public ScrollViewer ScrollOwner
{
get
{
return _scrollOwner;
}
set
{
foreach( AnimationPanel layout in this.Layouts )
{
if( layout != null && layout is IScrollInfo )
{
( ( IScrollInfo )layout ).ScrollOwner = value;
}
}
if( _scrollOwner != value )
{
_scrollOwner = value;
this.ResetScrollInfo();
}
}
}
public void SetHorizontalOffset( double offset )
{
offset = this.ValidateInputOffset( offset, "HorizontalOffset" );
offset = Math.Min( offset, this.ExtentWidth - this.ViewportWidth );
if( !DoubleHelper.AreVirtuallyEqual( offset, _offset.X ) )
{
_offset.X = offset;
base.InvalidateMeasure();
}
}
public void SetVerticalOffset( double offset )
{
offset = this.ValidateInputOffset( offset, "VerticalOffset" );
offset = Math.Min( offset, this.ExtentHeight - this.ViewportHeight );
if( !DoubleHelper.AreVirtuallyEqual( offset, _offset.Y ) )
{
_offset.Y = offset;
base.InvalidateMeasure();
}
}
public double VerticalOffset
{
get
{
if( this.ActiveLayout != null && this.ActiveLayout is IScrollInfo )
{
return ( ( IScrollInfo )this.ActiveLayout ).VerticalOffset;
}
return _offset.Y;
}
}
public double ViewportHeight
{
get
{
if( this.ActiveLayout != null && this.ActiveLayout is IScrollInfo )
{
return ( ( IScrollInfo )this.ActiveLayout ).ViewportHeight;
}
return _viewport.Height;
}
}
public double ViewportWidth
{
get
{
if( this.ActiveLayout != null && this.ActiveLayout is IScrollInfo )
{
return ( ( IScrollInfo )this.ActiveLayout ).ViewportWidth;
}
return _viewport.Width;
}
}
#endregion
#region Private Fields
internal AnimationPanel _currentLayoutPanel = null;
private readonly AnimationPanel _defaultLayoutCanvas = new Xceed.Wpf.Toolkit.Panels.WrapPanel();
private readonly Collection<SwitchPresenter> _presenters = new Collection<SwitchPresenter>();
private BitVector32 _cacheBits = new BitVector32( 0 );
private bool _allowHorizontal = false;
private bool _allowVertical = false;
private Vector _computedOffset = new Vector( 0.0, 0.0 );
private Size _extent = new Size( 0, 0 );
private Vector _offset = new Vector( 0, 0 );
private ScrollViewer _scrollOwner = null;
private Size _viewport;
#endregion
#region CacheBits Nested Type
private enum CacheBits
{
HasLoaded = 0x00000001,
}
#endregion
}
}