diff --git a/README.md b/README.md index 5a05eb07..402c5f19 100644 --- a/README.md +++ b/README.md @@ -48,6 +48,10 @@ Step 3:enjoy coding ## Latest examples +### SideMenu + +![SideMenu](https://raw.githubusercontent.com/NaBian/HandyControl/master/Resources/SideMenu.png) + ### NotifyIcon ![NotifyIcon](https://raw.githubusercontent.com/NaBian/HandyControl/master/Resources/NotifyIcon.png) @@ -64,12 +68,12 @@ Step 3:enjoy coding ![Badge](https://raw.githubusercontent.com/NaBian/HandyControl/master/Resources/Badge.png) +## History publication + ### Gravatar ![Gravatar](https://raw.githubusercontent.com/NaBian/HandyControl/master/Resources/Gravatar.gif) -## History publication - ### GoToTop ![GoToTop](https://raw.githubusercontent.com/NaBian/HandyControl/master/Resources/GoToTop.gif) diff --git a/Resources/SideMenu.png b/Resources/SideMenu.png new file mode 100644 index 00000000..fc0a655a Binary files /dev/null and b/Resources/SideMenu.png differ diff --git a/src/Core_30/HandyControlDemo_Core_30/HandyControlDemo_Core30.csproj b/src/Core_30/HandyControlDemo_Core_30/HandyControlDemo_Core30.csproj index 62a7d384..2f019719 100644 --- a/src/Core_30/HandyControlDemo_Core_30/HandyControlDemo_Core30.csproj +++ b/src/Core_30/HandyControlDemo_Core_30/HandyControlDemo_Core30.csproj @@ -321,6 +321,30 @@ Resources\Img\under_construction.gif + + Resources\Img\DevOps\DevOps-Boards.png + + + Resources\Img\DevOps\DevOps-Overview.png + + + Resources\Img\DevOps\DevOps-Pipelines.png + + + Resources\Img\DevOps\DevOps-Repos.png + + + Resources\Img\DevOps\DevOps-TestPlans.png + + + Resources\Img\LeftMainContent\MainMenuControl_16x.png + + + Resources\fabric-icons.ttf + + + Resources\Img\LeftMainContent\MainMenuControl_16x.png + diff --git a/src/HandyControl_Net_GE45.sln.DotSettings b/src/HandyControl_Net_GE45.sln.DotSettings new file mode 100644 index 00000000..df567fc2 --- /dev/null +++ b/src/HandyControl_Net_GE45.sln.DotSettings @@ -0,0 +1,2 @@ + + True \ No newline at end of file diff --git a/src/Net_40/HandyControlDemo_Net_40/HandyControlDemo_Net_40.csproj b/src/Net_40/HandyControlDemo_Net_40/HandyControlDemo_Net_40.csproj index bd927660..3324c055 100644 --- a/src/Net_40/HandyControlDemo_Net_40/HandyControlDemo_Net_40.csproj +++ b/src/Net_40/HandyControlDemo_Net_40/HandyControlDemo_Net_40.csproj @@ -381,13 +381,35 @@ Lang.Designer.cs - + + + Resources\fabric-icons.ttf + + Data\MessageToken.tt TextTemplatingFileGenerator MessageToken.cs + + Resources\Img\LeftMainContent\MainMenuControl_16x.png + + + Resources\Img\DevOps\DevOps-Boards.png + + + Resources\Img\DevOps\DevOps-Overview.png + + + Resources\Img\DevOps\DevOps-Pipelines.png + + + Resources\Img\DevOps\DevOps-Repos.png + + + Resources\Img\DevOps\DevOps-TestPlans.png + Resources\Img\LeftMainContent\RepeatButton_16x.png diff --git a/src/Net_GE45/HandyControlDemo_Net_GE45/HandyControlDemo_Net_GE45.csproj b/src/Net_GE45/HandyControlDemo_Net_GE45/HandyControlDemo_Net_GE45.csproj index 4d5aaea8..4e165a1b 100644 --- a/src/Net_GE45/HandyControlDemo_Net_GE45/HandyControlDemo_Net_GE45.csproj +++ b/src/Net_GE45/HandyControlDemo_Net_GE45/HandyControlDemo_Net_GE45.csproj @@ -411,6 +411,29 @@ TextTemplatingFileGenerator MessageToken.cs + + Resources\Img\DevOps\DevOps-Boards.png + + + Resources\Img\DevOps\DevOps-Overview.png + + + Resources\Img\DevOps\DevOps-Pipelines.png + + + Resources\Img\DevOps\DevOps-Repos.png + + + Resources\Img\DevOps\DevOps-TestPlans.png + + + Resources\Img\LeftMainContent\MainMenuControl_16x.png + + + + + Resources\fabric-icons.ttf + diff --git a/src/Shared/HandyControlDemo_Shared/App.xaml.cs b/src/Shared/HandyControlDemo_Shared/App.xaml.cs index 493daf1e..b597e60c 100644 --- a/src/Shared/HandyControlDemo_Shared/App.xaml.cs +++ b/src/Shared/HandyControlDemo_Shared/App.xaml.cs @@ -20,7 +20,7 @@ namespace HandyControlDemo base.OnStartup(e); GlobalData.Init(); - Thread.CurrentThread.CurrentUICulture = new CultureInfo(GlobalData.Config.Lang); + ConfigHelper.Instance.SetLang(GlobalData.Config.Lang); if (GlobalData.Config.Skin != SkinType.Default) { @@ -28,7 +28,7 @@ namespace HandyControlDemo } #if !Core - BlurWindow.SystemVersionInfo = CommonHelper.GetSystemVersionInfo(); + ConfigHelper.Instance.SetSystemVersionInfo(CommonHelper.GetSystemVersionInfo()); #endif } diff --git a/src/Shared/HandyControlDemo_Shared/Data/MessageToken.cs b/src/Shared/HandyControlDemo_Shared/Data/MessageToken.cs index e6f29fbc..9567de5c 100644 --- a/src/Shared/HandyControlDemo_Shared/Data/MessageToken.cs +++ b/src/Shared/HandyControlDemo_Shared/Data/MessageToken.cs @@ -92,6 +92,8 @@ public static readonly string DialogDemoCtl = nameof(DialogDemoCtl); + public static readonly string SideMenuDemoCtl = nameof(SideMenuDemoCtl); + public static readonly string ButtonDemoCtl = nameof(ButtonDemoCtl); public static readonly string RepeatButtonDemoCtl = nameof(RepeatButtonDemoCtl); diff --git a/src/Shared/HandyControlDemo_Shared/Data/MessageToken.tt b/src/Shared/HandyControlDemo_Shared/Data/MessageToken.tt index e9e4d4b7..13e61674 100644 --- a/src/Shared/HandyControlDemo_Shared/Data/MessageToken.tt +++ b/src/Shared/HandyControlDemo_Shared/Data/MessageToken.tt @@ -48,7 +48,8 @@ var controlList = new List "NotifyIconDemoCtl", "BadgeDemoCtl", "GravatarDemoCtl", - "DialogDemoCtl" + "DialogDemoCtl", + "SideMenuDemoCtl" }; var styleList = new List { diff --git a/src/Shared/HandyControlDemo_Shared/HandyControlDemo_Shared.projitems b/src/Shared/HandyControlDemo_Shared/HandyControlDemo_Shared.projitems index bcdb7a3a..c189a905 100644 --- a/src/Shared/HandyControlDemo_Shared/HandyControlDemo_Shared.projitems +++ b/src/Shared/HandyControlDemo_Shared/HandyControlDemo_Shared.projitems @@ -146,6 +146,9 @@ ShieldDemoCtl.xaml + + SideMenuDemoCtl.xaml + StepBarDemoCtl.xaml @@ -280,6 +283,7 @@ + @@ -333,6 +337,10 @@ Designer MSBuild:Compile + + Designer + MSBuild:Compile + Designer MSBuild:Compile @@ -505,6 +513,10 @@ Designer MSBuild:Compile + + Designer + MSBuild:Compile + Designer MSBuild:Compile diff --git a/src/Shared/HandyControlDemo_Shared/Properties/Langs/Lang.Designer.cs b/src/Shared/HandyControlDemo_Shared/Properties/Langs/Lang.Designer.cs index 41ef454d..c4a75fbe 100644 --- a/src/Shared/HandyControlDemo_Shared/Properties/Langs/Lang.Designer.cs +++ b/src/Shared/HandyControlDemo_Shared/Properties/Langs/Lang.Designer.cs @@ -1158,6 +1158,15 @@ namespace HandyControlDemo.Properties.Langs { } } + /// + /// 查找类似 侧边菜单 的本地化字符串。 + /// + public static string SideMenu { + get { + return ResourceManager.GetString("SideMenu", resourceCulture); + } + } + /// /// 查找类似 滑块 的本地化字符串。 /// diff --git a/src/Shared/HandyControlDemo_Shared/Properties/Langs/Lang.en.resx b/src/Shared/HandyControlDemo_Shared/Properties/Langs/Lang.en.resx index 0cbadb2c..5cad6050 100644 --- a/src/Shared/HandyControlDemo_Shared/Properties/Langs/Lang.en.resx +++ b/src/Shared/HandyControlDemo_Shared/Properties/Langs/Lang.en.resx @@ -576,4 +576,7 @@ Show in the main window + + SideMenu + \ No newline at end of file diff --git a/src/Shared/HandyControlDemo_Shared/Properties/Langs/Lang.resx b/src/Shared/HandyControlDemo_Shared/Properties/Langs/Lang.resx index 64783b77..72ded0fb 100644 --- a/src/Shared/HandyControlDemo_Shared/Properties/Langs/Lang.resx +++ b/src/Shared/HandyControlDemo_Shared/Properties/Langs/Lang.resx @@ -576,4 +576,7 @@ 在主窗口显示 + + 侧边菜单 + \ No newline at end of file diff --git a/src/Shared/HandyControlDemo_Shared/Resources/Img/DevOps/DevOps-Boards.png b/src/Shared/HandyControlDemo_Shared/Resources/Img/DevOps/DevOps-Boards.png new file mode 100644 index 00000000..5d14a4a8 Binary files /dev/null and b/src/Shared/HandyControlDemo_Shared/Resources/Img/DevOps/DevOps-Boards.png differ diff --git a/src/Shared/HandyControlDemo_Shared/Resources/Img/DevOps/DevOps-Overview.png b/src/Shared/HandyControlDemo_Shared/Resources/Img/DevOps/DevOps-Overview.png new file mode 100644 index 00000000..e9e3d7e4 Binary files /dev/null and b/src/Shared/HandyControlDemo_Shared/Resources/Img/DevOps/DevOps-Overview.png differ diff --git a/src/Shared/HandyControlDemo_Shared/Resources/Img/DevOps/DevOps-Pipelines.png b/src/Shared/HandyControlDemo_Shared/Resources/Img/DevOps/DevOps-Pipelines.png new file mode 100644 index 00000000..ad1da5b8 Binary files /dev/null and b/src/Shared/HandyControlDemo_Shared/Resources/Img/DevOps/DevOps-Pipelines.png differ diff --git a/src/Shared/HandyControlDemo_Shared/Resources/Img/DevOps/DevOps-Repos.png b/src/Shared/HandyControlDemo_Shared/Resources/Img/DevOps/DevOps-Repos.png new file mode 100644 index 00000000..379d17eb Binary files /dev/null and b/src/Shared/HandyControlDemo_Shared/Resources/Img/DevOps/DevOps-Repos.png differ diff --git a/src/Shared/HandyControlDemo_Shared/Resources/Img/DevOps/DevOps-TestPlans.png b/src/Shared/HandyControlDemo_Shared/Resources/Img/DevOps/DevOps-TestPlans.png new file mode 100644 index 00000000..686d0730 Binary files /dev/null and b/src/Shared/HandyControlDemo_Shared/Resources/Img/DevOps/DevOps-TestPlans.png differ diff --git a/src/Shared/HandyControlDemo_Shared/Resources/Img/LeftMainContent/MainMenuControl_16x.png b/src/Shared/HandyControlDemo_Shared/Resources/Img/LeftMainContent/MainMenuControl_16x.png new file mode 100644 index 00000000..16d105af Binary files /dev/null and b/src/Shared/HandyControlDemo_Shared/Resources/Img/LeftMainContent/MainMenuControl_16x.png differ diff --git a/src/Shared/HandyControlDemo_Shared/Resources/Themes/Basic/Basic.xaml b/src/Shared/HandyControlDemo_Shared/Resources/Themes/Basic/Basic.xaml index 6b2fbe74..927f257f 100644 --- a/src/Shared/HandyControlDemo_Shared/Resources/Themes/Basic/Basic.xaml +++ b/src/Shared/HandyControlDemo_Shared/Resources/Themes/Basic/Basic.xaml @@ -4,6 +4,7 @@ + \ No newline at end of file diff --git a/src/Shared/HandyControlDemo_Shared/Resources/Themes/Basic/Fonts.xaml b/src/Shared/HandyControlDemo_Shared/Resources/Themes/Basic/Fonts.xaml new file mode 100644 index 00000000..700d0689 --- /dev/null +++ b/src/Shared/HandyControlDemo_Shared/Resources/Themes/Basic/Fonts.xaml @@ -0,0 +1,6 @@ + + + pack://application:,,,/HandyControlDemo;component/Resources/fabric-icons.ttf#Fabric MDL2 Assets + + diff --git a/src/Shared/HandyControlDemo_Shared/Resources/Themes/Styles/Style.xaml b/src/Shared/HandyControlDemo_Shared/Resources/Themes/Styles/Style.xaml index d8cd940a..49831368 100644 --- a/src/Shared/HandyControlDemo_Shared/Resources/Themes/Styles/Style.xaml +++ b/src/Shared/HandyControlDemo_Shared/Resources/Themes/Styles/Style.xaml @@ -5,6 +5,7 @@ + + + \ No newline at end of file diff --git a/src/Shared/HandyControlDemo_Shared/Resources/fabric-icons.ttf b/src/Shared/HandyControlDemo_Shared/Resources/fabric-icons.ttf new file mode 100644 index 00000000..9964e1a0 Binary files /dev/null and b/src/Shared/HandyControlDemo_Shared/Resources/fabric-icons.ttf differ diff --git a/src/Shared/HandyControlDemo_Shared/UserControl/Controls/SideMenuDemoCtl.xaml b/src/Shared/HandyControlDemo_Shared/UserControl/Controls/SideMenuDemoCtl.xaml new file mode 100644 index 00000000..b056b8ce --- /dev/null +++ b/src/Shared/HandyControlDemo_Shared/UserControl/Controls/SideMenuDemoCtl.xaml @@ -0,0 +1,155 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Shared/HandyControlDemo_Shared/UserControl/Controls/SideMenuDemoCtl.xaml.cs b/src/Shared/HandyControlDemo_Shared/UserControl/Controls/SideMenuDemoCtl.xaml.cs new file mode 100644 index 00000000..021ff249 --- /dev/null +++ b/src/Shared/HandyControlDemo_Shared/UserControl/Controls/SideMenuDemoCtl.xaml.cs @@ -0,0 +1,10 @@ +namespace HandyControlDemo.UserControl +{ + public partial class SideMenuDemoCtl + { + public SideMenuDemoCtl() + { + InitializeComponent(); + } + } +} diff --git a/src/Shared/HandyControlDemo_Shared/UserControl/Main/LeftMainContent.xaml b/src/Shared/HandyControlDemo_Shared/UserControl/Main/LeftMainContent.xaml index a6d448a2..53d8d6de 100644 --- a/src/Shared/HandyControlDemo_Shared/UserControl/Main/LeftMainContent.xaml +++ b/src/Shared/HandyControlDemo_Shared/UserControl/Main/LeftMainContent.xaml @@ -193,7 +193,7 @@ - + @@ -203,7 +203,7 @@ - + @@ -393,6 +393,11 @@ + + + + + diff --git a/src/Shared/HandyControlDemo_Shared/UserControl/Styles/CalendarDemoCtl.xaml.cs b/src/Shared/HandyControlDemo_Shared/UserControl/Styles/CalendarDemoCtl.xaml.cs index 42e98aa2..e0c14d30 100644 --- a/src/Shared/HandyControlDemo_Shared/UserControl/Styles/CalendarDemoCtl.xaml.cs +++ b/src/Shared/HandyControlDemo_Shared/UserControl/Styles/CalendarDemoCtl.xaml.cs @@ -1,5 +1,4 @@ - -namespace HandyControlDemo.UserControl +namespace HandyControlDemo.UserControl { public partial class CalendarDemoCtl { diff --git a/src/Shared/HandyControlDemo_Shared/ViewModel/Controls/SideMenuDemoViewModel.cs b/src/Shared/HandyControlDemo_Shared/ViewModel/Controls/SideMenuDemoViewModel.cs new file mode 100644 index 00000000..e8b4e32a --- /dev/null +++ b/src/Shared/HandyControlDemo_Shared/ViewModel/Controls/SideMenuDemoViewModel.cs @@ -0,0 +1,20 @@ +using System; +using GalaSoft.MvvmLight; +using HandyControl.Controls; +using HandyControl.Data; +#if netle40 +using GalaSoft.MvvmLight.Command; +#else +using GalaSoft.MvvmLight.CommandWpf; +# endif + +namespace HandyControlDemo.ViewModel +{ + public class SideMenuDemoViewModel : ViewModelBase + { + public RelayCommand> SwitchItemCmd => new Lazy>>(() => + new RelayCommand>(SwitchItem)).Value; + + private void SwitchItem(FunctionEventArgs info) => Growl.Info((info.Info as SideMenuItem)?.Header.ToString()); + } +} \ No newline at end of file diff --git a/src/Shared/HandyControlDemo_Shared/ViewModel/ViewModelLocator.cs b/src/Shared/HandyControlDemo_Shared/ViewModel/ViewModelLocator.cs index e7f59c12..c3c84631 100644 --- a/src/Shared/HandyControlDemo_Shared/ViewModel/ViewModelLocator.cs +++ b/src/Shared/HandyControlDemo_Shared/ViewModel/ViewModelLocator.cs @@ -33,6 +33,7 @@ namespace HandyControlDemo.ViewModel SimpleIoc.Default.Register(); SimpleIoc.Default.Register(); SimpleIoc.Default.Register(); + SimpleIoc.Default.Register(); } public static ViewModelLocator Instance => new Lazy(() => @@ -71,6 +72,9 @@ namespace HandyControlDemo.ViewModel public InteractiveDialogViewModel InteractiveDialog => ServiceLocator.Current.GetInstance(); public BadgeDemoViewModel BadgeDemo => ServiceLocator.Current.GetInstance(); + + public SideMenuDemoViewModel SideMenuDemo => ServiceLocator.Current.GetInstance(); + #endregion } } \ No newline at end of file diff --git a/src/Shared/HandyControl_Shared/Controls/Base/HeaderedSimpleItemsControl.cs b/src/Shared/HandyControl_Shared/Controls/Base/HeaderedSimpleItemsControl.cs new file mode 100644 index 00000000..cd5750bb --- /dev/null +++ b/src/Shared/HandyControl_Shared/Controls/Base/HeaderedSimpleItemsControl.cs @@ -0,0 +1,16 @@ +using System.Windows; + +namespace HandyControl.Controls +{ + public class HeaderedSimpleItemsControl : SimpleItemsControl + { + public static readonly DependencyProperty HeaderProperty = DependencyProperty.Register( + "Header", typeof(object), typeof(HeaderedSimpleItemsControl), new PropertyMetadata(default(object))); + + public object Header + { + get => GetValue(HeaderProperty); + set => SetValue(HeaderProperty, value); + } + } +} \ No newline at end of file diff --git a/src/Shared/HandyControl_Shared/Controls/Base/SimpleItemsControl.cs b/src/Shared/HandyControl_Shared/Controls/Base/SimpleItemsControl.cs index 0f301ffb..b347b244 100644 --- a/src/Shared/HandyControl_Shared/Controls/Base/SimpleItemsControl.cs +++ b/src/Shared/HandyControl_Shared/Controls/Base/SimpleItemsControl.cs @@ -5,6 +5,7 @@ using System.ComponentModel; using System.Windows; using System.Windows.Controls; using System.Windows.Markup; +using HandyControl.Data; namespace HandyControl.Controls { @@ -33,7 +34,14 @@ namespace HandyControl.Controls public SimpleItemsControl() { var items = new ObservableCollection(); - items.CollectionChanged += OnItemsChanged; + items.CollectionChanged += (s, e) => + { + if (e.NewItems != null && e.NewItems.Count > 0) + { + SetValue(HasItemsPropertyKey, true); + } + OnItemsChanged(s, e); + }; Items = items; } @@ -118,6 +126,14 @@ namespace HandyControl.Controls protected virtual void OnItemContainerStyleChanged(DependencyPropertyChangedEventArgs e) => Refresh(); + internal static readonly DependencyPropertyKey HasItemsPropertyKey = + DependencyProperty.RegisterReadOnly(nameof(HasItems), typeof(bool), typeof(SimpleItemsControl), + new PropertyMetadata(ValueBoxes.FalseBox)); + + public static readonly DependencyProperty HasItemsProperty = HasItemsPropertyKey.DependencyProperty; + + public bool HasItems => (bool) GetValue(HasItemsProperty); + protected virtual void Refresh() { if (ItemsHost == null) return; diff --git a/src/Shared/HandyControl_Shared/Controls/SideMenu/SideMenu.cs b/src/Shared/HandyControl_Shared/Controls/SideMenu/SideMenu.cs new file mode 100644 index 00000000..02656070 --- /dev/null +++ b/src/Shared/HandyControl_Shared/Controls/SideMenu/SideMenu.cs @@ -0,0 +1,189 @@ +using System; +using System.Linq; +using System.Windows; +using HandyControl.Data; + +namespace HandyControl.Controls +{ + public class SideMenu : HeaderedSimpleItemsControl + { + private SideMenuItem _selectedItem; + + private SideMenuItem _selectedHeader; + + private bool _isItemSelected; + + public SideMenu() + { + AddHandler(SideMenuItem.SelectedEvent, new RoutedEventHandler(SideMenuItemSelected)); + + Loaded += (s, e) => Init(); + } + + protected override void Refresh() + { + base.Refresh(); + + Init(); + } + + private void Init() + { + if (ItemsHost == null) return; + + OnExpandModeChanged(ExpandMode); + } + + private void SideMenuItemSelected(object sender, RoutedEventArgs e) + { + if (e.OriginalSource is SideMenuItem item) + { + if (item.Role == SideMenuItemRole.Item) + { + if (Equals(item, _selectedItem)) return; + + if (_selectedItem != null) + { + _selectedItem.IsSelected = false; + } + + _selectedItem = item; + _selectedItem.IsSelected = true; + RaiseEvent(new FunctionEventArgs(SelectionChangedEvent, this) + { + Info = e.OriginalSource + }); + _isItemSelected = true; + } + else + { + if (!Equals(item, _selectedHeader)) + { + if (_selectedHeader != null) + { + if (ExpandMode == ExpandMode.Freedom && item.ItemsHost.IsVisible && !_isItemSelected) + { + item.IsSelected = false; + SwitchPanelArea(item); + return; + } + + _selectedHeader.IsSelected = false; + if (ExpandMode != ExpandMode.Freedom) + { + SwitchPanelArea(_selectedHeader); + } + } + + _selectedHeader = item; + _selectedHeader.IsSelected = true; + SwitchPanelArea(_selectedHeader); + } + else if (ExpandMode == ExpandMode.Freedom && !_isItemSelected) + { + _selectedHeader.IsSelected = false; + SwitchPanelArea(_selectedHeader); + _selectedHeader = null; + } + + if (_isItemSelected) + { + _isItemSelected = false; + } + else if(_selectedHeader != null) + { + _selectedHeader.SelectDefaultItem(); + _isItemSelected = false; + } + } + } + } + + private void SwitchPanelArea(SideMenuItem oldItem) + { + switch (ExpandMode) + { + case ExpandMode.ShowAll: + return; + case ExpandMode.ShowOne: + case ExpandMode.Freedom: + case ExpandMode.Accordion: + oldItem.SwitchPanelArea(oldItem.IsSelected); + break; + } + } + + protected override DependencyObject GetContainerForItemOverride() => new SideMenuItem(); + + protected override bool IsItemItsOwnContainerOverride(object item) => item is SideMenuItem; + + public static readonly DependencyProperty ExpandModeProperty = DependencyProperty.Register( + "ExpandMode", typeof(ExpandMode), typeof(SideMenu), new PropertyMetadata(default(ExpandMode), OnExpandModeChanged)); + + private static void OnExpandModeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + var ctl = (SideMenu) d; + var v = (ExpandMode) e.NewValue; + + if (ctl.ItemsHost == null) + { + return; + } + + ctl.OnExpandModeChanged(v); + } + + private void OnExpandModeChanged(ExpandMode mode) + { + if (mode == ExpandMode.ShowAll) + { + ShowAll(); + } + else if (mode == ExpandMode.ShowOne) + { + var sideMenuItem = ItemsHost.Children.OfType().FirstOrDefault(item => item.IsSelected); + ShowSelectedOne(sideMenuItem); + } + } + + public ExpandMode ExpandMode + { + get => (ExpandMode) GetValue(ExpandModeProperty); + set => SetValue(ExpandModeProperty, value); + } + + public static readonly DependencyProperty PanelAreaLengthProperty = DependencyProperty.Register( + "PanelAreaLength", typeof(double), typeof(SideMenu), new PropertyMetadata(double.NaN)); + + public double PanelAreaLength + { + get => (double) GetValue(PanelAreaLengthProperty); + set => SetValue(PanelAreaLengthProperty, value); + } + + private void ShowAll() + { + foreach (var sideMenuItem in ItemsHost.Children.OfType()) + { + sideMenuItem.SwitchPanelArea(true); + } + } + + private void ShowSelectedOne(SideMenuItem item) + { + foreach (var sideMenuItem in ItemsHost.Children.OfType()) + { + sideMenuItem.SwitchPanelArea(Equals(sideMenuItem, item)); + } + } + + public static readonly RoutedEvent SelectionChangedEvent = EventManager.RegisterRoutedEvent( + "SelectionChanged", RoutingStrategy.Bubble, typeof(EventHandler>), typeof(SideMenu)); + + public event EventHandler> SelectionChanged + { + add => AddHandler(SelectionChangedEvent, value); + remove => RemoveHandler(SelectionChangedEvent, value); + } + } +} diff --git a/src/Shared/HandyControl_Shared/Controls/SideMenu/SideMenuItem.cs b/src/Shared/HandyControl_Shared/Controls/SideMenu/SideMenuItem.cs new file mode 100644 index 00000000..26f43578 --- /dev/null +++ b/src/Shared/HandyControl_Shared/Controls/SideMenu/SideMenuItem.cs @@ -0,0 +1,152 @@ +using System.Linq; +using System.Windows; +using System.Windows.Data; +using System.Windows.Input; +using HandyControl.Data; +using HandyControl.Tools.Extension; + +namespace HandyControl.Controls +{ + public class SideMenuItem : HeaderedSimpleItemsControl, ISelectable + { + private bool _isMouseLeftButtonDown; + + public static readonly DependencyProperty IconProperty = DependencyProperty.Register( + "Icon", typeof(object), typeof(SideMenuItem), new PropertyMetadata(default(object))); + + public object Icon + { + get => GetValue(IconProperty); + set => SetValue(IconProperty, value); + } + + public SideMenuItem() + { + SetBinding(ExpandModeProperty, new Binding(SideMenu.ExpandModeProperty.Name) + { + RelativeSource = new RelativeSource(RelativeSourceMode.FindAncestor, typeof(SideMenu), 1) + }); + } + + internal static readonly DependencyProperty ExpandModeProperty = + SideMenu.ExpandModeProperty.AddOwner(typeof(SideMenuItem), new PropertyMetadata(default(ExpandMode))); + + internal ExpandMode ExpandMode + { + get => (ExpandMode) GetValue(ExpandModeProperty); + set => SetValue(ExpandModeProperty, value); + } + + protected override void Refresh() + { + if (ItemsHost == null) return; + + ItemsHost.Children.Clear(); + foreach (var item in Items) + { + DependencyObject container; + if (IsItemItsOwnContainerOverride(item)) + { + container = item as DependencyObject; + } + else + { + container = GetContainerForItemOverride(); + PrepareContainerForItemOverride(container, item); + } + + if (container is FrameworkElement element) + { + element.Style = ItemContainerStyle; + ItemsHost.Children.Add(element); + } + } + + if (IsLoaded) + { + SwitchPanelArea(ExpandMode == ExpandMode.ShowAll || IsSelected); + } + } + + protected virtual void OnSelected(RoutedEventArgs e) => RaiseEvent(e); + + public static readonly RoutedEvent SelectedEvent = + EventManager.RegisterRoutedEvent("Selected", RoutingStrategy.Bubble, + typeof(RoutedEventHandler), typeof(SideMenuItem)); + + public event RoutedEventHandler Selected + { + add => AddHandler(SelectedEvent, value); + remove => RemoveHandler(SelectedEvent, value); + } + + public static readonly DependencyProperty IsSelectedProperty = DependencyProperty.Register( + "IsSelected", typeof(bool), typeof(SideMenuItem), new PropertyMetadata(ValueBoxes.FalseBox)); + + public bool IsSelected + { + get => (bool) GetValue(IsSelectedProperty); + set => SetValue(IsSelectedProperty, value); + } + + public static readonly DependencyProperty RoleProperty = DependencyProperty.Register( + "Role", typeof(SideMenuItemRole), typeof(SideMenuItem), new PropertyMetadata(default(SideMenuItemRole))); + + public SideMenuItemRole Role + { + get => (SideMenuItemRole) GetValue(RoleProperty); + internal set => SetValue(RoleProperty, value); + } + + protected override DependencyObject GetContainerForItemOverride() => new SideMenuItem(); + + protected override bool IsItemItsOwnContainerOverride(object item) => item is SideMenuItem; + + protected override void OnMouseLeave(MouseEventArgs e) + { + base.OnMouseLeave(e); + + _isMouseLeftButtonDown = false; + } + + protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e) + { + base.OnMouseLeftButtonDown(e); + + _isMouseLeftButtonDown = true; + } + + protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e) + { + base.OnMouseLeftButtonUp(e); + + if (_isMouseLeftButtonDown) + { + IsSelected = true; + OnSelected(new RoutedEventArgs(SelectedEvent, this)); + _isMouseLeftButtonDown = false; + } + } + + internal void SelectDefaultItem() + { + if (Role == SideMenuItemRole.Header && ItemsHost.Children.Count > 0) + { + var item = ItemsHost.Children.OfType().FirstOrDefault(); + if (item != null && !item.IsSelected) + { + item.OnSelected(new RoutedEventArgs(SelectedEvent, item)); + } + } + } + + internal void SwitchPanelArea(bool isShow) + { + if (ItemsHost == null) return; + if (Role == SideMenuItemRole.Header) + { + ItemsHost.Show(isShow); + } + } + } +} \ No newline at end of file diff --git a/src/Shared/HandyControl_Shared/Data/Enum/ExpandMode.cs b/src/Shared/HandyControl_Shared/Data/Enum/ExpandMode.cs new file mode 100644 index 00000000..128c5aaf --- /dev/null +++ b/src/Shared/HandyControl_Shared/Data/Enum/ExpandMode.cs @@ -0,0 +1,25 @@ +namespace HandyControl.Data +{ + public enum ExpandMode + { + /// + /// 最多只能显示一项,且不可折叠 + /// + ShowOne, + + /// + /// 显示所有项,且不可折叠 + /// + ShowAll, + + /// + /// 类似ShowOne,但是控件的尺寸不随项的数量而改变 + /// + Accordion, + + /// + /// 没有任何限制 + /// + Freedom + } +} diff --git a/src/Shared/HandyControl_Shared/Data/Enum/SideMenuItemRole.cs b/src/Shared/HandyControl_Shared/Data/Enum/SideMenuItemRole.cs new file mode 100644 index 00000000..75b6a1fc --- /dev/null +++ b/src/Shared/HandyControl_Shared/Data/Enum/SideMenuItemRole.cs @@ -0,0 +1,8 @@ +namespace HandyControl.Data +{ + public enum SideMenuItemRole + { + Header, + Item + } +} \ No newline at end of file diff --git a/src/Shared/HandyControl_Shared/Data/HandyControlConfig.cs b/src/Shared/HandyControl_Shared/Data/HandyControlConfig.cs new file mode 100644 index 00000000..88702c88 --- /dev/null +++ b/src/Shared/HandyControl_Shared/Data/HandyControlConfig.cs @@ -0,0 +1,9 @@ +namespace HandyControl.Data +{ + public class HandyControlConfig + { + public SystemVersionInfo SystemVersionInfo { get; set; } + + public string Lang { get; set; } + } +} \ No newline at end of file diff --git a/src/Shared/HandyControl_Shared/HandyControl_Shared.projitems b/src/Shared/HandyControl_Shared/HandyControl_Shared.projitems index d3e3f040..d2ceb0df 100644 --- a/src/Shared/HandyControl_Shared/HandyControl_Shared.projitems +++ b/src/Shared/HandyControl_Shared/HandyControl_Shared.projitems @@ -25,6 +25,7 @@ + @@ -77,6 +78,8 @@ + + @@ -109,9 +112,11 @@ + + @@ -123,6 +128,7 @@ + @@ -221,6 +227,7 @@ + @@ -439,6 +446,10 @@ Designer MSBuild:Compile + + Designer + MSBuild:Compile + Designer MSBuild:Compile @@ -639,6 +650,10 @@ Designer MSBuild:Compile + + Designer + MSBuild:Compile + Designer MSBuild:Compile diff --git a/src/Shared/HandyControl_Shared/Themes/Styles/Base/SideMenuBaseStyle.xaml b/src/Shared/HandyControl_Shared/Themes/Styles/Base/SideMenuBaseStyle.xaml new file mode 100644 index 00000000..5bdde1c6 --- /dev/null +++ b/src/Shared/HandyControl_Shared/Themes/Styles/Base/SideMenuBaseStyle.xaml @@ -0,0 +1,188 @@ + + + + + + + + + + + + + diff --git a/src/Shared/HandyControl_Shared/Themes/Styles/Calendar.xaml b/src/Shared/HandyControl_Shared/Themes/Styles/Calendar.xaml index e3525efa..d4b717bb 100644 --- a/src/Shared/HandyControl_Shared/Themes/Styles/Calendar.xaml +++ b/src/Shared/HandyControl_Shared/Themes/Styles/Calendar.xaml @@ -1,6 +1,7 @@  + xmlns:controls="clr-namespace:HandyControl.Controls" + xmlns:tools="clr-namespace:HandyControl.Tools"> @@ -232,6 +233,7 @@ + diff --git a/src/Shared/HandyControl_Shared/Themes/Styles/SideMenu.xaml b/src/Shared/HandyControl_Shared/Themes/Styles/SideMenu.xaml new file mode 100644 index 00000000..a4a7190c --- /dev/null +++ b/src/Shared/HandyControl_Shared/Themes/Styles/SideMenu.xaml @@ -0,0 +1,26 @@ + + + + + + + + + diff --git a/src/Shared/HandyControl_Shared/Themes/Styles/Style.xaml b/src/Shared/HandyControl_Shared/Themes/Styles/Style.xaml index 6f0df42e..5a971e9d 100644 --- a/src/Shared/HandyControl_Shared/Themes/Styles/Style.xaml +++ b/src/Shared/HandyControl_Shared/Themes/Styles/Style.xaml @@ -62,6 +62,7 @@ + \ No newline at end of file diff --git a/src/Shared/HandyControl_Shared/Tools/Helper/ConfigHelper.cs b/src/Shared/HandyControl_Shared/Tools/Helper/ConfigHelper.cs new file mode 100644 index 00000000..915f0869 --- /dev/null +++ b/src/Shared/HandyControl_Shared/Tools/Helper/ConfigHelper.cs @@ -0,0 +1,69 @@ +using System; +using System.ComponentModel; +using System.Globalization; +#if !netle40 +using System.Runtime.CompilerServices; +#endif +using System.Windows; +using System.Windows.Markup; +using HandyControl.Controls; +using HandyControl.Data; + +namespace HandyControl.Tools +{ + public class ConfigHelper : INotifyPropertyChanged + { + private ConfigHelper() + { + + } + + public static ConfigHelper Instance = new Lazy(() => new ConfigHelper()).Value; + + private XmlLanguage _lang = XmlLanguage.GetLanguage("zh-cn"); + + public XmlLanguage Lang + { + get => _lang; + set + { + if (!_lang.IetfLanguageTag.Equals(value.IetfLanguageTag)) + { + _lang = value; + OnPropertyChanged(nameof(Lang)); + } + } + } + + public void SetSystemVersionInfo(SystemVersionInfo info) + { + BlurWindow.SystemVersionInfo = info; + } + + public void SetLang(string lang) + { + Application.Current.Dispatcher.Thread.CurrentUICulture = new CultureInfo(lang); + Lang = XmlLanguage.GetLanguage(lang); + } + + public void SetConfig(HandyControlConfig config) + { + SetSystemVersionInfo(config.SystemVersionInfo); + SetLang(config.Lang); + } + + public event PropertyChangedEventHandler PropertyChanged; + +#if netle40 + protected virtual void OnPropertyChanged(string propertyName) + { + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + } +#else + protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) + { + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + } +#endif + } +} \ No newline at end of file