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/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/Shared/HandyControlDemo_Shared/HandyControlDemo_Shared.projitems b/src/Shared/HandyControlDemo_Shared/HandyControlDemo_Shared.projitems index e7fe4d04..c189a905 100644 --- a/src/Shared/HandyControlDemo_Shared/HandyControlDemo_Shared.projitems +++ b/src/Shared/HandyControlDemo_Shared/HandyControlDemo_Shared.projitems @@ -283,6 +283,7 @@ + diff --git a/src/Shared/HandyControlDemo_Shared/UserControl/Controls/SideMenuDemoCtl.xaml b/src/Shared/HandyControlDemo_Shared/UserControl/Controls/SideMenuDemoCtl.xaml index 3c8dbb3a..b056b8ce 100644 --- a/src/Shared/HandyControlDemo_Shared/UserControl/Controls/SideMenuDemoCtl.xaml +++ b/src/Shared/HandyControlDemo_Shared/UserControl/Controls/SideMenuDemoCtl.xaml @@ -2,11 +2,18 @@ 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:interactivity="clr-namespace:HandyControl.Interactivity;assembly=HandyControl" + xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" + xmlns:command="http://www.galasoft.ch/mvvmlight" + DataContext="{Binding SideMenuDemo,Source={StaticResource Locator}}" Background="{DynamicResource RegionBrush}"> - - + + + + + + + @@ -143,6 +150,6 @@ - + diff --git a/src/Shared/HandyControlDemo_Shared/UserControl/Main/LeftMainContent.xaml b/src/Shared/HandyControlDemo_Shared/UserControl/Main/LeftMainContent.xaml index d3b4c74d..53d8d6de 100644 --- a/src/Shared/HandyControlDemo_Shared/UserControl/Main/LeftMainContent.xaml +++ b/src/Shared/HandyControlDemo_Shared/UserControl/Main/LeftMainContent.xaml @@ -203,7 +203,7 @@ - + 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/SideMenu/SideMenu.cs b/src/Shared/HandyControl_Shared/Controls/SideMenu/SideMenu.cs index 9f5dff65..02656070 100644 --- a/src/Shared/HandyControl_Shared/Controls/SideMenu/SideMenu.cs +++ b/src/Shared/HandyControl_Shared/Controls/SideMenu/SideMenu.cs @@ -1,6 +1,7 @@ -using System.Windows; +using System; +using System.Linq; +using System.Windows; using HandyControl.Data; -using HandyControl.Data.Enum; namespace HandyControl.Controls { @@ -15,6 +16,22 @@ namespace HandyControl.Controls 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) @@ -23,6 +40,8 @@ namespace HandyControl.Controls { if (item.Role == SideMenuItemRole.Item) { + if (Equals(item, _selectedItem)) return; + if (_selectedItem != null) { _selectedItem.IsSelected = false; @@ -30,6 +49,10 @@ namespace HandyControl.Controls _selectedItem = item; _selectedItem.IsSelected = true; + RaiseEvent(new FunctionEventArgs(SelectionChangedEvent, this) + { + Info = e.OriginalSource + }); _isItemSelected = true; } else @@ -38,20 +61,36 @@ namespace HandyControl.Controls { if (_selectedHeader != null) { + if (ExpandMode == ExpandMode.Freedom && item.ItemsHost.IsVisible && !_isItemSelected) + { + item.IsSelected = false; + SwitchPanelArea(item); + return; + } + _selectedHeader.IsSelected = false; - SwitchPanelArea(_selectedHeader); + 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 + else if(_selectedHeader != null) { _selectedHeader.SelectDefaultItem(); _isItemSelected = false; @@ -67,6 +106,7 @@ namespace HandyControl.Controls case ExpandMode.ShowAll: return; case ExpandMode.ShowOne: + case ExpandMode.Freedom: case ExpandMode.Accordion: oldItem.SwitchPanelArea(oldItem.IsSelected); break; @@ -78,12 +118,72 @@ namespace HandyControl.Controls 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))); + "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 index 937b3c52..26f43578 100644 --- a/src/Shared/HandyControl_Shared/Controls/SideMenu/SideMenuItem.cs +++ b/src/Shared/HandyControl_Shared/Controls/SideMenu/SideMenuItem.cs @@ -1,5 +1,6 @@ using System.Linq; using System.Windows; +using System.Windows.Data; using System.Windows.Input; using HandyControl.Data; using HandyControl.Tools.Extension; @@ -19,6 +20,54 @@ namespace HandyControl.Controls 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 = @@ -91,11 +140,12 @@ namespace HandyControl.Controls } } - internal void SwitchPanelArea(bool close) + internal void SwitchPanelArea(bool isShow) { + if (ItemsHost == null) return; if (Role == SideMenuItemRole.Header) { - ItemsHost.Show(close); + ItemsHost.Show(isShow); } } } diff --git a/src/Shared/HandyControl_Shared/Data/Enum/ExpandMode.cs b/src/Shared/HandyControl_Shared/Data/Enum/ExpandMode.cs index ab404a40..128c5aaf 100644 --- a/src/Shared/HandyControl_Shared/Data/Enum/ExpandMode.cs +++ b/src/Shared/HandyControl_Shared/Data/Enum/ExpandMode.cs @@ -1,17 +1,17 @@ -namespace HandyControl.Data.Enum +namespace HandyControl.Data { public enum ExpandMode { - /// - /// 显示所有项,且不可折叠 - /// - ShowAll, - /// /// 最多只能显示一项,且不可折叠 /// ShowOne, + /// + /// 显示所有项,且不可折叠 + /// + ShowAll, + /// /// 类似ShowOne,但是控件的尺寸不随项的数量而改变 /// diff --git a/src/Shared/HandyControl_Shared/Themes/Styles/Base/SideMenuBaseStyle.xaml b/src/Shared/HandyControl_Shared/Themes/Styles/Base/SideMenuBaseStyle.xaml index 64ff65c6..5bdde1c6 100644 --- a/src/Shared/HandyControl_Shared/Themes/Styles/Base/SideMenuBaseStyle.xaml +++ b/src/Shared/HandyControl_Shared/Themes/Styles/Base/SideMenuBaseStyle.xaml @@ -44,6 +44,44 @@ + + + + diff --git a/src/Shared/HandyControl_Shared/Tools/Helper/ConfigHelper.cs b/src/Shared/HandyControl_Shared/Tools/Helper/ConfigHelper.cs index ed1ab456..915f0869 100644 --- a/src/Shared/HandyControl_Shared/Tools/Helper/ConfigHelper.cs +++ b/src/Shared/HandyControl_Shared/Tools/Helper/ConfigHelper.cs @@ -1,7 +1,9 @@ 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; @@ -28,7 +30,7 @@ namespace HandyControl.Tools if (!_lang.IetfLanguageTag.Equals(value.IetfLanguageTag)) { _lang = value; - OnPropertyChanged(); + OnPropertyChanged(nameof(Lang)); } } } @@ -52,9 +54,16 @@ namespace HandyControl.Tools public event PropertyChangedEventHandler PropertyChanged; - protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) +#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