diff --git a/ChangeLog.txt b/ChangeLog.txt index f69316d0..6a3c4ef5 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -1,3 +1,13 @@ +2018.09.04 Version 1.2.1 +* new controls + - add TabControl + - add ContextMenuButton + - add ContextMenuToggleButton + +* other +- update HandyControlDemo UI +- Localization + 2018.09.04 Version 1.2.0 * new controls - add Growl diff --git a/HandyControl/Controls/Button/ContextMenuButton.cs b/HandyControl/Controls/Button/ContextMenuButton.cs new file mode 100644 index 00000000..a1136b2f --- /dev/null +++ b/HandyControl/Controls/Button/ContextMenuButton.cs @@ -0,0 +1,23 @@ +using System.Windows.Controls; + +// ReSharper disable once CheckNamespace +namespace HandyControl.Controls +{ + /// + /// 带上下文菜单的按钮 + /// + public class ContextMenuButton : Button + { + public ContextMenu Menu { get; set; } + + protected override void OnClick() + { + base.OnClick(); + if (Menu != null) + { + Menu.PlacementTarget = this; + Menu.IsOpen = true; + } + } + } +} \ No newline at end of file diff --git a/HandyControl/Controls/Button/ContextMenuToggleButton.cs b/HandyControl/Controls/Button/ContextMenuToggleButton.cs new file mode 100644 index 00000000..4af71b2a --- /dev/null +++ b/HandyControl/Controls/Button/ContextMenuToggleButton.cs @@ -0,0 +1,31 @@ +using System.Windows.Controls; +using System.Windows.Controls.Primitives; + +// ReSharper disable once CheckNamespace +namespace HandyControl.Controls +{ + /// + /// 带上下文菜单的切换按钮 + /// + public class ContextMenuToggleButton : ToggleButton + { + public ContextMenu Menu { get; set; } + + protected override void OnClick() + { + base.OnClick(); + if (Menu != null) + { + if (IsChecked == true) + { + Menu.PlacementTarget = this; + Menu.IsOpen = true; + } + else + { + Menu.IsOpen = false; + } + } + } + } +} \ No newline at end of file diff --git a/HandyControl/Controls/ColorPicker.xaml b/HandyControl/Controls/ColorPicker.xaml index 2e0005c6..efb8bfd1 100644 --- a/HandyControl/Controls/ColorPicker.xaml +++ b/HandyControl/Controls/ColorPicker.xaml @@ -8,6 +8,7 @@ mc:Ignorable="d" Name="UserControlMain" Width="230" + xmlns:langs="clr-namespace:HandyControl.Properties.Langs" UseLayoutRounding="True"> @@ -86,8 +87,8 @@ - - + + diff --git a/HandyControl/Controls/Growl.xaml.cs b/HandyControl/Controls/Growl.xaml.cs index 11b72942..31e3ac50 100644 --- a/HandyControl/Controls/Growl.xaml.cs +++ b/HandyControl/Controls/Growl.xaml.cs @@ -108,16 +108,12 @@ namespace HandyControl.Controls GrowlPanel = panel; var menuItem = new MenuItem { - Header = "清空消息" + Header = Properties.Langs.Lang.Clear }; menuItem.Click += (s, e) => { foreach (var item in GrowlPanel.Children.OfType()) { - //if (item.CloseAction != null) - //{ - // item.Close(); - //} item.Close(); } }; diff --git a/HandyControl/Controls/Info/InfoNumericUpDown.xaml b/HandyControl/Controls/Info/InfoNumericUpDown.xaml index 9609429f..519e5614 100644 --- a/HandyControl/Controls/Info/InfoNumericUpDown.xaml +++ b/HandyControl/Controls/Info/InfoNumericUpDown.xaml @@ -44,7 +44,7 @@ - + @@ -56,7 +56,7 @@ - + diff --git a/HandyControl/Controls/Info/InfoTextBox.xaml b/HandyControl/Controls/Info/InfoTextBox.xaml index 9cf02129..18930a13 100644 --- a/HandyControl/Controls/Info/InfoTextBox.xaml +++ b/HandyControl/Controls/Info/InfoTextBox.xaml @@ -43,7 +43,7 @@ - + @@ -54,7 +54,7 @@ - + diff --git a/HandyControl/Controls/TabControl/TabControl.cs b/HandyControl/Controls/TabControl/TabControl.cs new file mode 100644 index 00000000..38e24b2f --- /dev/null +++ b/HandyControl/Controls/TabControl/TabControl.cs @@ -0,0 +1,225 @@ +using System; +using System.Collections.Specialized; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Controls.Primitives; +using HandyControl.Tools.Extension; + +// ReSharper disable once CheckNamespace +namespace HandyControl.Controls +{ + [TemplatePart(Name = OverflowButtonKey, Type = typeof(ContextMenuToggleButton))] + [TemplatePart(Name = HeaderPanelKey, Type = typeof(TabPanel))] + public class TabControl : System.Windows.Controls.TabControl + { + private const string OverflowButtonKey = "PART_OverflowButton"; + + private const string HeaderPanelKey = "PART_HeaderPanel"; + + private ContextMenuToggleButton _buttonOverflow; + + private TabPanel _headerPanel; + + /// + /// 是否为内部操作 + /// + internal bool IsInternalAction; + + /// + /// 是否启用动画 + /// + public static readonly DependencyProperty IsEnableAnimationProperty = DependencyProperty.Register( + "IsEnableAnimation", typeof(bool), typeof(TabControl), new PropertyMetadata(default(bool))); + + /// + /// 是否启用动画 + /// + public bool IsEnableAnimation + { + get => (bool)GetValue(IsEnableAnimationProperty); + set => SetValue(IsEnableAnimationProperty, value); + } + + /// + /// 是否可以拖动 + /// + public static readonly DependencyProperty IsDraggableProperty = DependencyProperty.Register( + "IsDraggable", typeof(bool), typeof(TabControl), new PropertyMetadata(default(bool))); + + /// + /// 是否可以拖动 + /// + public bool IsDraggable + { + get => (bool)GetValue(IsDraggableProperty); + set => SetValue(IsDraggableProperty, value); + } + + /// + /// 是否显示关闭按钮 + /// + public static readonly DependencyProperty ShowCloseButtonProperty = DependencyProperty.Register( + "ShowCloseButton", typeof(bool), typeof(TabControl), new PropertyMetadata(default(bool))); + + /// + /// 是否显示关闭按钮 + /// + public bool ShowCloseButton + { + get => (bool)GetValue(ShowCloseButtonProperty); + set => SetValue(ShowCloseButtonProperty, value); + } + + /// + /// 是否将标签填充 + /// + public static readonly DependencyProperty IsEnableTabFillProperty = DependencyProperty.Register( + "IsEnableTabFill", typeof(bool), typeof(TabControl), new PropertyMetadata(default(bool))); + + /// + /// 是否将标签填充 + /// + public bool IsEnableTabFill + { + get => (bool)GetValue(IsEnableTabFillProperty); + set => SetValue(IsEnableTabFillProperty, value); + } + + /// + /// 标签宽度 + /// + public static readonly DependencyProperty TabItemWidthProperty = DependencyProperty.Register( + "TabItemWidth", typeof(double), typeof(TabControl), new PropertyMetadata(200.0)); + + /// + /// 标签宽度 + /// + public double TabItemWidth + { + get => (double)GetValue(TabItemWidthProperty); + set => SetValue(TabItemWidthProperty, value); + } + + /// + /// 标签高度 + /// + public static readonly DependencyProperty TabItemHeightProperty = DependencyProperty.Register( + "TabItemHeight", typeof(double), typeof(TabControl), new PropertyMetadata(30.0)); + + /// + /// 标签高度 + /// + public double TabItemHeight + { + get => (double)GetValue(TabItemHeightProperty); + set => SetValue(TabItemHeightProperty, value); + } + + /// + /// 可见的标签数量 + /// + private int _itemShowCount; + + protected override void OnItemsChanged(NotifyCollectionChangedEventArgs e) + { + base.OnItemsChanged(e); + + if (_headerPanel == null) + { + IsInternalAction = false; + return; + } + + if (!IsEnableTabFill) + { + _itemShowCount = (int)(ActualWidth / TabItemWidth); + _buttonOverflow.Show(Items.Count >= _itemShowCount); + } + + if (IsInternalAction) + { + IsInternalAction = false; + return; + } + if (IsEnableAnimation) + { + _headerPanel.ClearValue(TabPanel.FluidMoveDurationProperty); + } + else + { + _headerPanel.FluidMoveDuration = new Duration(TimeSpan.FromSeconds(0)); + } + if (e.Action == NotifyCollectionChangedAction.Add) + { + foreach (UIElement item in e.NewItems) + { + item.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity)); + } + } + IsInternalAction = false; + } + + public override void OnApplyTemplate() + { + base.OnApplyTemplate(); + _headerPanel = Template.FindName(HeaderPanelKey, this) as TabPanel; + + if (IsEnableTabFill) return; + + _buttonOverflow = Template.FindName(OverflowButtonKey, this) as ContextMenuToggleButton; + if (_buttonOverflow != null) + { + _itemShowCount = (int)(ActualWidth / TabItemWidth); + _buttonOverflow.Show(Items.Count >= _itemShowCount); + + var menu = new ContextMenu + { + Placement = PlacementMode.Bottom, + PlacementTarget = _buttonOverflow + }; + menu.Closed += (s, e) => _buttonOverflow.IsChecked = false; + _buttonOverflow.Menu = menu; + _buttonOverflow.Click += (s, e) => + { + if (_buttonOverflow.IsChecked == true) + { + _buttonOverflow.Menu.Items.Clear(); + foreach (TabItem item in Items) + { + var menuItem = new MenuItem + { + Header = item.Header, + Width = TabItemWidth, + IsChecked = item.IsSelected, + IsCheckable = true + }; + menuItem.Click += delegate + { + _buttonOverflow.IsChecked = false; + var index = Items.IndexOf(item); + if (index >= _itemShowCount) + { + Items.Remove(item); + Items.Insert(0, item); + if (IsEnableAnimation) + { + _headerPanel.ClearValue(TabPanel.FluidMoveDurationProperty); + } + else + { + _headerPanel.FluidMoveDuration = new Duration(TimeSpan.FromSeconds(0)); + } + _headerPanel.ForceUpdate = true; + _headerPanel.Measure(new Size(_headerPanel.DesiredSize.Width, ActualHeight)); + _headerPanel.ForceUpdate = false; + } + item.IsSelected = true; + }; + _buttonOverflow.Menu.Items.Add(menuItem); + } + } + }; + } + } + } +} \ No newline at end of file diff --git a/HandyControl/Controls/TabControl/TabItem.cs b/HandyControl/Controls/TabControl/TabItem.cs new file mode 100644 index 00000000..5d5f4610 --- /dev/null +++ b/HandyControl/Controls/TabControl/TabItem.cs @@ -0,0 +1,304 @@ +using System; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Animation; +using HandyControl.Tools; + +// ReSharper disable once CheckNamespace +namespace HandyControl.Controls +{ + [TemplatePart(Name = CloseButtonKey, Type = typeof(Button))] + public class TabItem : System.Windows.Controls.TabItem + { + private const string CloseButtonKey = "PART_CloseButton"; + + private Button _buttonClose; + + /// + /// 动画速度 + /// + private const int AnimationSpeed = 150; + + /// + /// 选项卡是否处于拖动状态 + /// + private static bool ItemIsDragging; + + /// + /// 选项卡是否等待被拖动 + /// + private bool _isWaiting; + + /// + /// 拖动中的选项卡坐标 + /// + private Point _dragPoint; + + /// + /// 鼠标按下时选项卡位置 + /// + private int _mouseDownIndex; + + /// + /// 鼠标按下时选项卡横向偏移 + /// + private double _mouseDownOffsetX; + + /// + /// 鼠标按下时的坐标 + /// + private Point _mouseDownPoint; + + /// + /// 右侧可移动的最大值 + /// + private double _maxMoveRight; + + /// + /// 左侧可移动的最大值 + /// + private double _maxMoveLeft; + + /// + /// 选项卡宽度 + /// + public double ItemWidth { get; internal set; } + + /// + /// 选项卡拖动等待距离(在鼠标移动了超过20个像素无关单位后,选项卡才开始被拖动) + /// + private const double WaitLength = 20; + + /// + /// 选项卡是否处于拖动状态 + /// + private bool _isDragging; + + /// + /// 选项卡是否已经被拖动 + /// + private bool _isDragged; + + /// + /// 目标横向位移 + /// + internal double TargetOffsetX { get; set; } + + /// + /// 当前编号 + /// + private int _currentIndex; + + /// + /// 标签容器 + /// + private TabPanel _tabPanel; + + /// + /// 当前编号 + /// + internal int CurrentIndex + { + get => _currentIndex; + set + { + if (_currentIndex == value || value < 0) return; + var oldIndex = _currentIndex; + _currentIndex = value; + UpdateItemOffsetX(oldIndex); + } + } + + private bool _isLoaded; + + /// + /// 更新选项卡横向偏移 + /// + /// + private void UpdateItemOffsetX(int oldIndex) + { + if (!_isDragging) return; + var moveItem = _tabPanel.ItemDic[CurrentIndex]; + moveItem.CurrentIndex -= CurrentIndex - oldIndex; + var offsetX = moveItem.TargetOffsetX; + var resultX = offsetX + (oldIndex - CurrentIndex) * ItemWidth; + _tabPanel.ItemDic[CurrentIndex] = this; + _tabPanel.ItemDic[moveItem.CurrentIndex] = moveItem; + moveItem.CreateAnimation(offsetX, resultX); + } + + public TabItem() + { + Loaded += (s, e) => + { + if (_isLoaded) return; + _tabPanel = VisualParent as TabPanel; + _isLoaded = true; + }; + //CommandBindings.Add(new CommandBinding(CloseOtherCommand, (s, e) => + //{ + // var enumerator = ((IEnumerable)TabControlParent.Items).GetEnumerator(); + // while (enumerator.MoveNext()) + // { + // var item = enumerator.Current; + // if (!Equals(item) && item != null) + // { + // TabControlParent.Items.Remove(item); + // enumerator = ((IEnumerable)TabControlParent.Items).GetEnumerator(); + // } + // } + //})); + } + + private TabControl TabControlParent => new Lazy(() => ItemsControl.ItemsControlFromItemContainer(this) as TabControl).Value; + + protected override void OnMouseRightButtonDown(MouseButtonEventArgs e) + { + base.OnMouseRightButtonDown(e); + IsSelected = true; + Focus(); + } + + public override void OnApplyTemplate() + { + base.OnApplyTemplate(); + _buttonClose = Template.FindName(CloseButtonKey, this) as Button; + if (_buttonClose != null) + { + _buttonClose.Click += (s, e) => + { + if (TabControlParent.IsEnableAnimation) + { + _tabPanel.ClearValue(TabPanel.FluidMoveDurationProperty); + } + else + { + _tabPanel.FluidMoveDuration = new Duration(TimeSpan.FromSeconds(0)); + } + TabControlParent.IsInternalAction = true; + TabControlParent.Items.Remove(this); + }; + } + } + + protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e) + { + base.OnMouseLeftButtonDown(e); + if (TabControlParent.IsDraggable && !ItemIsDragging && !_isDragging) + { + _tabPanel.FluidMoveDuration = new Duration(TimeSpan.FromSeconds(0)); + _mouseDownOffsetX = RenderTransform.Value.OffsetX; + var mx = TranslatePoint(new Point(), TabControlParent).X; + _mouseDownIndex = CalLocationIndex(mx); + _maxMoveLeft = -_mouseDownIndex * ItemWidth; + _maxMoveRight = TabControlParent.ActualWidth - ActualWidth + _maxMoveLeft; + + _isDragging = true; + ItemIsDragging = true; + _isWaiting = true; + _dragPoint = e.GetPosition(TabControlParent); + _mouseDownPoint = _dragPoint; + CaptureMouse(); + } + } + + protected override void OnMouseMove(MouseEventArgs e) + { + base.OnMouseMove(e); + if (ItemIsDragging && _isDragging) + { + var subX = TranslatePoint(new Point(), TabControlParent).X; + CurrentIndex = CalLocationIndex(subX); + var p = e.GetPosition(TabControlParent); + 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) + { + left = _maxMoveLeft + _mouseDownOffsetX; + } + else if (totalLeft > _maxMoveRight) + { + left = _maxMoveRight + _mouseDownOffsetX; + } + var t = new TranslateTransform(left, 0); + RenderTransform = t; + _dragPoint = p; + } + } + + protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e) + { + base.OnMouseLeftButtonUp(e); + ReleaseMouseCapture(); + if (_isDragged) + { + var subX = TranslatePoint(new Point(), TabControlParent).X; + 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; + } + + /// + /// 创建动画 + /// + internal void CreateAnimation(double offsetX, double resultX, int index = -1) + { + void AnimationCompleted() + { + RenderTransform = new TranslateTransform(resultX, 0); + if (index == -1) return; + var parent = TabControlParent; + _tabPanel.CanUpdate = false; + parent.IsInternalAction = true; + parent.Items.Remove(this); + parent.IsInternalAction = true; + parent.Items.Insert(index, this); + _tabPanel.CanUpdate = true; + _tabPanel.ForceUpdate = true; + _tabPanel.Measure(new Size(_tabPanel.DesiredSize.Width, ActualHeight)); + _tabPanel.ForceUpdate = false; + Focus(); + IsSelected = true; + } + TargetOffsetX = resultX; + if (!TabControlParent.IsEnableAnimation) + { + AnimationCompleted(); + return; + } + var animation = AnimationHelper.CreateAnimation(resultX, AnimationSpeed); + animation.FillBehavior = FillBehavior.Stop; + animation.Completed += (s1, e1) => AnimationCompleted(); + var f = new TranslateTransform(offsetX, 0); + RenderTransform = f; + f.BeginAnimation(TranslateTransform.XProperty, animation); + } + + /// + /// 计算选项卡当前合适的位置编号 + /// + /// + /// + private int CalLocationIndex(double left) + { + var maxIndex = TabControlParent.Items.Count - 1; + var div = (int)(left / ItemWidth); + var rest = left % ItemWidth; + var result = rest / ItemWidth > .5 ? div + 1 : div; + + return result > maxIndex ? maxIndex : result; + } + } +} \ No newline at end of file diff --git a/HandyControl/Controls/TabControl/TabPanel.cs b/HandyControl/Controls/TabControl/TabPanel.cs new file mode 100644 index 00000000..7c7de2a7 --- /dev/null +++ b/HandyControl/Controls/TabControl/TabPanel.cs @@ -0,0 +1,169 @@ +using System; +using System.Collections.Generic; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Media; +using HandyControl.Tools; + +// ReSharper disable once CheckNamespace +namespace HandyControl.Controls +{ + public class TabPanel : Panel + { + private int _itemCount; + + /// + /// 是否可以更新 + /// + internal bool CanUpdate = true; + + /// + /// 选项卡字典 + /// + internal Dictionary ItemDic = new Dictionary(); + + /// + /// 流式行为持续时间 + /// + public static readonly DependencyProperty FluidMoveDurationProperty = DependencyProperty.Register( + "FluidMoveDuration", typeof(Duration), typeof(TabPanel), new PropertyMetadata(new Duration(TimeSpan.FromMilliseconds(200)))); + + /// + /// 流式行为持续时间 + /// + public Duration FluidMoveDuration + { + get => (Duration)GetValue(FluidMoveDurationProperty); + set => SetValue(FluidMoveDurationProperty, value); + } + + /// + /// 是否将标签填充 + /// + public static readonly DependencyProperty IsEnableTabFillProperty = DependencyProperty.Register( + "IsEnableTabFill", typeof(bool), typeof(TabPanel), new PropertyMetadata(default(bool))); + + /// + /// 是否将标签填充 + /// + public bool IsEnableTabFill + { + get => (bool)GetValue(IsEnableTabFillProperty); + set => SetValue(IsEnableTabFillProperty, value); + } + + /// + /// 标签宽度 + /// + public static readonly DependencyProperty TabItemWidthProperty = DependencyProperty.Register( + "TabItemWidth", typeof(double), typeof(TabPanel), new PropertyMetadata(200.0)); + + /// + /// 标签宽度 + /// + public double TabItemWidth + { + get => (double)GetValue(TabItemWidthProperty); + set => SetValue(TabItemWidthProperty, value); + } + + /// + /// 标签高度 + /// + public static readonly DependencyProperty TabItemHeightProperty = DependencyProperty.Register( + "TabItemHeight", typeof(double), typeof(TabPanel), new PropertyMetadata(30.0)); + + /// + /// 标签高度 + /// + public double TabItemHeight + { + get => (double)GetValue(TabItemHeightProperty); + set => SetValue(TabItemHeightProperty, value); + } + + /// + /// 是否可以强制更新 + /// + internal bool ForceUpdate; + + private Size _oldSize; + + /// + /// 是否已经加载 + /// + private bool _isLoaded; + + protected override Size MeasureOverride(Size constraint) + { + if ((_itemCount == InternalChildren.Count || !CanUpdate) && !ForceUpdate) return _oldSize; + constraint.Height = TabItemHeight; + _itemCount = InternalChildren.Count; + + var size = new Size(); + + ItemDic.Clear(); + + var count = InternalChildren.Count; + if (count == 0) + { + _oldSize.Width = 0; + return _oldSize; + } + constraint.Width += InternalChildren.Count; + + var itemWidth = .0; + var arr = new int[count]; + + if (!IsEnableTabFill) + { + itemWidth = TabItemWidth; + } + else + { + arr = ArithmeticHelper.DivideInt2Arr((int)constraint.Width, count); + } + + for (var index = 0; index < count; index++) + { + if (IsEnableTabFill) + { + itemWidth = arr[index]; + } + if (InternalChildren[index] is TabItem tabItem) + { + tabItem.RenderTransform = new TranslateTransform(); + tabItem.MaxWidth = itemWidth; + var rect = new Rect + { + X = size.Width - tabItem.BorderThickness.Left, + Width = itemWidth, + Height = TabItemHeight + }; + Console.WriteLine(rect); + tabItem.Arrange(rect); + tabItem.ItemWidth = itemWidth - tabItem.BorderThickness.Left; + tabItem.CurrentIndex = index; + tabItem.TargetOffsetX = 0; + ItemDic[index] = tabItem; + size.Width += tabItem.ItemWidth; + } + } + size.Height = constraint.Height; + _oldSize = size; + return _oldSize; + } + + public TabPanel() + { + Loaded += (s, e) => + { + if (_isLoaded) return; + ForceUpdate = true; + Measure(new Size(DesiredSize.Width, ActualHeight)); + ForceUpdate = false; + _isLoaded = true; + }; + } + } +} \ No newline at end of file diff --git a/HandyControl/Controls/TimeBar/TimeBar.xaml b/HandyControl/Controls/TimeBar/TimeBar.xaml index 051cbb01..031983ad 100644 --- a/HandyControl/Controls/TimeBar/TimeBar.xaml +++ b/HandyControl/Controls/TimeBar/TimeBar.xaml @@ -40,7 +40,7 @@ - + diff --git a/HandyControl/Controls/TimeBar/TimeBar.xaml.cs b/HandyControl/Controls/TimeBar/TimeBar.xaml.cs index af1523de..e2e85379 100644 --- a/HandyControl/Controls/TimeBar/TimeBar.xaml.cs +++ b/HandyControl/Controls/TimeBar/TimeBar.xaml.cs @@ -23,7 +23,7 @@ namespace HandyControl.Controls /// 刻度字符串 /// private static readonly DependencyProperty SpeStrProperty = DependencyProperty.Register( - "SpeStr", typeof(string), typeof(TimeBar), new PropertyMetadata("间隔1小时")); + "SpeStr", typeof(string), typeof(TimeBar), new PropertyMetadata(Properties.Langs.Lang.Interval1h)); /// /// 选中时间 @@ -150,13 +150,13 @@ namespace HandyControl.Controls if (value < 0) { - SpeStr = "间隔2小时"; + SpeStr = Properties.Langs.Lang.Interval2h; _speIndex = 0; return; } if (value > 6) { - SpeStr = "间隔30秒"; + SpeStr = Properties.Langs.Lang.Interval30s; _speIndex = 6; return; } @@ -164,26 +164,26 @@ namespace HandyControl.Controls switch (value) { case 0: - SpeStr = "间隔2小时"; + SpeStr = Properties.Langs.Lang.Interval2h; break; case 1: - SpeStr = "间隔1小时"; + SpeStr = Properties.Langs.Lang.Interval1h; break; case 2: - SpeStr = "间隔30分钟"; + SpeStr = Properties.Langs.Lang.Interval30m; break; case 3: - SpeStr = "间隔10分钟"; + SpeStr = Properties.Langs.Lang.Interval10m; break; case 4: - SpeStr = "间隔5分钟"; + SpeStr = Properties.Langs.Lang.Interval5m; break; case 5: - SpeStr = "间隔1分钟"; + SpeStr = Properties.Langs.Lang.Interval1m; break; case 6: SetSpeTimeFormat("HH:mm:ss"); - SpeStr = "间隔30秒"; + SpeStr = Properties.Langs.Lang.Interval30s; break; } _speIndex = value; diff --git a/HandyControl/Controls/Window/ImageBrowser.xaml b/HandyControl/Controls/Window/ImageBrowser.xaml index 702febe9..3897295e 100644 --- a/HandyControl/Controls/Window/ImageBrowser.xaml +++ b/HandyControl/Controls/Window/ImageBrowser.xaml @@ -75,7 +75,7 @@ - + \ No newline at end of file diff --git a/HandyControl/Controls/Window/ImageBrowser.xaml.cs b/HandyControl/Controls/Window/ImageBrowser.xaml.cs index 53660ea2..54b3ece3 100644 --- a/HandyControl/Controls/Window/ImageBrowser.xaml.cs +++ b/HandyControl/Controls/Window/ImageBrowser.xaml.cs @@ -56,7 +56,7 @@ namespace HandyControl.Controls /// private static readonly SaveFileDialog SaveFileDialog = new SaveFileDialog { - Filter = "PNG图片|*.png" + Filter = $"{Properties.Langs.Lang.PngImg}|*.png" }; public static readonly DependencyProperty ImgPathProperty = DependencyProperty.Register( @@ -211,7 +211,7 @@ namespace HandyControl.Controls } catch { - PopupWindow.ShowDialog("非法的图片路径!"); + PopupWindow.ShowDialog(Properties.Langs.Lang.ErrorImgPath); } } @@ -343,7 +343,7 @@ namespace HandyControl.Controls if (Math.Abs(height - 0) < 0.001 || Math.Abs(width - 0) < 0.001) { - PopupWindow.ShowDialog("非法的图片尺寸!"); + PopupWindow.ShowDialog(Properties.Langs.Lang.ErrorImgSize); return; } _imgWidHeiScale = width / height; @@ -395,7 +395,7 @@ namespace HandyControl.Controls private void ButtonSave_OnClick(object sender, RoutedEventArgs e) { - SaveFileDialog.FileName = $"{DateTime.Now:yyyy年M月d日h时m分s.fff秒}"; + SaveFileDialog.FileName = $"{DateTime.Now:yyyy-M-d-h-m-s.fff}"; if (SaveFileDialog.ShowDialog() == true) { var path = SaveFileDialog.FileName; diff --git a/HandyControl/HandyControl.csproj b/HandyControl/HandyControl.csproj index 2f09af67..03422c79 100644 --- a/HandyControl/HandyControl.csproj +++ b/HandyControl/HandyControl.csproj @@ -38,6 +38,8 @@ + + Carousel.xaml @@ -63,6 +65,9 @@ Pagination.xaml + + + TimeBar.xaml @@ -96,12 +101,14 @@ + + @@ -110,19 +117,28 @@ Code + + True + True + Lang.resx + + + True + True + Lang.en.resx + - - + + - - + @@ -268,6 +284,10 @@ Designer MSBuild:Compile + + Designer + MSBuild:Compile + Designer MSBuild:Compile @@ -304,6 +324,10 @@ Designer MSBuild:Compile + + Designer + MSBuild:Compile + Designer MSBuild:Compile @@ -332,6 +356,16 @@ - + + + PublicResXFileCodeGenerator + Lang.en.Designer.cs + + + PublicResXFileCodeGenerator + Lang.Designer.cs + Designer + + \ No newline at end of file diff --git a/HandyControl/Interactivity/InvokeCommandAction.cs b/HandyControl/Interactivity/InvokeCommandAction.cs new file mode 100644 index 00000000..d188d9d4 --- /dev/null +++ b/HandyControl/Interactivity/InvokeCommandAction.cs @@ -0,0 +1,72 @@ +using System; +using System.Reflection; +using System.Windows; +using System.Windows.Input; + +namespace HandyControl.Interactivity +{ + public sealed class InvokeCommandAction : TriggerAction + { + public static readonly DependencyProperty CommandProperty = + DependencyProperty.Register(nameof(Command), typeof(ICommand), typeof(InvokeCommandAction), null); + + public static readonly DependencyProperty CommandParameterProperty = + DependencyProperty.Register(nameof(CommandParameter), typeof(object), typeof(InvokeCommandAction), + null); + + private string _commandName; + + public string CommandName + { + get + { + ReadPreamble(); + return _commandName; + } + set + { + if (CommandName == value) + return; + WritePreamble(); + _commandName = value; + WritePostscript(); + } + } + + public ICommand Command + { + get => (ICommand)GetValue(CommandProperty); + set => SetValue(CommandProperty, value); + } + + public object CommandParameter + { + get => GetValue(CommandParameterProperty); + set => SetValue(CommandParameterProperty, value); + } + + protected override void Invoke(object parameter) + { + if (AssociatedObject == null) + return; + var command = ResolveCommand(); + if (command == null || !command.CanExecute(CommandParameter)) + return; + command.Execute(CommandParameter); + } + + private ICommand ResolveCommand() + { + var command = (ICommand)null; + if (Command != null) + command = Command; + else if (AssociatedObject != null) + foreach (var property in AssociatedObject.GetType() + .GetProperties(BindingFlags.Instance | BindingFlags.Public)) + if (typeof(ICommand).IsAssignableFrom(property.PropertyType) && + string.Equals(property.Name, CommandName, StringComparison.Ordinal)) + command = (ICommand)property.GetValue(AssociatedObject, null); + return command; + } + } +} \ No newline at end of file diff --git a/HandyControl/Interactivity/TriggerAction!1.cs b/HandyControl/Interactivity/TriggerAction!1.cs new file mode 100644 index 00000000..57d0df4c --- /dev/null +++ b/HandyControl/Interactivity/TriggerAction!1.cs @@ -0,0 +1,19 @@ +using System; +using System.Windows; + +namespace HandyControl.Interactivity +{ + public abstract class TriggerAction : TriggerAction where T : DependencyObject + { + protected TriggerAction() : base(typeof(T)) + { + } + +#pragma warning disable 108,114 + protected T AssociatedObject => (T)base.AssociatedObject; +#pragma warning restore 108,114 + + protected sealed override Type AssociatedObjectTypeConstraint => + base.AssociatedObjectTypeConstraint; + } +} \ No newline at end of file diff --git a/HandyControl/Interactivity/TriggerBase.cs b/HandyControl/Interactivity/TriggerBase.cs index be6cebc7..d1eaeeff 100644 --- a/HandyControl/Interactivity/TriggerBase.cs +++ b/HandyControl/Interactivity/TriggerBase.cs @@ -9,12 +9,12 @@ namespace HandyControl.Interactivity [ContentProperty("Actions")] public abstract class TriggerBase : Animatable, IAttachedObject { - public static readonly DependencyProperty ActionsProperty = ActionsPropertyKey.DependencyProperty; - private static readonly DependencyPropertyKey ActionsPropertyKey = DependencyProperty.RegisterReadOnly("Actions", typeof(TriggerActionCollection), typeof(TriggerBase), new FrameworkPropertyMetadata()); + public static readonly DependencyProperty ActionsProperty = ActionsPropertyKey.DependencyProperty; + private DependencyObject _associatedObject; private readonly Type _associatedObjectTypeConstraint; diff --git a/HandyControl/Properties/AssemblyInfo.cs b/HandyControl/Properties/AssemblyInfo.cs index 86af382f..f7371f0f 100644 --- a/HandyControl/Properties/AssemblyInfo.cs +++ b/HandyControl/Properties/AssemblyInfo.cs @@ -10,5 +10,5 @@ using System.Runtime.InteropServices; [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] [assembly: ComVisible(false)] -[assembly: AssemblyVersion("1.2.0.0")] -[assembly: AssemblyFileVersion("1.2.0.0")] +[assembly: AssemblyVersion("1.2.1.0")] +[assembly: AssemblyFileVersion("1.2.1.0")] diff --git a/HandyControl/Properties/Langs/Lang.Designer.cs b/HandyControl/Properties/Langs/Lang.Designer.cs new file mode 100644 index 00000000..7cd624cd --- /dev/null +++ b/HandyControl/Properties/Langs/Lang.Designer.cs @@ -0,0 +1,207 @@ +//------------------------------------------------------------------------------ +// +// 此代码由工具生成。 +// 运行时版本:4.0.30319.42000 +// +// 对此文件的更改可能会导致不正确的行为,并且如果 +// 重新生成代码,这些更改将会丢失。 +// +//------------------------------------------------------------------------------ + +namespace HandyControl.Properties.Langs { + using System; + + + /// + /// 一个强类型的资源类,用于查找本地化的字符串等。 + /// + // 此类是由 StronglyTypedResourceBuilder + // 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。 + // 若要添加或移除成员,请编辑 .ResX 文件,然后重新运行 ResGen + // (以 /str 作为命令选项),或重新生成 VS 项目。 + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + public class Lang { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Lang() { + } + + /// + /// 返回此类使用的缓存的 ResourceManager 实例。 + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + public static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("HandyControl.Properties.Langs.Lang", typeof(Lang).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// 使用此强类型资源类,为所有资源查找 + /// 重写当前线程的 CurrentUICulture 属性。 + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + public static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// 查找类似 取消 的本地化字符串。 + /// + public static string Cancel { + get { + return ResourceManager.GetString("Cancel", resourceCulture); + } + } + + /// + /// 查找类似 清空 的本地化字符串。 + /// + public static string Clear { + get { + return ResourceManager.GetString("Clear", resourceCulture); + } + } + + /// + /// 查找类似 确定 的本地化字符串。 + /// + public static string Confirm { + get { + return ResourceManager.GetString("Confirm", resourceCulture); + } + } + + /// + /// 查找类似 错误的图片路径! 的本地化字符串。 + /// + public static string ErrorImgPath { + get { + return ResourceManager.GetString("ErrorImgPath", resourceCulture); + } + } + + /// + /// 查找类似 非法的图片尺寸! 的本地化字符串。 + /// + public static string ErrorImgSize { + get { + return ResourceManager.GetString("ErrorImgSize", resourceCulture); + } + } + + /// + /// 查找类似 间隔10分钟 的本地化字符串。 + /// + public static string Interval10m { + get { + return ResourceManager.GetString("Interval10m", resourceCulture); + } + } + + /// + /// 查找类似 间隔1小时 的本地化字符串。 + /// + public static string Interval1h { + get { + return ResourceManager.GetString("Interval1h", resourceCulture); + } + } + + /// + /// 查找类似 间隔1分钟 的本地化字符串。 + /// + public static string Interval1m { + get { + return ResourceManager.GetString("Interval1m", resourceCulture); + } + } + + /// + /// 查找类似 间隔2小时 的本地化字符串。 + /// + public static string Interval2h { + get { + return ResourceManager.GetString("Interval2h", resourceCulture); + } + } + + /// + /// 查找类似 间隔30分钟 的本地化字符串。 + /// + public static string Interval30m { + get { + return ResourceManager.GetString("Interval30m", resourceCulture); + } + } + + /// + /// 查找类似 间隔30秒 的本地化字符串。 + /// + public static string Interval30s { + get { + return ResourceManager.GetString("Interval30s", resourceCulture); + } + } + + /// + /// 查找类似 间隔5分钟 的本地化字符串。 + /// + public static string Interval5m { + get { + return ResourceManager.GetString("Interval5m", resourceCulture); + } + } + + /// + /// 查找类似 PNG图片 的本地化字符串。 + /// + public static string PngImg { + get { + return ResourceManager.GetString("PngImg", resourceCulture); + } + } + + /// + /// 查找类似 过大 的本地化字符串。 + /// + public static string TooLarge { + get { + return ResourceManager.GetString("TooLarge", resourceCulture); + } + } + + /// + /// 查找类似 未知 的本地化字符串。 + /// + public static string Unknown { + get { + return ResourceManager.GetString("Unknown", resourceCulture); + } + } + + /// + /// 查找类似 未知大小 的本地化字符串。 + /// + public static string UnknownSize { + get { + return ResourceManager.GetString("UnknownSize", resourceCulture); + } + } + } +} diff --git a/HandyControl/Properties/Langs/Lang.en.Designer.cs b/HandyControl/Properties/Langs/Lang.en.Designer.cs new file mode 100644 index 00000000..e69de29b diff --git a/HandyControl/Properties/Langs/Lang.en.resx b/HandyControl/Properties/Langs/Lang.en.resx new file mode 100644 index 00000000..bb8c6c34 --- /dev/null +++ b/HandyControl/Properties/Langs/Lang.en.resx @@ -0,0 +1,168 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Confirm + + + Cancel + + + PNG image + + + Wrong picture path + + + Wrong picture size + + + Unknown size + + + Too large + + + Unknown + + + 30 seconds interval + + + 1 minute interval + + + 5 minutes interval + + + 10 minutes interval + + + 30 minutes interval + + + 1 hour interval + + + 2 hour interval + + + Clear + + \ No newline at end of file diff --git a/HandyControl/Properties/Langs/Lang.resx b/HandyControl/Properties/Langs/Lang.resx new file mode 100644 index 00000000..c3ea80ca --- /dev/null +++ b/HandyControl/Properties/Langs/Lang.resx @@ -0,0 +1,148 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 1.3 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.3500.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.3500.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 确定 + + + 取消 + + + PNG图片 + + + 错误的图片路径! + + + 非法的图片尺寸! + + + 未知大小 + + + 过大 + + + 未知 + + + 间隔30秒 + + + 间隔1分钟 + + + 间隔5分钟 + + + 间隔10分钟 + + + 间隔30分钟 + + + 间隔1小时 + + + 间隔2小时 + + + 清空 + + \ No newline at end of file diff --git a/HandyControl/Themes/Basic/Brushes.xaml b/HandyControl/Themes/Basic/Brushes.xaml index 03675870..d7af76b6 100644 --- a/HandyControl/Themes/Basic/Brushes.xaml +++ b/HandyControl/Themes/Basic/Brushes.xaml @@ -1,9 +1,11 @@  - + + + + - @@ -17,16 +19,28 @@ - + + + + - + + + + - + + + + - + + + + diff --git a/HandyControl/Themes/Basic/Colors.xaml b/HandyControl/Themes/Basic/Colors.xaml index 2b9727f7..ca9c56e5 100644 --- a/HandyControl/Themes/Basic/Colors.xaml +++ b/HandyControl/Themes/Basic/Colors.xaml @@ -1,21 +1,20 @@  - #2196F3 - #1976D2 - #81d4fa + #73a5ff + #5477f5 - #d9534f - #d43f3a + #ff8792 + #ff4c9f - #f0ad4e - #eea236 + #ffd07a + #ff9133 - #5bc0de - #46b8da + #4dd0e1 + #00bcd4 - #5cb85c - #4cae4c + #A5D6A7 + #4CAF50 #212121 #757575 diff --git a/HandyControl/Themes/Basic/Converters.xaml b/HandyControl/Themes/Basic/Converters.xaml index 59d88ec2..4cf30a0a 100644 --- a/HandyControl/Themes/Basic/Converters.xaml +++ b/HandyControl/Themes/Basic/Converters.xaml @@ -2,14 +2,13 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:converter="clr-namespace:HandyControl.Tools.Converter"> - - + + - - + diff --git a/HandyControl/Themes/Basic/Effects.xaml b/HandyControl/Themes/Basic/Effects.xaml index 874da734..bd866ffe 100644 --- a/HandyControl/Themes/Basic/Effects.xaml +++ b/HandyControl/Themes/Basic/Effects.xaml @@ -4,10 +4,10 @@ #AA000000 - - - - - + + + + + \ No newline at end of file diff --git a/HandyControl/Themes/Styles/Base/ButtonBaseBaseStyle.xaml b/HandyControl/Themes/Styles/Base/ButtonBaseBaseStyle.xaml index dfe6c714..d0fc1a9b 100644 --- a/HandyControl/Themes/Styles/Base/ButtonBaseBaseStyle.xaml +++ b/HandyControl/Themes/Styles/Base/ButtonBaseBaseStyle.xaml @@ -10,11 +10,12 @@ - + + \ No newline at end of file diff --git a/HandyControl/Themes/Styles/Base/ProgressBarBaseStyle.xaml b/HandyControl/Themes/Styles/Base/ProgressBarBaseStyle.xaml index 3d0de4c2..0c9c3b66 100644 --- a/HandyControl/Themes/Styles/Base/ProgressBarBaseStyle.xaml +++ b/HandyControl/Themes/Styles/Base/ProgressBarBaseStyle.xaml @@ -30,7 +30,7 @@ - + diff --git a/HandyControl/Themes/Styles/Button.xaml b/HandyControl/Themes/Styles/Button.xaml index 08337930..86b39ae0 100644 --- a/HandyControl/Themes/Styles/Button.xaml +++ b/HandyControl/Themes/Styles/Button.xaml @@ -10,6 +10,7 @@ + + \ No newline at end of file diff --git a/HandyControl/Themes/Styles/ProgressBar.xaml b/HandyControl/Themes/Styles/ProgressBar.xaml index afd6ba29..ed718a2f 100644 --- a/HandyControl/Themes/Styles/ProgressBar.xaml +++ b/HandyControl/Themes/Styles/ProgressBar.xaml @@ -39,8 +39,8 @@ - - + + @@ -101,8 +101,8 @@ - - + + @@ -131,8 +131,8 @@ - - + + @@ -161,8 +161,8 @@ - - + + @@ -191,8 +191,8 @@ - - + + diff --git a/HandyControl/Themes/Styles/Style.xaml b/HandyControl/Themes/Styles/Style.xaml index 26871661..3e721de9 100644 --- a/HandyControl/Themes/Styles/Style.xaml +++ b/HandyControl/Themes/Styles/Style.xaml @@ -18,7 +18,7 @@ - + @@ -28,7 +28,7 @@ - + \ No newline at end of file diff --git a/HandyControl/Themes/Styles/TabControl.xaml b/HandyControl/Themes/Styles/TabControl.xaml new file mode 100644 index 00000000..925d6ae4 --- /dev/null +++ b/HandyControl/Themes/Styles/TabControl.xaml @@ -0,0 +1,107 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/HandyControl/Themes/Styles/Window.xaml b/HandyControl/Themes/Styles/Window.xaml index 0e1f63c3..b81b7513 100644 --- a/HandyControl/Themes/Styles/Window.xaml +++ b/HandyControl/Themes/Styles/Window.xaml @@ -37,7 +37,7 @@ - + diff --git a/HandyControl/Tools/ArithmeticHelper.cs b/HandyControl/Tools/ArithmeticHelper.cs index e6b09453..8d2c4780 100644 --- a/HandyControl/Tools/ArithmeticHelper.cs +++ b/HandyControl/Tools/ArithmeticHelper.cs @@ -5,15 +5,40 @@ using System.Windows.Controls.Primitives; namespace HandyControl.Tools { - public class ArithmeticHelper + /// + /// 包含内部使用的一些简单算法 + /// + internal class ArithmeticHelper { + /// + /// 平分一个整数到一个数组中 + /// + /// + /// + /// + public static int[] DivideInt2Arr(int num, int count) + { + var arr = new int[count]; + var div = num / count; + var rest = num % count; + for (int i = 0; i < count; i++) + { + arr[i] = div; + } + for (int i = 0; i < rest; i++) + { + arr[i] += 1; + } + return arr; + } + /// /// 计算控件在窗口中的可见坐标 /// /// /// /// - internal static Point CalSafePoint(FrameworkElement element, FrameworkElement showElement) + public static Point CalSafePoint(FrameworkElement element, FrameworkElement showElement) { if (element == null || showElement == null) return default(Point); var point = element.PointToScreen(new Point(0, 0)); @@ -33,7 +58,7 @@ namespace HandyControl.Tools /// /// /// - internal static Rect GetLayoutRect(FrameworkElement element) + public static Rect GetLayoutRect(FrameworkElement element) { var num1 = element.ActualWidth; var num2 = element.ActualHeight; diff --git a/HandyControl/Tools/Converter/Boolean2BooleanFeConverter.cs b/HandyControl/Tools/Converter/Boolean2BooleanReConverter.cs similarity index 89% rename from HandyControl/Tools/Converter/Boolean2BooleanFeConverter.cs rename to HandyControl/Tools/Converter/Boolean2BooleanReConverter.cs index d97a711b..399bccbe 100644 --- a/HandyControl/Tools/Converter/Boolean2BooleanFeConverter.cs +++ b/HandyControl/Tools/Converter/Boolean2BooleanReConverter.cs @@ -4,7 +4,7 @@ using System.Windows.Data; namespace HandyControl.Tools.Converter { - public class Boolean2BooleanFeConverter : IValueConverter + public class Boolean2BooleanReConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { diff --git a/HandyControl/Tools/Converter/Boolean2VisibilityFeConverter.cs b/HandyControl/Tools/Converter/Boolean2VisibilityReConverter.cs similarity index 89% rename from HandyControl/Tools/Converter/Boolean2VisibilityFeConverter.cs rename to HandyControl/Tools/Converter/Boolean2VisibilityReConverter.cs index decb6007..83eaad30 100644 --- a/HandyControl/Tools/Converter/Boolean2VisibilityFeConverter.cs +++ b/HandyControl/Tools/Converter/Boolean2VisibilityReConverter.cs @@ -5,7 +5,7 @@ using System.Windows.Data; namespace HandyControl.Tools.Converter { - public class Boolean2VisibilityFeConverter : IValueConverter + public class Boolean2VisibilityReConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { diff --git a/HandyControl/Tools/Converter/IsNullConverter.cs b/HandyControl/Tools/Converter/IsNullConverter.cs deleted file mode 100644 index cc24a835..00000000 --- a/HandyControl/Tools/Converter/IsNullConverter.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System; -using System.Globalization; -using System.Windows.Data; - -namespace HandyControl.Tools.Converter -{ - public class IsNullConverter : IValueConverter - { - - public object Convert(object value, Type targetType, object parameter, CultureInfo culture) - { - return value == null; - } - - public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) - { - throw new InvalidOperationException("IsNullConverter can only be used OneWay."); - } - } -} diff --git a/HandyControl/Tools/Converter/Long2FileSizeConverter.cs b/HandyControl/Tools/Converter/Long2FileSizeConverter.cs index 200969df..895b0b4f 100644 --- a/HandyControl/Tools/Converter/Long2FileSizeConverter.cs +++ b/HandyControl/Tools/Converter/Long2FileSizeConverter.cs @@ -8,12 +8,12 @@ namespace HandyControl.Tools.Converter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { - if (value == null) return "未知大小"; + if (value == null) return Properties.Langs.Lang.UnknownSize; if (value is long intValue) { if (intValue < 0) { - return "未知大小"; + return Properties.Langs.Lang.UnknownSize; } if (intValue < 1024) { @@ -39,9 +39,9 @@ namespace HandyControl.Tools.Converter { return $"{intValue / 1125899906842624.0:0.00} PB"; } - return "过大"; + return Properties.Langs.Lang.TooLarge; } - return "未知"; + return Properties.Langs.Lang.Unknown; } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) diff --git a/HandyControl/Tools/Converter/String2VisibilityFeConverter.cs b/HandyControl/Tools/Converter/String2VisibilityReConverter.cs similarity index 89% rename from HandyControl/Tools/Converter/String2VisibilityFeConverter.cs rename to HandyControl/Tools/Converter/String2VisibilityReConverter.cs index ec1fbfad..56e7be13 100644 --- a/HandyControl/Tools/Converter/String2VisibilityFeConverter.cs +++ b/HandyControl/Tools/Converter/String2VisibilityReConverter.cs @@ -5,7 +5,7 @@ using System.Windows.Data; namespace HandyControl.Tools.Converter { - public class String2VisibilityFeConverter : IValueConverter + public class String2VisibilityReConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { diff --git a/HandyControl/Tools/RegularJudgment.cs b/HandyControl/Tools/RegularJudgment.cs index d7e19a16..59ddbe38 100644 --- a/HandyControl/Tools/RegularJudgment.cs +++ b/HandyControl/Tools/RegularJudgment.cs @@ -1,17 +1,18 @@ -using System.Text.RegularExpressions; +using System; +using System.Text.RegularExpressions; using HandyControl.Data.Enum; namespace HandyControl.Tools { /// - /// 包含一些正则验证操作 + /// 包含一些正则验证操作 /// public static class RegularJudgment { private static readonly RegularPatterns RegularPatterns = new RegularPatterns(); /// - /// 判断字符串格式是否符合某种要求 + /// 判断字符串格式是否符合某种要求 /// /// 需要判断的字符串 /// 正则表达式 @@ -22,7 +23,7 @@ namespace HandyControl.Tools } /// - /// 判断字符串是否满足指定的格式 + /// 判断字符串是否满足指定的格式 /// /// 需要判断的字符串 /// 指定格式的文本 @@ -31,11 +32,11 @@ namespace HandyControl.Tools { if (textType == TextType.Common) return true; return Regex.IsMatch(text, - RegularPatterns.GetValue(System.Enum.GetName(typeof(TextType), textType) + "Pattern").ToString()); + RegularPatterns.GetValue(Enum.GetName(typeof(TextType), textType) + "Pattern").ToString()); } /// - /// 判断字符串格式是否为电子邮件 + /// 判断字符串格式是否为电子邮件 /// /// 需要判断的Email字符串 /// 方法返回布尔值 @@ -45,7 +46,7 @@ namespace HandyControl.Tools } /// - /// 判断字符串格式是否为指定类型的IP地址 + /// 判断字符串格式是否为指定类型的IP地址 /// /// 需要判断的IP字符串 /// 指定的IP类型 @@ -64,7 +65,7 @@ namespace HandyControl.Tools } /// - /// 判断字符串格式是否为IP地址 + /// 判断字符串格式是否为IP地址 /// /// 需要判断的IP字符串 /// 方法返回布尔值 @@ -74,7 +75,7 @@ namespace HandyControl.Tools } /// - /// 判断字符串格式是否为单个汉字 + /// 判断字符串格式是否为单个汉字 /// /// 需要判断的单个汉字字符串 /// 方法返回布尔值 @@ -84,7 +85,7 @@ namespace HandyControl.Tools } /// - /// 判断字符串格式是否为url + /// 判断字符串格式是否为url /// /// 需要判断的url字符串 /// 方法返回布尔值 diff --git a/HandyControl/Tools/RegularPatterns.cs b/HandyControl/Tools/RegularPatterns.cs index 28216073..4ff94eb6 100644 --- a/HandyControl/Tools/RegularPatterns.cs +++ b/HandyControl/Tools/RegularPatterns.cs @@ -1,24 +1,15 @@ namespace HandyControl.Tools { /// - /// 包含一些正则验证所需要的字符串 + /// 包含一些正则验证所需要的字符串 /// public sealed class RegularPatterns { - /// - /// - /// - /// - /// - public object GetValue(string propertyName) - { - return GetType().GetField(propertyName).GetValue(null); - } - /// /// 邮件正则匹配表达式 /// - public const string MailPattern = @"^([\w-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([\w-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$"; + public const string MailPattern = + @"^([\w-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([\w-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$"; /// /// 手机号正则匹配表达式 @@ -26,127 +17,135 @@ public const string PhonePattern = @"^((13[0-9])|(15[^4,\d])|(18[0,5-9]))\d{8}$"; /// - /// IP正则匹配 + /// IP正则匹配 /// public const string IpPattern = - @"^(25[0-5]|2[0-4]\d|1\d{2}|[1-9]?\d)\." + @"^(25[0-5]|2[0-4]\d|1\d{2}|[1-9]?\d)\." + @"(25[0-5]|2[0-4]\d|1\d{2}|[1-9]?\d)\." + @"(25[0-5]|2[0-4]\d|1\d{2}|[1-9]?\d)\." + @"(25[0-5]|2[0-4]\d|1\d{2}|[1-9]?\d)$"; /// - /// A类IP正则匹配 + /// A类IP正则匹配 /// public const string IpAPattern = - @"^(12[0-6]|1[0-1]\d|[1-9]?\d)\." + @"^(12[0-6]|1[0-1]\d|[1-9]?\d)\." + @"(25[0-5]|2[0-4]\d|1\d{2}|[1-9]?\d)\." + @"(25[0-5]|2[0-4]\d|1\d{2}|[1-9]?\d)\." + @"(25[0-5]|2[0-4]\d|1\d{2}|[1-9]?\d)$"; /// - /// B类IP正则匹配 + /// B类IP正则匹配 /// public const string IpBPattern = - @"^(19[0-1]|12[8-9]|1[3-8]\d)\." + @"^(19[0-1]|12[8-9]|1[3-8]\d)\." + @"(25[0-5]|2[0-4]\d|1\d{2}|[1-9]?\d)\." + @"(25[0-5]|2[0-4]\d|1\d{2}|[1-9]?\d)\." + @"(25[0-5]|2[0-4]\d|1\d{2}|[1-9]?\d)$"; /// - /// C类IP正则匹配 + /// C类IP正则匹配 /// public const string IpCPattern = - @"^(19[2-9]|22[0-3]|2[0-1]\d)\." + @"^(19[2-9]|22[0-3]|2[0-1]\d)\." + @"(25[0-5]|2[0-4]\d|1\d{2}|[1-9]?\d)\." + @"(25[0-5]|2[0-4]\d|1\d{2}|[1-9]?\d)\." + @"(25[0-5]|2[0-4]\d|1\d{2}|[1-9]?\d)$"; /// - /// D类IP正则匹配 + /// D类IP正则匹配 /// public const string IpDPattern = - @"^(22[4-9]|23\d\." + @"^(22[4-9]|23\d\." + @"(25[0-5]|2[0-4]\d|1\d{2}|[1-9]?\d)\." + @"(25[0-5]|2[0-4]\d|1\d{2}|[1-9]?\d)\." + @"(25[0-5]|2[0-4]\d|1\d{2}|[1-9]?\d)$"; /// - /// E类IP正则匹配 + /// E类IP正则匹配 /// public const string IpEPattern = - @"^(25[0-5]|24\d\." + @"^(25[0-5]|24\d\." + @"(25[0-5]|2[0-4]\d|1\d{2}|[1-9]?\d)\." + @"(25[0-5]|2[0-4]\d|1\d{2}|[1-9]?\d)\." + @"(25[0-5]|2[0-4]\d|1\d{2}|[1-9]?\d)$"; /// - /// 汉字正则匹配 + /// 汉字正则匹配 /// public const string ChinesePattern = @"^[\u4e00-\u9fa5]$"; /// - /// Url正则匹配 + /// Url正则匹配 /// - public const string UrlPattern = @"((http|ftp|https)://)(([a-zA-Z0-9\._-]+\.[a-zA-Z]{2,6})|([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}))(:[0-9]{1,4})*(/[a-zA-Z0-9\&%_\./-~-]*)?"; + public const string UrlPattern = + @"((http|ftp|https)://)(([a-zA-Z0-9\._-]+\.[a-zA-Z]{2,6})|([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}))(:[0-9]{1,4})*(/[a-zA-Z0-9\&%_\./-~-]*)?"; /// - /// 数字正则匹配 + /// 数字正则匹配 /// public const string NumberPattern = @"^\d$"; /// - /// 计算性质数字正则匹配 + /// 计算性质数字正则匹配 /// public const string DigitsPattern = @"^[+-]?([0-9]*\.?[0-9]+|[0-9]+\.?[0-9]*)([eE][+-]?[0-9]+)?$"; /// - /// 正整数正则匹配 + /// 正整数正则匹配 /// public const string PIntPattern = @"^[1-9]\d*$"; /// - /// 负整数正则匹配 + /// 负整数正则匹配 /// public const string NIntPattern = @"^-[1-9]\d*$ "; /// - /// 整数正则匹配 + /// 整数正则匹配 /// public const string IntPattern = @"^-?[1-9]\d*$"; /// - /// 非负整数正则匹配 + /// 非负整数正则匹配 /// public const string NnIntPattern = @"^[1-9]\d*|0$"; /// - /// 非正整数正则匹配 + /// 非正整数正则匹配 /// public const string NpIntPattern = @"^-[1-9]\d*|0$"; /// - /// 正浮点数正则匹配 + /// 正浮点数正则匹配 /// public const string PDoublePattern = @"^[1-9]\d*\.\d*|0\.\d*[1-9]\d*$"; /// - /// 负浮点数正则匹配 + /// 负浮点数正则匹配 /// public const string NDoublePattern = @"^-([1-9]\d*\.\d*|0\.\d*[1-9]\d*)$"; /// - /// 浮点数正则匹配 + /// 浮点数正则匹配 /// public const string DoublePattern = @"^-?([1-9]\d*\.\d*|0\.\d*[1-9]\d*|0?\.0+|0)$"; /// - /// 非负浮点数正则匹配 + /// 非负浮点数正则匹配 /// public const string NnDoublePattern = @"^[1-9]\d*\.\d*|0\.\d*[1-9]\d*|0?\.0+|0$"; /// - /// 非正浮点数正则匹配 + /// 非正浮点数正则匹配 /// public const string NpDoublePattern = @"^(-([1-9]\d*\.\d*|0\.\d*[1-9]\d*))|0?\.0+|0$"; + + /// + /// 根据属性名称使用反射来获取值 + /// + /// + /// + public object GetValue(string propertyName) => GetType().GetField(propertyName).GetValue(null); } } \ No newline at end of file diff --git a/HandyControlDemo/App.xaml b/HandyControlDemo/App.xaml index 12f6ccc6..8e37d27b 100644 --- a/HandyControlDemo/App.xaml +++ b/HandyControlDemo/App.xaml @@ -10,9 +10,8 @@ - - + diff --git a/HandyControlDemo/Data/MessageToken.cs b/HandyControlDemo/Data/MessageToken.cs index feccd5f9..c9ae0edc 100644 --- a/HandyControlDemo/Data/MessageToken.cs +++ b/HandyControlDemo/Data/MessageToken.cs @@ -30,5 +30,7 @@ public static readonly string LoadButtonDemoCtl = nameof(LoadButtonDemoCtl); public static readonly string LoadToggleButtonDemoCtl = nameof(LoadToggleButtonDemoCtl); + + public static readonly string LoadTabControlDemoCtl = nameof(LoadTabControlDemoCtl); } } \ No newline at end of file diff --git a/HandyControlDemo/HandyControlDemo.csproj b/HandyControlDemo/HandyControlDemo.csproj index aa937f6f..56c4afc7 100644 --- a/HandyControlDemo/HandyControlDemo.csproj +++ b/HandyControlDemo/HandyControlDemo.csproj @@ -63,6 +63,16 @@ Designer + + True + True + Lang.resx + + + True + True + Lang.en.resx + True True @@ -89,6 +99,9 @@ LoadingDemoCtl.xaml + + NoUserContent.xaml + ButtonDemoCtl.xaml @@ -110,6 +123,9 @@ ProgressBarDemoCtl.xaml + + TabControlDemoCtl.xaml + ToggleButtonDemoCtl.xaml @@ -129,10 +145,6 @@ MainWindow.xaml Code - - Designer - MSBuild:Compile - Designer MSBuild:Compile @@ -141,7 +153,19 @@ Designer MSBuild:Compile - + + Designer + MSBuild:Compile + + + Designer + MSBuild:Compile + + + Designer + MSBuild:Compile + + Designer MSBuild:Compile @@ -173,6 +197,10 @@ Designer MSBuild:Compile + + Designer + MSBuild:Compile + Designer MSBuild:Compile @@ -201,6 +229,10 @@ Designer MSBuild:Compile + + Designer + MSBuild:Compile + Designer MSBuild:Compile @@ -224,16 +256,10 @@ - - - - - - @@ -246,5 +272,18 @@ + + + + + + PublicResXFileCodeGenerator + Lang.en.Designer.cs + + + PublicResXFileCodeGenerator + Lang.Designer.cs + + \ No newline at end of file diff --git a/HandyControlDemo/MainWindow.xaml b/HandyControlDemo/MainWindow.xaml index cf329059..b1b18d9c 100644 --- a/HandyControlDemo/MainWindow.xaml +++ b/HandyControlDemo/MainWindow.xaml @@ -16,29 +16,8 @@ Name="MyWindow" DataContext="{Binding Main,Source={StaticResource Locator}}" d:DesignHeight="800" - d:DesignWidth="1400"> - - - - - - - - - - - - - - - - - - - - - - + d:DesignWidth="1400" + NoUserContent="{Binding NoUserContent}"> diff --git a/HandyControlDemo/Properties/AssemblyInfo.cs b/HandyControlDemo/Properties/AssemblyInfo.cs index 5b9572c9..c8c620a7 100644 --- a/HandyControlDemo/Properties/AssemblyInfo.cs +++ b/HandyControlDemo/Properties/AssemblyInfo.cs @@ -12,5 +12,5 @@ using System.Windows; [assembly: AssemblyCulture("")] [assembly: ComVisible(false)] [assembly: ThemeInfo(ResourceDictionaryLocation.None, ResourceDictionaryLocation.SourceAssembly)] -[assembly: AssemblyVersion("1.2.0.0")] -[assembly: AssemblyFileVersion("1.2.0.0")] +[assembly: AssemblyVersion("1.2.1.0")] +[assembly: AssemblyFileVersion("1.2.1.0")] diff --git a/HandyControlDemo/Properties/Langs/Lang.Designer.cs b/HandyControlDemo/Properties/Langs/Lang.Designer.cs new file mode 100644 index 00000000..e206a143 --- /dev/null +++ b/HandyControlDemo/Properties/Langs/Lang.Designer.cs @@ -0,0 +1,360 @@ +//------------------------------------------------------------------------------ +// +// 此代码由工具生成。 +// 运行时版本:4.0.30319.42000 +// +// 对此文件的更改可能会导致不正确的行为,并且如果 +// 重新生成代码,这些更改将会丢失。 +// +//------------------------------------------------------------------------------ + +namespace HandyControlDemo.Properties.Langs { + using System; + + + /// + /// 一个强类型的资源类,用于查找本地化的字符串等。 + /// + // 此类是由 StronglyTypedResourceBuilder + // 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。 + // 若要添加或移除成员,请编辑 .ResX 文件,然后重新运行 ResGen + // (以 /str 作为命令选项),或重新生成 VS 项目。 + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + public class Lang { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Lang() { + } + + /// + /// 返回此类使用的缓存的 ResourceManager 实例。 + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + public static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("HandyControlDemo.Properties.Langs.Lang", typeof(Lang).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// 使用此强类型资源类,为所有资源查找 + /// 重写当前线程的 CurrentUICulture 属性。 + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + public static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// 查找类似 动画路径 的本地化字符串。 + /// + public static string AnimationPath { + get { + return ResourceManager.GetString("AnimationPath", resourceCulture); + } + } + + /// + /// 查找类似 按钮 的本地化字符串。 + /// + public static string Button { + get { + return ResourceManager.GetString("Button", resourceCulture); + } + } + + /// + /// 查找类似 透明按钮 的本地化字符串。 + /// + public static string ButtonOpacity { + get { + return ResourceManager.GetString("ButtonOpacity", resourceCulture); + } + } + + /// + /// 查找类似 轮播 的本地化字符串。 + /// + public static string Carousel { + get { + return ResourceManager.GetString("Carousel", resourceCulture); + } + } + + /// + /// 查找类似 复选框 的本地化字符串。 + /// + public static string CheckBox { + get { + return ResourceManager.GetString("CheckBox", resourceCulture); + } + } + + /// + /// 查找类似 颜色拾取器 的本地化字符串。 + /// + public static string ColorPicker { + get { + return ResourceManager.GetString("ColorPicker", resourceCulture); + } + } + + /// + /// 查找类似 对比滑块 的本地化字符串。 + /// + public static string CompareSlider { + get { + return ResourceManager.GetString("CompareSlider", resourceCulture); + } + } + + /// + /// 查找类似 控件 的本地化字符串。 + /// + public static string Controls { + get { + return ResourceManager.GetString("Controls", resourceCulture); + } + } + + /// + /// 查找类似 危险 的本地化字符串。 + /// + public static string Danger { + get { + return ResourceManager.GetString("Danger", resourceCulture); + } + } + + /// + /// 查找类似 默认 的本地化字符串。 + /// + public static string Default { + get { + return ResourceManager.GetString("Default", resourceCulture); + } + } + + /// + /// 查找类似 展开框 的本地化字符串。 + /// + public static string Expander { + get { + return ResourceManager.GetString("Expander", resourceCulture); + } + } + + /// + /// 查找类似 信息通知 的本地化字符串。 + /// + public static string Growl { + get { + return ResourceManager.GetString("Growl", resourceCulture); + } + } + + /// + /// 查找类似 检测到有新版本! 的本地化字符串。 + /// + public static string GrowlAsk { + get { + return ResourceManager.GetString("GrowlAsk", resourceCulture); + } + } + + /// + /// 查找类似 连接失败,请检查网络! 的本地化字符串。 + /// + public static string GrowlError { + get { + return ResourceManager.GetString("GrowlError", resourceCulture); + } + } + + /// + /// 查找类似 程序已崩溃~~~ 的本地化字符串。 + /// + public static string GrowlFatal { + get { + return ResourceManager.GetString("GrowlFatal", resourceCulture); + } + } + + /// + /// 查找类似 今天的天气不错~~~ 的本地化字符串。 + /// + public static string GrowlInfo { + get { + return ResourceManager.GetString("GrowlInfo", resourceCulture); + } + } + + /// + /// 查找类似 文件保存成功! 的本地化字符串。 + /// + public static string GrowlSuccess { + get { + return ResourceManager.GetString("GrowlSuccess", resourceCulture); + } + } + + /// + /// 查找类似 磁盘空间快要满了! 的本地化字符串。 + /// + public static string GrowlWarning { + get { + return ResourceManager.GetString("GrowlWarning", resourceCulture); + } + } + + /// + /// 查找类似 图片浏览器 的本地化字符串。 + /// + public static string ImageBrowser { + get { + return ResourceManager.GetString("ImageBrowser", resourceCulture); + } + } + + /// + /// 查找类似 信息 的本地化字符串。 + /// + public static string Info { + get { + return ResourceManager.GetString("Info", resourceCulture); + } + } + + /// + /// 查找类似 加载条 的本地化字符串。 + /// + public static string Loading { + get { + return ResourceManager.GetString("Loading", resourceCulture); + } + } + + /// + /// 查找类似 点击打开图片浏览器 的本地化字符串。 + /// + public static string OpenImageBrowser { + get { + return ResourceManager.GetString("OpenImageBrowser", resourceCulture); + } + } + + /// + /// 查找类似 页码条 的本地化字符串。 + /// + public static string Pagination { + get { + return ResourceManager.GetString("Pagination", resourceCulture); + } + } + + /// + /// 查找类似 主要 的本地化字符串。 + /// + public static string Primary { + get { + return ResourceManager.GetString("Primary", resourceCulture); + } + } + + /// + /// 查找类似 进度条 的本地化字符串。 + /// + public static string ProgressBar { + get { + return ResourceManager.GetString("ProgressBar", resourceCulture); + } + } + + /// + /// 查找类似 样式模板 的本地化字符串。 + /// + public static string Styles { + get { + return ResourceManager.GetString("Styles", resourceCulture); + } + } + + /// + /// 查找类似 成功 的本地化字符串。 + /// + public static string Success { + get { + return ResourceManager.GetString("Success", resourceCulture); + } + } + + /// + /// 查找类似 选项卡控件 的本地化字符串。 + /// + public static string TabControl { + get { + return ResourceManager.GetString("TabControl", resourceCulture); + } + } + + /// + /// 查找类似 文本块 的本地化字符串。 + /// + public static string TextBlock { + get { + return ResourceManager.GetString("TextBlock", resourceCulture); + } + } + + /// + /// 查找类似 时间条 的本地化字符串。 + /// + public static string TimeBar { + get { + return ResourceManager.GetString("TimeBar", resourceCulture); + } + } + + /// + /// 查找类似 标题 的本地化字符串。 + /// + public static string Title { + get { + return ResourceManager.GetString("Title", resourceCulture); + } + } + + /// + /// 查找类似 切换按钮 的本地化字符串。 + /// + public static string ToggleButton { + get { + return ResourceManager.GetString("ToggleButton", resourceCulture); + } + } + + /// + /// 查找类似 警告 的本地化字符串。 + /// + public static string Warning { + get { + return ResourceManager.GetString("Warning", resourceCulture); + } + } + } +} diff --git a/HandyControlDemo/Properties/Langs/Lang.en.Designer.cs b/HandyControlDemo/Properties/Langs/Lang.en.Designer.cs new file mode 100644 index 00000000..e69de29b diff --git a/HandyControlDemo/Properties/Langs/Lang.en.resx b/HandyControlDemo/Properties/Langs/Lang.en.resx new file mode 100644 index 00000000..c47ebe1e --- /dev/null +++ b/HandyControlDemo/Properties/Langs/Lang.en.resx @@ -0,0 +1,219 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Controls + + + Styles + + + Growl + + + It's a nice day today~~~ + + + File saved successfully! + + + Disk space is running out! + + + Connection failed. please check your network! + + + The program has crashed~~~ + + + A new version has been detected! + + + Loading + + + ImageBrowser + + + ColorPicker + + + Carousel + + + CompareSlider + + + TimeBar + + + Expander + + + Pagination + + + Click to open image browser + + + ProgressBar + + + AnimationPath + + + Button + + + ToggleButton + + + TabControl + + + CheckBox + + + TextBlock + + + Default + + + Primary + + + Success + + + Info + + + Warning + + + Danger + + + Opacity button + + + Title + + \ No newline at end of file diff --git a/HandyControlDemo/Properties/Langs/Lang.resx b/HandyControlDemo/Properties/Langs/Lang.resx new file mode 100644 index 00000000..2d238d25 --- /dev/null +++ b/HandyControlDemo/Properties/Langs/Lang.resx @@ -0,0 +1,199 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 1.3 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.3500.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.3500.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 控件 + + + 样式模板 + + + 信息通知 + + + 今天的天气不错~~~ + + + 文件保存成功! + + + 磁盘空间快要满了! + + + 连接失败,请检查网络! + + + 程序已崩溃~~~ + + + 检测到有新版本! + + + 加载条 + + + 图片浏览器 + + + 颜色拾取器 + + + 轮播 + + + 对比滑块 + + + 时间条 + + + 展开框 + + + 页码条 + + + 点击打开图片浏览器 + + + 进度条 + + + 动画路径 + + + 按钮 + + + 切换按钮 + + + 选项卡控件 + + + 复选框 + + + 文本块 + + + 默认 + + + 主要 + + + 成功 + + + 信息 + + + 警告 + + + 危险 + + + 透明按钮 + + + 标题 + + \ No newline at end of file diff --git a/HandyControlDemo/Resources/Lang/zh-cn.xaml b/HandyControlDemo/Resources/Lang/zh-cn.xaml deleted file mode 100644 index 83f9964b..00000000 --- a/HandyControlDemo/Resources/Lang/zh-cn.xaml +++ /dev/null @@ -1,28 +0,0 @@ - - - 控件 - 样式模板 - 信息通知 - 今天的天气不错~~~ - 文件保存成功! - 磁盘空间快要满了! - 连接服务器失败,请检查网络! - 程序已崩溃~~~ - 检测到有新版本,是否更新? - 加载条 - 图片浏览器 - 颜色拾取器 - 轮播 - 对比滑块 - 时间条 - 展开框 - 页码条 - 点击打开图片浏览器 - 进度条 - 动画路径 - 按钮 - 切换按钮 - - \ No newline at end of file diff --git a/HandyControlDemo/Resources/Themes/Basic/Geometries.xaml b/HandyControlDemo/Resources/Themes/Basic/Geometries.xaml new file mode 100644 index 00000000..30fb4ba4 --- /dev/null +++ b/HandyControlDemo/Resources/Themes/Basic/Geometries.xaml @@ -0,0 +1,7 @@ + + + M512 0h1216a512 512 0 1 1 0 1024H512A512 512 0 1 1 512 0zM420.16 311.04V768h74.88V433.92h2.56l228.48 334.08h72.96V311.04h-75.52v329.6h-2.56l-225.92-329.6h-74.88z m468.48 0V768h340.48v-64h-265.6V565.76h239.36v-64h-239.36V375.04h254.72v-64h-329.6z m369.28 0l131.2 456.96h80l89.6-343.68h2.56l88.96 343.68h79.36l131.84-456.96h-84.48l-85.76 347.52h-2.56l-90.24-347.52h-77.44l-90.24 347.52h-2.56l-85.76-347.52h-84.48z + M40.493382,19.001303 C36.637875,19.06448 33.938568,21.421986 33.948524,25.271919 L34.068279,71.56765 34.066906,71.598007 34.068745,71.747833 34.18895,118.21758 C34.202225,123.35083 39.026951,129.19344 44.965271,131.2674 50.903587,133.34137 55.706783,130.86133 55.693504,125.72808 L55.589508,85.524513 93.866371,85.524513 93.950943,118.21758 C93.964218,123.35083 98.788948,129.19344 104.72726,131.2674 110.66558,133.34137 115.46878,130.86133 115.4555,125.72808 L115.33575,79.432381 115.33712,79.401993 115.33528,79.252007 115.21507,32.782413 C115.2018,27.64917 110.37708,21.806566 104.43876,19.732603 98.500435,17.658638 93.697243,20.138674 93.710518,25.271919 L93.814514,65.475487 55.537647,65.475487 55.453079,32.782413 C55.439804,27.64917 50.615082,21.806566 44.676762,19.732603 43.192181,19.214111 41.778549,18.980244 40.493382,19.001303 z M9.999999,0 L140,0 C145.52284,0 150,4.4771523 150,9.999999 L150,140 C150,145.52284 145.52284,150 140,150 L9.999999,150 C4.4771523,150 0,145.52284 0,140 L0,9.999999 C0,4.4771523 4.4771523,0 9.999999,0 z + + \ No newline at end of file diff --git a/HandyControlDemo/Resources/Themes/Styles/Label.xaml b/HandyControlDemo/Resources/Themes/Styles/Label.xaml new file mode 100644 index 00000000..a6138bfe --- /dev/null +++ b/HandyControlDemo/Resources/Themes/Styles/Label.xaml @@ -0,0 +1,19 @@ + + + + + \ No newline at end of file diff --git a/HandyControlDemo/Resources/Themes/Styles/Style.xaml b/HandyControlDemo/Resources/Themes/Styles/Style.xaml new file mode 100644 index 00000000..c187fff7 --- /dev/null +++ b/HandyControlDemo/Resources/Themes/Styles/Style.xaml @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/HandyControlDemo/Resources/Themes/Styles/TreeViewItem.xaml b/HandyControlDemo/Resources/Themes/Styles/TreeViewItem.xaml new file mode 100644 index 00000000..ffd16b8e --- /dev/null +++ b/HandyControlDemo/Resources/Themes/Styles/TreeViewItem.xaml @@ -0,0 +1,21 @@ + + + + + + + + + \ No newline at end of file diff --git a/HandyControlDemo/UserControl/ControlLocator.cs b/HandyControlDemo/UserControl/ControlLocator.cs index 20268ccb..067b0fe7 100644 --- a/HandyControlDemo/UserControl/ControlLocator.cs +++ b/HandyControlDemo/UserControl/ControlLocator.cs @@ -13,6 +13,7 @@ namespace HandyControlDemo.UserControl { SimpleIoc.Default.Register(); SimpleIoc.Default.Register(); + SimpleIoc.Default.Register(); SimpleIoc.Default.Register(); SimpleIoc.Default.Register(); SimpleIoc.Default.Register(); @@ -26,6 +27,7 @@ namespace HandyControlDemo.UserControl SimpleIoc.Default.Register(); SimpleIoc.Default.Register(); SimpleIoc.Default.Register(); + SimpleIoc.Default.Register(); } public static ControlLocator Instance => new Lazy(() => new ControlLocator()).Value; @@ -36,6 +38,8 @@ namespace HandyControlDemo.UserControl public LeftMainContent LeftMainContent => ServiceLocator.Current.GetInstance(); + public NoUserContent NoUserContent => ServiceLocator.Current.GetInstance(); + #endregion #region Controls @@ -70,6 +74,8 @@ namespace HandyControlDemo.UserControl public ProgressBarDemoCtl ProgressBarDemoCtl => new ProgressBarDemoCtl(); + public TabControlDemoCtl TabControlDemoCtl => new TabControlDemoCtl(); + #endregion } } \ No newline at end of file diff --git a/HandyControlDemo/UserControl/ControlLocator.tt b/HandyControlDemo/UserControl/ControlLocator.tt index d0afc878..e8ecc91f 100644 --- a/HandyControlDemo/UserControl/ControlLocator.tt +++ b/HandyControlDemo/UserControl/ControlLocator.tt @@ -5,7 +5,8 @@ var singleList = new List { "MainContent", - "LeftMainContent" + "LeftMainContent", + "NoUserContent" }; var controlList = new List { @@ -24,7 +25,8 @@ var styleList = new List "ButtonDemoCtl", "ToggleButtonDemoCtl", "ExpanderDemoCtl", - "ProgressBarDemoCtl" + "ProgressBarDemoCtl", + "TabControlDemoCtl" }; #> using System; diff --git a/HandyControlDemo/UserControl/Controls/GrowlDemoCtl.xaml b/HandyControlDemo/UserControl/Controls/GrowlDemoCtl.xaml index 21975f89..14756f83 100644 --- a/HandyControlDemo/UserControl/Controls/GrowlDemoCtl.xaml +++ b/HandyControlDemo/UserControl/Controls/GrowlDemoCtl.xaml @@ -6,13 +6,13 @@ Background="White"> - + - + diff --git a/HandyControlDemo/UserControl/Controls/ImageBrowserDemoCtl.xaml b/HandyControlDemo/UserControl/Controls/ImageBrowserDemoCtl.xaml index 78b9247a..a35f9a89 100644 --- a/HandyControlDemo/UserControl/Controls/ImageBrowserDemoCtl.xaml +++ b/HandyControlDemo/UserControl/Controls/ImageBrowserDemoCtl.xaml @@ -2,9 +2,10 @@ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Background="White" + xmlns:langs="clr-namespace:HandyControlDemo.Properties.Langs" DataContext="{Binding ImageBrowserDemo,Source={StaticResource Locator}}" xmlns:controls="clr-namespace:HandyControl.Controls;assembly=HandyControl"> - + diff --git a/HandyControlDemo/UserControl/Controls/TabControlDemoCtl.xaml b/HandyControlDemo/UserControl/Controls/TabControlDemoCtl.xaml new file mode 100644 index 00000000..8e897d20 --- /dev/null +++ b/HandyControlDemo/UserControl/Controls/TabControlDemoCtl.xaml @@ -0,0 +1,65 @@ + + + + + + + + diff --git a/HandyControlDemo/UserControl/Controls/TabControlDemoCtl.xaml.cs b/HandyControlDemo/UserControl/Controls/TabControlDemoCtl.xaml.cs new file mode 100644 index 00000000..86ce60ba --- /dev/null +++ b/HandyControlDemo/UserControl/Controls/TabControlDemoCtl.xaml.cs @@ -0,0 +1,14 @@ +// ReSharper disable once CheckNamespace +namespace HandyControlDemo.UserControl +{ + /// + /// TabControlDemoCtl.xaml 的交互逻辑 + /// + public partial class TabControlDemoCtl + { + public TabControlDemoCtl() + { + InitializeComponent(); + } + } +} diff --git a/HandyControlDemo/UserControl/Main/LeftMainContent.xaml b/HandyControlDemo/UserControl/Main/LeftMainContent.xaml index fca35ebc..a0510fde 100644 --- a/HandyControlDemo/UserControl/Main/LeftMainContent.xaml +++ b/HandyControlDemo/UserControl/Main/LeftMainContent.xaml @@ -5,6 +5,7 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:data="clr-namespace:HandyControlDemo.Data" xmlns:controls="clr-namespace:HandyControl.Controls;assembly=HandyControl" + xmlns:langs="clr-namespace:HandyControlDemo.Properties.Langs" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"> @@ -12,22 +13,23 @@ - - - - - + + + + + - - - - - - - - - - + + + + + + + + + + + \ No newline at end of file diff --git a/HandyControlDemo/UserControl/Main/MainContent.xaml b/HandyControlDemo/UserControl/Main/MainContent.xaml index e25e1273..af71d28c 100644 --- a/HandyControlDemo/UserControl/Main/MainContent.xaml +++ b/HandyControlDemo/UserControl/Main/MainContent.xaml @@ -3,13 +3,13 @@ x:Class="HandyControlDemo.UserControl.MainContent" Background="#f0f0f0"> - + - - + + diff --git a/HandyControlDemo/UserControl/Main/NoUserContent.xaml b/HandyControlDemo/UserControl/Main/NoUserContent.xaml new file mode 100644 index 00000000..d309b59c --- /dev/null +++ b/HandyControlDemo/UserControl/Main/NoUserContent.xaml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + diff --git a/HandyControlDemo/UserControl/Main/NoUserContent.xaml.cs b/HandyControlDemo/UserControl/Main/NoUserContent.xaml.cs new file mode 100644 index 00000000..0242de49 --- /dev/null +++ b/HandyControlDemo/UserControl/Main/NoUserContent.xaml.cs @@ -0,0 +1,14 @@ +// ReSharper disable once CheckNamespace +namespace HandyControlDemo.UserControl +{ + /// + /// NoUserContent.xaml 的交互逻辑 + /// + public partial class NoUserContent + { + public NoUserContent() + { + InitializeComponent(); + } + } +} diff --git a/HandyControlDemo/UserControl/Styles/ButtonDemoCtl.xaml b/HandyControlDemo/UserControl/Styles/ButtonDemoCtl.xaml index 142798ec..fcc0448d 100644 --- a/HandyControlDemo/UserControl/Styles/ButtonDemoCtl.xaml +++ b/HandyControlDemo/UserControl/Styles/ButtonDemoCtl.xaml @@ -2,38 +2,39 @@ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:controls="clr-namespace:HandyControl.Controls;assembly=HandyControl" + xmlns:langs="clr-namespace:HandyControlDemo.Properties.Langs" Background="White"> - - + + - - + + - - + + - - + + - - + + - - + + @@ -69,7 +70,7 @@ - + diff --git a/HandyControlDemo/UserControl/Styles/ExpanderDemoCtl.xaml b/HandyControlDemo/UserControl/Styles/ExpanderDemoCtl.xaml index bdef7ab3..5cd2b108 100644 --- a/HandyControlDemo/UserControl/Styles/ExpanderDemoCtl.xaml +++ b/HandyControlDemo/UserControl/Styles/ExpanderDemoCtl.xaml @@ -2,19 +2,20 @@ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Background="White" + xmlns:langs="clr-namespace:HandyControlDemo.Properties.Langs" xmlns:controls="clr-namespace:HandyControl.Controls;assembly=HandyControl"> - + - + - + - + diff --git a/HandyControlDemo/UserControl/Styles/ToggleButtonDemoCtl.xaml b/HandyControlDemo/UserControl/Styles/ToggleButtonDemoCtl.xaml index 6e0978ea..84f72ad7 100644 --- a/HandyControlDemo/UserControl/Styles/ToggleButtonDemoCtl.xaml +++ b/HandyControlDemo/UserControl/Styles/ToggleButtonDemoCtl.xaml @@ -2,37 +2,38 @@ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Background="White" + xmlns:langs="clr-namespace:HandyControlDemo.Properties.Langs" xmlns:controls="clr-namespace:HandyControl.Controls;assembly=HandyControl"> - - + + - - + + - - + + - - + + - - + + - - + + diff --git a/HandyControlDemo/ViewModel/GrowlDemoViewModel.cs b/HandyControlDemo/ViewModel/GrowlDemoViewModel.cs index 8cb26d9a..a3413087 100644 --- a/HandyControlDemo/ViewModel/GrowlDemoViewModel.cs +++ b/HandyControlDemo/ViewModel/GrowlDemoViewModel.cs @@ -1,33 +1,32 @@ using System; using GalaSoft.MvvmLight.Command; using HandyControl.Controls; -using HandyControl.Tools; namespace HandyControlDemo.ViewModel { public class GrowlDemoViewModel { public RelayCommand InfoCmd => new Lazy(() => - new RelayCommand(() => Growl.Info(ResourceHelper.GetString("GrowlInfo")))).Value; + new RelayCommand(() => Growl.Info(Properties.Langs.Lang.GrowlInfo))).Value; public RelayCommand SuccessCmd => new Lazy(() => - new RelayCommand(() => Growl.Success(ResourceHelper.GetString("GrowlSuccess")))).Value; + new RelayCommand(() => Growl.Success(Properties.Langs.Lang.GrowlSuccess))).Value; public RelayCommand WarningCmd => new Lazy(() => - new RelayCommand(() => Growl.Warning(ResourceHelper.GetString("GrowlWarning")))).Value; + new RelayCommand(() => Growl.Warning(Properties.Langs.Lang.GrowlWarning))).Value; public RelayCommand ErrorCmd => new Lazy(() => - new RelayCommand(() => Growl.Error(ResourceHelper.GetString("GrowlError")))).Value; + new RelayCommand(() => Growl.Error(Properties.Langs.Lang.GrowlError))).Value; public RelayCommand AskCmd => new Lazy(() => - new RelayCommand(() => Growl.Ask("GrowlAsk", (closeAction, b) => + new RelayCommand(() => Growl.Ask(Properties.Langs.Lang.GrowlAsk, (closeAction, b) => { Growl.Info(b.ToString()); closeAction?.Invoke(); }))).Value; public RelayCommand FatalCmd => new Lazy(() => - new RelayCommand(() => Growl.Fatal(ResourceHelper.GetString("GrowlFatal")))).Value; + new RelayCommand(() => Growl.Fatal(Properties.Langs.Lang.GrowlFatal))).Value; public RelayCommand ClearCmd => new Lazy(() => new RelayCommand(Growl.Clear)).Value; diff --git a/HandyControlDemo/ViewModel/ImageBrowserDemoViewModel.cs b/HandyControlDemo/ViewModel/ImageBrowserDemoViewModel.cs index 2fa5120a..2324a4e7 100644 --- a/HandyControlDemo/ViewModel/ImageBrowserDemoViewModel.cs +++ b/HandyControlDemo/ViewModel/ImageBrowserDemoViewModel.cs @@ -1,5 +1,5 @@ using System; -using GalaSoft.MvvmLight.Command; +using GalaSoft.MvvmLight.CommandWpf; using HandyControl.Controls; namespace HandyControlDemo.ViewModel diff --git a/HandyControlDemo/ViewModel/MainViewModel.cs b/HandyControlDemo/ViewModel/MainViewModel.cs index 12e94878..d17136a4 100644 --- a/HandyControlDemo/ViewModel/MainViewModel.cs +++ b/HandyControlDemo/ViewModel/MainViewModel.cs @@ -2,7 +2,7 @@ using System.Windows; using System.Windows.Controls; using GalaSoft.MvvmLight; -using GalaSoft.MvvmLight.Command; +using GalaSoft.MvvmLight.CommandWpf; using GalaSoft.MvvmLight.Messaging; using HandyControlDemo.Data; using HandyControlDemo.UserControl; @@ -33,12 +33,18 @@ namespace HandyControlDemo.ViewModel /// private object _subContent; + /// + /// 非用户区域内容 + /// + private object _noUserContent; + #endregion public MainViewModel() { LeftMainContent = ControlLocator.Instance.LeftMainContent; MainContent = ControlLocator.Instance.MainContent; + NoUserContent = ControlLocator.Instance.NoUserContent; Messenger.Default.Register(this, MessageToken.LoadGrowlDemoCtl, obj => SubContent = ControlLocator.Instance.GrowlDemoCtl); Messenger.Default.Register(this, MessageToken.LoadLoadingDemoCtl, obj => SubContent = ControlLocator.Instance.LoadingDemoCtl); @@ -53,10 +59,20 @@ namespace HandyControlDemo.ViewModel Messenger.Default.Register(this, MessageToken.LoadAnimationPathDemoCtl, obj => SubContent = ControlLocator.Instance.AnimationPathDemoCtl); Messenger.Default.Register(this, MessageToken.LoadButtonDemoCtl, obj => SubContent = ControlLocator.Instance.ButtonDemoCtl); Messenger.Default.Register(this, MessageToken.LoadToggleButtonDemoCtl, obj => SubContent = ControlLocator.Instance.ToggleButtonDemoCtl); + Messenger.Default.Register(this, MessageToken.LoadTabControlDemoCtl, obj => SubContent = ControlLocator.Instance.TabControlDemoCtl); } #region 属性 + /// + /// 非用户区域内容 + /// + public object NoUserContent + { + get => _noUserContent; + set => Set(ref _noUserContent, value); + } + /// /// 左侧主内容 /// diff --git a/README.md b/README.md index 98d85a7e..943ccbd6 100644 --- a/README.md +++ b/README.md @@ -54,6 +54,10 @@ ![进度条ProgressBar](https://raw.githubusercontent.com/NaBian/HandyControl/master/Resources/ProgressBar.gif) +### 12、选项卡控件TabControl + +![选项卡控件TabControl](https://raw.githubusercontent.com/NaBian/HandyControl/master/Resources/TabControl.gif) + # 使用方法 第一步:添加HandyControl的引用; @@ -85,10 +89,9 @@ ``` * 为什么我连编译都无法通过: -编译之前,请确保IDE为vs2017且c#最低版本为7.0,HandyControl目前仅支持4.5以上的.net环境,低版本支持估计很快就有了。 +编译之前,请确保IDE为vs2017且c#最低版本为7.0,HandyControl目前仅支持4.5以上的.net环境。 # v1.3.0版本计划 -1、添加可拖动的tabcontrol; -2、添加时间、日历控件; -3、添加步骤条控件; \ No newline at end of file +1、添加时间、日历控件; +2、添加步骤条控件; \ No newline at end of file diff --git a/Resources/TabControl.gif b/Resources/TabControl.gif new file mode 100644 index 00000000..d897226e Binary files /dev/null and b/Resources/TabControl.gif differ