Scrolling Tabs in TabControl, Better horizontal scrolling
This commit is contained in:
1 parent
8f9fe6df49
commit
53c9bd7836
3 files changed
+138
-24
No files matched your search
@@ -17,6 +17,8 @@ namespace HandyControl.Controls
|
||||
|
||||
private bool _isRunning;
|
||||
|
||||
private Storyboard _scrollingAnimation = new Storyboard();
|
||||
|
||||
/// <summary>
|
||||
/// 滚动方向
|
||||
/// </summary>
|
||||
@@ -28,7 +30,7 @@ namespace HandyControl.Controls
|
||||
/// </summary>
|
||||
public Orientation Orientation
|
||||
{
|
||||
get => (Orientation) GetValue(OrientationProperty);
|
||||
get => (Orientation)GetValue(OrientationProperty);
|
||||
set => SetValue(OrientationProperty, value);
|
||||
}
|
||||
|
||||
@@ -43,7 +45,7 @@ namespace HandyControl.Controls
|
||||
/// </summary>
|
||||
public bool CanMouseWheel
|
||||
{
|
||||
get => (bool) GetValue(CanMouseWheelProperty);
|
||||
get => (bool)GetValue(CanMouseWheelProperty);
|
||||
set => SetValue(CanMouseWheelProperty, value);
|
||||
}
|
||||
|
||||
@@ -101,7 +103,7 @@ namespace HandyControl.Controls
|
||||
}
|
||||
|
||||
internal void ScrollToVerticalOffsetInternal(double offset, double milliseconds = 500)
|
||||
{
|
||||
{
|
||||
var animation = AnimationHelper.CreateAnimation(offset, milliseconds);
|
||||
animation.EasingFunction = new CubicEase
|
||||
{
|
||||
@@ -114,7 +116,11 @@ namespace HandyControl.Controls
|
||||
_isRunning = false;
|
||||
};
|
||||
_isRunning = true;
|
||||
BeginAnimation(CurrentVerticalOffsetProperty, animation);
|
||||
|
||||
_scrollingAnimation.Children.Add(animation);
|
||||
BeginStoryboard(_scrollingAnimation);
|
||||
|
||||
//BeginAnimation(CurrentVerticalOffsetProperty, animation);
|
||||
}
|
||||
|
||||
internal void ScrollToHorizontalOffsetInternal(double offset, double milliseconds = 500)
|
||||
@@ -131,7 +137,8 @@ namespace HandyControl.Controls
|
||||
_isRunning = false;
|
||||
};
|
||||
_isRunning = true;
|
||||
BeginAnimation(CurrentHorizontalOffsetProperty, animation);
|
||||
|
||||
BeginAnimation(CurrentHorizontalOffsetProperty, animation, HandoffBehavior.Compose);
|
||||
}
|
||||
|
||||
protected override HitTestResult HitTestCore(PointHitTestParameters hitTestParameters) =>
|
||||
@@ -150,7 +157,7 @@ namespace HandyControl.Controls
|
||||
|
||||
public static bool GetIsEnableInertia(DependencyObject element)
|
||||
{
|
||||
return (bool) element.GetValue(IsEnableInertiaProperty);
|
||||
return (bool)element.GetValue(IsEnableInertiaProperty);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -184,7 +191,7 @@ namespace HandyControl.Controls
|
||||
|
||||
public static bool GetIsPenetrating(DependencyObject element)
|
||||
{
|
||||
return (bool) element.GetValue(IsPenetratingProperty);
|
||||
return (bool)element.GetValue(IsPenetratingProperty);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -207,7 +214,7 @@ namespace HandyControl.Controls
|
||||
private double CurrentVerticalOffset
|
||||
{
|
||||
// ReSharper disable once UnusedMember.Local
|
||||
get => (double) GetValue(CurrentVerticalOffsetProperty);
|
||||
get => (double)GetValue(CurrentVerticalOffsetProperty);
|
||||
set => SetValue(CurrentVerticalOffsetProperty, value);
|
||||
}
|
||||
|
||||
@@ -230,7 +237,7 @@ namespace HandyControl.Controls
|
||||
/// </summary>
|
||||
public double CurrentHorizontalOffset
|
||||
{
|
||||
get => (double) GetValue(CurrentHorizontalOffsetProperty);
|
||||
get => (double)GetValue(CurrentHorizontalOffsetProperty);
|
||||
set => SetValue(CurrentHorizontalOffsetProperty, value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,16 +10,31 @@ namespace HandyControl.Controls
|
||||
{
|
||||
[TemplatePart(Name = OverflowButtonKey, Type = typeof(ContextMenuToggleButton))]
|
||||
[TemplatePart(Name = HeaderPanelKey, Type = typeof(TabPanel))]
|
||||
[TemplatePart(Name = OverflowScrollviewer, Type = typeof(ScrollViewer))]
|
||||
[TemplatePart(Name = OverflowButtonLeft, Type = typeof(Button))]
|
||||
[TemplatePart(Name = OverflowButtonRight, Type = typeof(Button))]
|
||||
public class TabControl : System.Windows.Controls.TabControl
|
||||
{
|
||||
private const string OverflowButtonKey = "PART_OverflowButton";
|
||||
|
||||
private const string HeaderPanelKey = "PART_HeaderPanel";
|
||||
|
||||
private const string OverflowScrollviewer = "PART_OverflowScrollviewer";
|
||||
|
||||
private const string OverflowButtonLeft = "PART_OverflowButtonLeft";
|
||||
|
||||
private const string OverflowButtonRight = "PART_OverflowButtonRight";
|
||||
|
||||
private ContextMenuToggleButton _buttonOverflow;
|
||||
|
||||
private TabPanel _headerPanel;
|
||||
|
||||
private ScrollViewer _scrollviewerOverflow;
|
||||
|
||||
private Button _buttonOverflowLeft;
|
||||
|
||||
private Button _buttonOverflowRight;
|
||||
|
||||
/// <summary>
|
||||
/// 是否为内部操作
|
||||
/// </summary>
|
||||
@@ -115,6 +130,16 @@ namespace HandyControl.Controls
|
||||
set => SetValue(TabItemHeightProperty, value);
|
||||
}
|
||||
|
||||
//TODO: Implement this
|
||||
public bool IsScrollable
|
||||
{
|
||||
get { return (bool)GetValue(IsScrollableProperty); }
|
||||
set { SetValue(IsScrollableProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty IsScrollableProperty =
|
||||
DependencyProperty.Register("IsScrollable", typeof(bool), typeof(TabControl), new PropertyMetadata(ValueBoxes.FalseBox));
|
||||
|
||||
/// <summary>
|
||||
/// 可见的标签数量
|
||||
/// </summary>
|
||||
@@ -133,7 +158,7 @@ namespace HandyControl.Controls
|
||||
if (!IsEnableTabFill)
|
||||
{
|
||||
_itemShowCount = (int)(ActualWidth / TabItemWidth);
|
||||
_buttonOverflow.Show(Items.Count > 0 && Items.Count >= _itemShowCount);
|
||||
_buttonOverflow.Show(Items.Count > 0 && Items.Count >= _itemShowCount);
|
||||
}
|
||||
|
||||
if (IsInternalAction)
|
||||
@@ -169,6 +194,33 @@ namespace HandyControl.Controls
|
||||
if (IsEnableTabFill) return;
|
||||
|
||||
_buttonOverflow = Template.FindName(OverflowButtonKey, this) as ContextMenuToggleButton;
|
||||
_scrollviewerOverflow = Template.FindName(OverflowScrollviewer, this) as ScrollViewer;
|
||||
_buttonOverflowLeft = Template.FindName(OverflowButtonLeft, this) as Button;
|
||||
_buttonOverflowRight = Template.FindName(OverflowButtonRight, this) as Button;
|
||||
|
||||
_buttonOverflowLeft.Click += (s, e) =>
|
||||
{
|
||||
var currentOffset = _scrollviewerOverflow.CurrentHorizontalOffset;
|
||||
var modulo = (currentOffset % TabItemWidth);
|
||||
var offset = currentOffset - (modulo == 0 ? TabItemWidth : modulo);
|
||||
|
||||
if (offset >= 0)
|
||||
{
|
||||
_scrollviewerOverflow.ScrollToHorizontalOffsetInternal(offset);
|
||||
}
|
||||
};
|
||||
|
||||
_buttonOverflowRight.Click += (s, e) =>
|
||||
{
|
||||
var currentOffset = _scrollviewerOverflow.CurrentHorizontalOffset;
|
||||
var offset = currentOffset + (TabItemWidth - (currentOffset % TabItemWidth));
|
||||
|
||||
if(offset <= _scrollviewerOverflow.ScrollableWidth)
|
||||
{
|
||||
_scrollviewerOverflow.ScrollToHorizontalOffsetInternal(offset);
|
||||
}
|
||||
};
|
||||
|
||||
if (_buttonOverflow != null)
|
||||
{
|
||||
_itemShowCount = (int)(ActualWidth / TabItemWidth);
|
||||
|
||||
Reference in new issue
Block a user