This commit is contained in:
NaBian committed 2019-11-17 13:32:14 +08:00
1 parent 334b2269b6
commit 4e14400307
9 files changed
+225 -89

No files matched your search

@@ -0,0 +1,9 @@
namespace HandyControlDemo.Data
{
public class TabControlDemoModel
{
public string Header { get; set; }
public string BackgroundToken { get; set; }
}
}
@@ -22,6 +22,7 @@
<Compile Include="$(MSBuildThisFileDirectory)Data\Model\CoverViewDemoModel.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Data\Model\DemoDataModel.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Data\Model\StepBarDemoModel.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Data\Model\TabControlDemoModel.cs" />
<Compile Include="$(MSBuildThisFileDirectory)MainWindow.xaml.cs">
<SubType>Code</SubType>
<DependentUpon>MainWindow.xaml</DependentUpon>
@@ -13,6 +13,38 @@ namespace HandyControlDemo.Service
{
public class DataService
{
internal ObservableCollection<TabControlDemoModel> GetTabControlDemoDataList()
{
return new ObservableCollection<TabControlDemoModel>
{
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<DemoDataModel> GetDemoDataList()
{
var list = new List<DemoDataModel>();
@@ -18,32 +18,7 @@
<Label Style="{StaticResource LabelPrimary}" Content="Default" Margin="32,32,0,0" HorizontalAlignment="Left"/>
<hc:TabControl ShowOverflowButton="False" ShowScrollButton="True" Margin="32,16,32,0" Width="800" Height="300" IsScrollable="True">
<hc:TabItem Header="TabItem1" IsSelected="True">
<!--<hc:SimplePanel Background="White"/>-->
<hc:TransitioningContentControl>
<StackPanel Margin="32">
<Slider Value="50" Name="SliderDemo" Maximum="100"/>
<StackPanel Orientation="Horizontal" Margin="0,32,0,0">
<hc:CircleProgressBar Value="{Binding Value,ElementName=SliderDemo}"/>
<hc:CircleProgressBar Value="{Binding Value,ElementName=SliderDemo}" FontSize="30" Margin="16,0,0,0"/>
<hc:CircleProgressBar Value="{Binding Value,ElementName=SliderDemo}" Margin="16,0,0,0" ShowText="False" Width="20" Height="20" ArcThickness="2" Style="{StaticResource ProgressBarSuccessCircle}"/>
<hc:CircleProgressBar Value="{Binding Value,ElementName=SliderDemo}" Margin="16,0,0,0" ShowText="False" Width="30" Height="30" ArcThickness="6" Style="{StaticResource ProgressBarInfoCircle}"/>
<hc:CircleProgressBar Value="{Binding Value,ElementName=SliderDemo}" Margin="16,0,0,0" ShowText="False" Width="40" Height="40" ArcThickness="10" Style="{StaticResource ProgressBarWarningCircle}"/>
<hc:CircleProgressBar Value="{Binding Value,ElementName=SliderDemo}" Margin="16,0,0,0" Width="50" Height="50" Style="{StaticResource ProgressBarDangerCircle}"/>
</StackPanel>
<StackPanel Orientation="Horizontal" Margin="0,32,0,0">
<hc:WaveProgressBar Value="{Binding Value,ElementName=SliderDemo}"/>
<hc:WaveProgressBar Value="{Binding Value,ElementName=SliderDemo}" FontSize="20" Margin="16,0,0,0" WaveThickness="4" WaveStroke="#FFFF0080">
<hc:WaveProgressBar.WaveFill>
<LinearGradientBrush EndPoint="0,1" StartPoint="0,0">
<GradientStop Color="#66FF0080" Offset="0"/>
<GradientStop Color="#FFFF0080" Offset="1"/>
</LinearGradientBrush>
</hc:WaveProgressBar.WaveFill>
</hc:WaveProgressBar>
<hc:WaveProgressBar Value="{Binding Value,ElementName=SliderDemo}" Margin="16,0,0,0" ShowText="False" Width="50" Height="50" Style="{StaticResource ProgressBarWarningWave}"/>
</StackPanel>
</StackPanel>
</hc:TransitioningContentControl>
<hc:SimplePanel Background="White"/>
</hc:TabItem>
<hc:TabItem Header="TabItem2">
<hc:SimplePanel Background="{DynamicResource DarkDangerBrush}"/>
@@ -70,12 +45,12 @@
<Label Style="{StaticResource LabelPrimary}" Margin="16,0,0,0" Content="IsDraggable = True"/>
<Label Style="{StaticResource LabelPrimary}" Margin="16,0,0,0" Content="IsEnableAnimation = True"/>
</StackPanel>
<hc:TabControl IsEnableAnimation="True" ShowCloseButton="True" IsDraggable="True" IsEnableTabFill="True" Margin="32,0,32,32" Width="800" Height="300">
<hc:TabControl x:Name="TabControlDemo" IsEnableAnimation="True" ShowCloseButton="True" IsDraggable="True" IsEnableTabFill="True" Margin="32,0,32,32" Width="800" Height="300">
<hc:TabItem Header="TabItem1">
<hc:SimplePanel Background="White"/>
</hc:TabItem>
<hc:TabItem IsSelected="True" Header="TabItem2">
<hc:SimplePanel Background="#FFE8563F"/>
<hc:SimplePanel Tag="123" Background="#FFE8563F"/>
</hc:TabItem>
<hc:TabItem Header="TabItem3">
<hc:SimplePanel Background="#FF3F4EE8"/>
@@ -93,6 +68,18 @@
<hc:SimplePanel Background="#FFE8E03F"/>
</hc:TabItem>
</hc:TabControl>
<hc:TabControl IsEnableAnimation="True" ShowCloseButton="True" IsDraggable="True" ItemsSource="{Binding DataList}" Width="800" Height="300">
<TabControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Header}"/>
</DataTemplate>
</TabControl.ItemTemplate>
<TabControl.ContentTemplate>
<DataTemplate>
<hc:SimplePanel HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Background="{Binding BackgroundToken,Converter={StaticResource String2BrushConverter}}"/>
</DataTemplate>
</TabControl.ContentTemplate>
</hc:TabControl>
</StackPanel>
</hc:ScrollViewer>
</hc:TransitioningContentControl>
@@ -1,5 +1,4 @@
namespace HandyControlDemo.UserControl
namespace HandyControlDemo.UserControl
{
public partial class TabControlDemoCtl
{
@@ -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<TabControlDemoModel>
{
public TabControlDemoViewModel(DataService dataService) => DataList = dataService.GetTabControlDemoDataList();
public RelayCommand<CancelRoutedEventArgs> ClosingCmd => new Lazy<RelayCommand<CancelRoutedEventArgs>>(() =>
new RelayCommand<CancelRoutedEventArgs>(Closing)).Value;
@@ -14,6 +14,7 @@ namespace HandyControlDemo.ViewModel
ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);
SimpleIoc.Default.Register<DataService>();
var dataService = ServiceLocator.Current.GetInstance<DataService>();
SimpleIoc.Default.Register<MainViewModel>();
SimpleIoc.Default.Register(() => new GrowlDemoViewModel(), "GrowlDemo");
@@ -21,9 +22,9 @@ namespace HandyControlDemo.ViewModel
SimpleIoc.Default.Register<ImageBrowserDemoViewModel>();
SimpleIoc.Default.Register<ComboBoxDemoViewModel>();
SimpleIoc.Default.Register<WindowDemoViewModel>();
SimpleIoc.Default.Register(() => new ItemsDisplayViewModel(ServiceLocator.Current.GetInstance<DataService>().GetContributorDataList), "Contributors");
SimpleIoc.Default.Register(() => new ItemsDisplayViewModel(ServiceLocator.Current.GetInstance<DataService>().GetBlogDataList), "Blogs");
SimpleIoc.Default.Register(() => new ItemsDisplayViewModel(ServiceLocator.Current.GetInstance<DataService>().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<StepBarDemoViewModel>();
SimpleIoc.Default.Register<PaginationDemoViewModel>();
SimpleIoc.Default.Register<ChatBoxViewModel>();
@@ -85,7 +86,7 @@ namespace HandyControlDemo.ViewModel
public SideMenuDemoViewModel SideMenuDemo => ServiceLocator.Current.GetInstance<SideMenuDemoViewModel>();
public TabControlDemoViewModel TabControlDemo => ServiceLocator.Current.GetInstance<TabControlDemoViewModel>();
public TabControlDemoViewModel TabControlDemo => new TabControlDemoViewModel(ServiceLocator.Current.GetInstance<DataService>());
public NoUserViewModel NoUser => ServiceLocator.Current.GetInstance<NoUserViewModel>();
@@ -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();
}
}
@@ -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
/// </summary>
private double _scrollHorizontalOffset;
private TabPanel _tabPanel;
/// <summary>
/// 标签容器
/// </summary>
internal TabPanel TabPanel { get; set; }
internal TabPanel TabPanel
{
get => _tabPanel ??= TabControlParent.HeaderPanel;
set => _tabPanel = value;
}
/// <summary>
/// 当前编号
@@ -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<TabControl>(() => 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
/// </summary>
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();