diff --git a/src/Shared/HandyControlDemo_Shared/Data/Model/TabControlDemoModel.cs b/src/Shared/HandyControlDemo_Shared/Data/Model/TabControlDemoModel.cs
new file mode 100644
index 00000000..5f27697e
--- /dev/null
+++ b/src/Shared/HandyControlDemo_Shared/Data/Model/TabControlDemoModel.cs
@@ -0,0 +1,9 @@
+namespace HandyControlDemo.Data
+{
+ public class TabControlDemoModel
+ {
+ public string Header { get; set; }
+
+ public string BackgroundToken { get; set; }
+ }
+}
diff --git a/src/Shared/HandyControlDemo_Shared/HandyControlDemo_Shared.projitems b/src/Shared/HandyControlDemo_Shared/HandyControlDemo_Shared.projitems
index 35d3356f..ec4ff019 100644
--- a/src/Shared/HandyControlDemo_Shared/HandyControlDemo_Shared.projitems
+++ b/src/Shared/HandyControlDemo_Shared/HandyControlDemo_Shared.projitems
@@ -22,6 +22,7 @@
+
Code
MainWindow.xaml
diff --git a/src/Shared/HandyControlDemo_Shared/Service/Data/DataService.cs b/src/Shared/HandyControlDemo_Shared/Service/Data/DataService.cs
index 0ea49299..17128d90 100644
--- a/src/Shared/HandyControlDemo_Shared/Service/Data/DataService.cs
+++ b/src/Shared/HandyControlDemo_Shared/Service/Data/DataService.cs
@@ -13,6 +13,38 @@ namespace HandyControlDemo.Service
{
public class DataService
{
+ internal ObservableCollection GetTabControlDemoDataList()
+ {
+ return new ObservableCollection
+ {
+ new TabControlDemoModel
+ {
+ Header = "Success",
+ BackgroundToken = ResourceToken.SuccessBrush
+ },
+ new TabControlDemoModel
+ {
+ Header = "Primary",
+ BackgroundToken = ResourceToken.PrimaryBrush
+ },
+ new TabControlDemoModel
+ {
+ Header = "Warning",
+ BackgroundToken = ResourceToken.WarningBrush
+ },
+ new TabControlDemoModel
+ {
+ Header = "Danger",
+ BackgroundToken = ResourceToken.DangerBrush
+ },
+ new TabControlDemoModel
+ {
+ Header = "Info",
+ BackgroundToken = ResourceToken.InfoBrush
+ }
+ };
+ }
+
internal List GetDemoDataList()
{
var list = new List();
diff --git a/src/Shared/HandyControlDemo_Shared/UserControl/Controls/TabControlDemoCtl.xaml b/src/Shared/HandyControlDemo_Shared/UserControl/Controls/TabControlDemoCtl.xaml
index 490a8b1c..5fc6801b 100644
--- a/src/Shared/HandyControlDemo_Shared/UserControl/Controls/TabControlDemoCtl.xaml
+++ b/src/Shared/HandyControlDemo_Shared/UserControl/Controls/TabControlDemoCtl.xaml
@@ -18,32 +18,7 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
@@ -70,12 +45,12 @@
-
+
-
+
@@ -93,6 +68,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Shared/HandyControlDemo_Shared/UserControl/Controls/TabControlDemoCtl.xaml.cs b/src/Shared/HandyControlDemo_Shared/UserControl/Controls/TabControlDemoCtl.xaml.cs
index 32d10ea9..7df67fc8 100644
--- a/src/Shared/HandyControlDemo_Shared/UserControl/Controls/TabControlDemoCtl.xaml.cs
+++ b/src/Shared/HandyControlDemo_Shared/UserControl/Controls/TabControlDemoCtl.xaml.cs
@@ -1,5 +1,4 @@
-
-namespace HandyControlDemo.UserControl
+namespace HandyControlDemo.UserControl
{
public partial class TabControlDemoCtl
{
diff --git a/src/Shared/HandyControlDemo_Shared/ViewModel/Controls/TabControlDemoViewModel.cs b/src/Shared/HandyControlDemo_Shared/ViewModel/Controls/TabControlDemoViewModel.cs
index d82c4254..0546ae7b 100644
--- a/src/Shared/HandyControlDemo_Shared/ViewModel/Controls/TabControlDemoViewModel.cs
+++ b/src/Shared/HandyControlDemo_Shared/ViewModel/Controls/TabControlDemoViewModel.cs
@@ -1,8 +1,9 @@
using System;
using System.Windows;
-using GalaSoft.MvvmLight;
using HandyControl.Controls;
using HandyControl.Data;
+using HandyControlDemo.Data;
+using HandyControlDemo.Service;
#if netle40
using GalaSoft.MvvmLight.Command;
#else
@@ -11,8 +12,10 @@ using GalaSoft.MvvmLight.CommandWpf;
namespace HandyControlDemo.ViewModel
{
- public class TabControlDemoViewModel : ViewModelBase
+ public class TabControlDemoViewModel : DemoViewModelBase
{
+ public TabControlDemoViewModel(DataService dataService) => DataList = dataService.GetTabControlDemoDataList();
+
public RelayCommand ClosingCmd => new Lazy>(() =>
new RelayCommand(Closing)).Value;
diff --git a/src/Shared/HandyControlDemo_Shared/ViewModel/ViewModelLocator.cs b/src/Shared/HandyControlDemo_Shared/ViewModel/ViewModelLocator.cs
index 3910168c..9a65e1ea 100644
--- a/src/Shared/HandyControlDemo_Shared/ViewModel/ViewModelLocator.cs
+++ b/src/Shared/HandyControlDemo_Shared/ViewModel/ViewModelLocator.cs
@@ -14,6 +14,7 @@ namespace HandyControlDemo.ViewModel
ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);
SimpleIoc.Default.Register();
+ var dataService = ServiceLocator.Current.GetInstance();
SimpleIoc.Default.Register();
SimpleIoc.Default.Register(() => new GrowlDemoViewModel(), "GrowlDemo");
@@ -21,9 +22,9 @@ namespace HandyControlDemo.ViewModel
SimpleIoc.Default.Register();
SimpleIoc.Default.Register();
SimpleIoc.Default.Register();
- SimpleIoc.Default.Register(() => new ItemsDisplayViewModel(ServiceLocator.Current.GetInstance().GetContributorDataList), "Contributors");
- SimpleIoc.Default.Register(() => new ItemsDisplayViewModel(ServiceLocator.Current.GetInstance().GetBlogDataList), "Blogs");
- SimpleIoc.Default.Register(() => new ItemsDisplayViewModel(ServiceLocator.Current.GetInstance().GetProjectDataList), "Projects");
+ SimpleIoc.Default.Register(() => new ItemsDisplayViewModel(dataService.GetContributorDataList), "Contributors");
+ SimpleIoc.Default.Register(() => new ItemsDisplayViewModel(dataService.GetBlogDataList), "Blogs");
+ SimpleIoc.Default.Register(() => new ItemsDisplayViewModel(dataService.GetProjectDataList), "Projects");
SimpleIoc.Default.Register();
SimpleIoc.Default.Register();
SimpleIoc.Default.Register();
@@ -85,7 +86,7 @@ namespace HandyControlDemo.ViewModel
public SideMenuDemoViewModel SideMenuDemo => ServiceLocator.Current.GetInstance();
- public TabControlDemoViewModel TabControlDemo => ServiceLocator.Current.GetInstance();
+ public TabControlDemoViewModel TabControlDemo => new TabControlDemoViewModel(ServiceLocator.Current.GetInstance());
public NoUserViewModel NoUser => ServiceLocator.Current.GetInstance();
diff --git a/src/Shared/HandyControl_Shared/Controls/TabControl/TabControl.cs b/src/Shared/HandyControl_Shared/Controls/TabControl/TabControl.cs
index a75c276a..4344f41d 100644
--- a/src/Shared/HandyControl_Shared/Controls/TabControl/TabControl.cs
+++ b/src/Shared/HandyControl_Shared/Controls/TabControl/TabControl.cs
@@ -32,7 +32,7 @@ namespace HandyControl.Controls
private ContextMenuToggleButton _buttonOverflow;
- private TabPanel _headerPanel;
+ internal TabPanel HeaderPanel { get; private set; }
private ScrollViewer _scrollViewerOverflow;
@@ -218,7 +218,7 @@ namespace HandyControl.Controls
{
base.OnItemsChanged(e);
- if (_headerPanel == null)
+ if (HeaderPanel == null)
{
IsInternalAction = false;
return;
@@ -235,21 +235,23 @@ namespace HandyControl.Controls
IsInternalAction = false;
return;
}
+
if (IsEnableAnimation)
{
- _headerPanel.SetCurrentValue(TabPanel.FluidMoveDurationProperty, new Duration(TimeSpan.FromMilliseconds(200)));
+ HeaderPanel.SetCurrentValue(TabPanel.FluidMoveDurationProperty, new Duration(TimeSpan.FromMilliseconds(200)));
}
else
{
- _headerPanel.FluidMoveDuration = new Duration(TimeSpan.FromSeconds(0));
+ HeaderPanel.FluidMoveDuration = new Duration(TimeSpan.FromSeconds(0));
}
+
if (e.Action == NotifyCollectionChangedAction.Add)
{
- foreach (TabItem item in e.NewItems)
+ for (var i = 0; i < Items.Count; i++)
{
+ if (!(ItemContainerGenerator.ContainerFromIndex(i) is TabItem item)) return;
item.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
- item.IsSelected = true;
- item.TabPanel = _headerPanel;
+ item.TabPanel = HeaderPanel;
}
}
@@ -275,7 +277,7 @@ namespace HandyControl.Controls
if (_buttonScrollRight != null) _buttonScrollRight.Click -= ButtonScrollRight_Click;
base.OnApplyTemplate();
- _headerPanel = GetTemplateChild(HeaderPanelKey) as TabPanel;
+ HeaderPanel = GetTemplateChild(HeaderPanelKey) as TabPanel;
if (IsEnableTabFill) return;
@@ -290,7 +292,13 @@ namespace HandyControl.Controls
if (_buttonOverflow != null)
{
- _itemShowCount = (int)(ActualWidth / TabItemWidth);
+ if (ItemsSource != null)
+ {
+ Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
+ }
+
+ var size = DesiredSize;
+ _itemShowCount = (int)(size.Width / TabItemWidth);
_buttonOverflow.Show(ShowOverflowButton && Items.Count > 0 && Items.Count >= _itemShowCount);
var menu = new ContextMenu
@@ -319,35 +327,50 @@ namespace HandyControl.Controls
if (_buttonOverflow.IsChecked == true)
{
_buttonOverflow.Menu.Items.Clear();
- foreach (TabItem item in Items)
+ for (var i = 0; i < Items.Count; i++)
{
+ if(!(ItemContainerGenerator.ContainerFromIndex(i) is TabItem item)) continue;
+
var menuItem = new MenuItem
{
+ HeaderStringFormat = ItemStringFormat,
+ HeaderTemplate = ItemTemplate,
+ HeaderTemplateSelector = ItemTemplateSelector,
Header = item.Header,
Width = TabItemWidth,
IsChecked = item.IsSelected,
IsCheckable = true
};
+
menuItem.Click += delegate
{
_buttonOverflow.IsChecked = false;
- var index = Items.IndexOf(item);
+
+ var list = GetActuaList();
+ if (list == null) return;
+
+ var actualItem = ItemContainerGenerator.ItemFromContainer(item);
+ if (actualItem == null) return;
+
+ var index = list.IndexOf(actualItem);
if (index >= _itemShowCount)
{
- Items.Remove(item);
- Items.Insert(0, item);
+ list.Remove(actualItem);
+ list.Insert(0, actualItem);
if (IsEnableAnimation)
{
- _headerPanel.SetCurrentValue(TabPanel.FluidMoveDurationProperty, new Duration(TimeSpan.FromMilliseconds(200)));
+ HeaderPanel.SetCurrentValue(TabPanel.FluidMoveDurationProperty, new Duration(TimeSpan.FromMilliseconds(200)));
}
else
{
- _headerPanel.FluidMoveDuration = new Duration(TimeSpan.FromSeconds(0));
+ HeaderPanel.FluidMoveDuration = new Duration(TimeSpan.FromSeconds(0));
}
- _headerPanel.ForceUpdate = true;
- _headerPanel.Measure(new Size(_headerPanel.DesiredSize.Width, ActualHeight));
- _headerPanel.ForceUpdate = false;
+ HeaderPanel.ForceUpdate = true;
+ HeaderPanel.Measure(new Size(HeaderPanel.DesiredSize.Width, ActualHeight));
+ HeaderPanel.ForceUpdate = false;
+ SetCurrentValue(SelectedIndexProperty, 0);
}
+
item.IsSelected = true;
};
_buttonOverflow.Menu.Items.Add(menuItem);
@@ -366,26 +389,52 @@ namespace HandyControl.Controls
internal void CloseOtherItems(TabItem currentItem)
{
+ var actualItem = currentItem != null ? ItemContainerGenerator.ItemFromContainer(currentItem) : null;
+
+ var list = GetActuaList();
+ if (list == null) return;
+
IsInternalAction = true;
- var enumerator = ((IEnumerable)Items).GetEnumerator();
- while (enumerator.MoveNext())
+
+ for (var i = 0; i < Items.Count; i++)
{
- var item = enumerator.Current;
- if (!Equals(item, currentItem) && item != null)
+ var item = list[i];
+ if (!Equals(item, actualItem) && item != null)
{
var argsClosing = new CancelRoutedEventArgs(TabItem.ClosingEvent, item);
- var elment = item as UIElement;
- if (elment != null)
- {
- elment.RaiseEvent(argsClosing);
- if (argsClosing.Cancel) return;
- }
- elment?.RaiseEvent(new RoutedEventArgs(TabItem.ClosedEvent, item));
- Items.Remove(item);
- enumerator = ((IEnumerable)Items).GetEnumerator();
+ if (!(ItemContainerGenerator.ContainerFromItem(item) is TabItem tabItem)) continue;
+
+ tabItem.RaiseEvent(argsClosing);
+ if (argsClosing.Cancel) return;
+
+ tabItem.RaiseEvent(new RoutedEventArgs(TabItem.ClosedEvent, item));
+ list.Remove(item);
+
+ i--;
}
}
+
+ SetCurrentValue(SelectedIndexProperty, Items.Count == 0 ? -1 : 0);
}
+
+ internal IList GetActuaList()
+ {
+ IList list;
+ if (ItemsSource != null)
+ {
+ list = ItemsSource as IList;
+ }
+ else
+ {
+ list = Items;
+ }
+
+ return list;
+ }
+
+ protected override bool IsItemItsOwnContainerOverride(object item) => item is TabItem;
+
+ protected override DependencyObject GetContainerForItemOverride() => new TabItem();
}
}
\ No newline at end of file
diff --git a/src/Shared/HandyControl_Shared/Controls/TabControl/TabItem.cs b/src/Shared/HandyControl_Shared/Controls/TabControl/TabItem.cs
index 6dd93a30..e78a4491 100644
--- a/src/Shared/HandyControl_Shared/Controls/TabControl/TabItem.cs
+++ b/src/Shared/HandyControl_Shared/Controls/TabControl/TabItem.cs
@@ -1,6 +1,7 @@
using System;
using System.Windows;
using System.Windows.Controls;
+using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Input;
using System.Windows.Media;
@@ -94,10 +95,16 @@ namespace HandyControl.Controls
///
private double _scrollHorizontalOffset;
+ private TabPanel _tabPanel;
+
///
/// 标签容器
///
- internal TabPanel TabPanel { get; set; }
+ internal TabPanel TabPanel
+ {
+ get => _tabPanel ??= TabControlParent.HeaderPanel;
+ set => _tabPanel = value;
+ }
///
/// 当前编号
@@ -180,7 +187,12 @@ namespace HandyControl.Controls
{
if (IsLoaded && menu != null)
{
- menu.DataContext = this;
+ var parent = TabControlParent;
+ if (parent == null) return;
+
+ var item = parent.ItemContainerGenerator.ItemFromContainer(this);
+
+ menu.DataContext = item;
menu.SetBinding(IsEnabledProperty, new Binding(ShowContextMenuProperty.Name)
{
Source = this
@@ -226,7 +238,7 @@ namespace HandyControl.Controls
Loaded += (s, e) => OnMenuChanged(Menu);
}
- private TabControl TabControlParent => new Lazy(() => ItemsControl.ItemsControlFromItemContainer(this) as TabControl).Value;
+ private TabControl TabControlParent => ItemsControl.ItemsControlFromItemContainer(this) as TabControl;
protected override void OnMouseRightButtonDown(MouseButtonEventArgs e)
{
@@ -249,38 +261,49 @@ namespace HandyControl.Controls
internal void Close()
{
- var argsClosing = new CancelRoutedEventArgs(ClosingEvent, this);
+ var parent = TabControlParent;
+ if (parent == null) return;
+
+ var item = parent.ItemContainerGenerator.ItemFromContainer(this);
+
+ var argsClosing = new CancelRoutedEventArgs(ClosingEvent, item);
RaiseEvent(argsClosing);
if (argsClosing.Cancel) return;
- TabPanel.SetCurrentValue(TabPanel.FluidMoveDurationProperty,
- TabControlParent.IsEnableAnimation
+ TabPanel.SetCurrentValue(TabPanel.FluidMoveDurationProperty, parent.IsEnableAnimation
? new Duration(TimeSpan.FromMilliseconds(200))
: new Duration(TimeSpan.FromMilliseconds(1)));
- TabControlParent.IsInternalAction = true;
- RaiseEvent(new RoutedEventArgs(ClosedEvent, this));
- TabControlParent.Items.Remove(this);
+
+ parent.IsInternalAction = true;
+ RaiseEvent(new RoutedEventArgs(ClosedEvent, item));
+
+ var list = parent.GetActuaList();
+ list?.Remove(item);
}
protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
{
base.OnMouseLeftButtonDown(e);
- if (TabControlParent.IsDraggable && !ItemIsDragging && !_isDragging)
+
+ var parent = TabControlParent;
+ if (parent == null) return;
+
+ if (parent.IsDraggable && !ItemIsDragging && !_isDragging)
{
- TabControlParent.UpdateScroll();
+ parent.UpdateScroll();
TabPanel.FluidMoveDuration = new Duration(TimeSpan.FromSeconds(0));
_mouseDownOffsetX = RenderTransform.Value.OffsetX;
- _scrollHorizontalOffset = TabControlParent.GetHorizontalOffset();
- var mx = TranslatePoint(new Point(), TabControlParent).X + _scrollHorizontalOffset;
+ _scrollHorizontalOffset = parent.GetHorizontalOffset();
+ var mx = TranslatePoint(new Point(), parent).X + _scrollHorizontalOffset;
_mouseDownIndex = CalLocationIndex(mx);
var subIndex = _mouseDownIndex - CalLocationIndex(_scrollHorizontalOffset);
_maxMoveLeft = -subIndex * ItemWidth;
- _maxMoveRight = TabControlParent.ActualWidth - ActualWidth + _maxMoveLeft;
+ _maxMoveRight = parent.ActualWidth - ActualWidth + _maxMoveLeft;
_isDragging = true;
ItemIsDragging = true;
_isWaiting = true;
- _dragPoint = e.GetPosition(TabControlParent);
+ _dragPoint = e.GetPosition(parent);
_dragPoint = new Point(_dragPoint.X + +_scrollHorizontalOffset, _dragPoint.Y);
_mouseDownPoint = _dragPoint;
CaptureMouse();
@@ -290,18 +313,26 @@ namespace HandyControl.Controls
protected override void OnMouseMove(MouseEventArgs e)
{
base.OnMouseMove(e);
+
if (ItemIsDragging && _isDragging)
{
- var subX = TranslatePoint(new Point(), TabControlParent).X + _scrollHorizontalOffset;
+ var parent = TabControlParent;
+ if (parent == null) return;
+
+ var subX = TranslatePoint(new Point(), parent).X + _scrollHorizontalOffset;
CurrentIndex = CalLocationIndex(subX);
- var p = e.GetPosition(TabControlParent);
+
+ var p = e.GetPosition(parent);
p = new Point(p.X + _scrollHorizontalOffset, p.Y);
+
var subLeft = p.X - _dragPoint.X;
var totalLeft = p.X - _mouseDownPoint.X;
if (Math.Abs(subLeft) <= WaitLength && _isWaiting) return;
+
_isWaiting = false;
_isDragged = true;
+
var left = subLeft + RenderTransform.Value.OffsetX;
if (totalLeft < _maxMoveLeft)
{
@@ -311,6 +342,7 @@ namespace HandyControl.Controls
{
left = _maxMoveRight + _mouseDownOffsetX;
}
+
var t = new TranslateTransform(left, 0);
RenderTransform = t;
_dragPoint = p;
@@ -320,15 +352,21 @@ namespace HandyControl.Controls
protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e)
{
base.OnMouseLeftButtonUp(e);
+
ReleaseMouseCapture();
+
if (_isDragged)
{
- var subX = TranslatePoint(new Point(), TabControlParent).X + _scrollHorizontalOffset;
+ var parent = TabControlParent;
+ if (parent == null) return;
+
+ var subX = TranslatePoint(new Point(), parent).X + _scrollHorizontalOffset;
var index = CalLocationIndex(subX);
var left = index * ItemWidth;
var offsetX = RenderTransform.Value.OffsetX;
CreateAnimation(offsetX, offsetX - subX + left, index);
}
+
_isDragging = false;
ItemIsDragging = false;
_isDragged = false;
@@ -339,29 +377,46 @@ namespace HandyControl.Controls
///
internal void CreateAnimation(double offsetX, double resultX, int index = -1)
{
+ var parent = TabControlParent;
+
void AnimationCompleted()
{
RenderTransform = new TranslateTransform(resultX, 0);
if (index == -1) return;
- var parent = TabControlParent;
+
+ var list = parent.GetActuaList();
+ if (list == null) return;
+
+ var item = parent.ItemContainerGenerator.ItemFromContainer(this);
+ if (item == null) return;
+
TabPanel.CanUpdate = false;
parent.IsInternalAction = true;
- parent.Items.Remove(this);
+
+ list.Remove(item);
parent.IsInternalAction = true;
- parent.Items.Insert(index, this);
+ list.Insert(index, item);
TabPanel.CanUpdate = true;
TabPanel.ForceUpdate = true;
TabPanel.Measure(new Size(TabPanel.DesiredSize.Width, ActualHeight));
TabPanel.ForceUpdate = false;
+
Focus();
IsSelected = true;
+
+ if (!IsMouseCaptured)
+ {
+ parent.SetCurrentValue(Selector.SelectedIndexProperty, _currentIndex);
+ }
}
+
TargetOffsetX = resultX;
- if (!TabControlParent.IsEnableAnimation)
+ if (!parent.IsEnableAnimation)
{
AnimationCompleted();
return;
}
+
var animation = AnimationHelper.CreateAnimation(resultX, AnimationSpeed);
animation.FillBehavior = FillBehavior.Stop;
animation.Completed += (s1, e1) => AnimationCompleted();