diff --git a/MultiTerm.Core/ViewModel/ShellViewModel.cs b/MultiTerm.Core/ViewModel/ShellViewModel.cs index 4c753ca..8410f8c 100644 --- a/MultiTerm.Core/ViewModel/ShellViewModel.cs +++ b/MultiTerm.Core/ViewModel/ShellViewModel.cs @@ -39,11 +39,17 @@ public partial class ShellViewModel : ObservableObject { this.sendReceiveViewModelFactory = sendReceiveViewModelFactory; // create a new terminal - this.AppendTerminal(this.sendReceiveViewModelFactory.Create()); + this.AppendConfiguredTerminal(this.sendReceiveViewModelFactory.Create()); } [RelayCommand] - private void AppendTerminal(ITerminalViewModel? newTerminal) + private void AppendTerminalWithSelectedViewType(ProtocolType protocolType) + { + Console.WriteLine($"Type = {protocolType}"); + } + + + private void AppendConfiguredTerminal(ITerminalViewModel? newTerminal) { // guard null value if(newTerminal == null) { return; } diff --git a/MultiTerm.Wpf/Controls/CommandableSubMenu.cs b/MultiTerm.Wpf/Controls/CommandableSubMenu.cs new file mode 100644 index 0000000..df97628 --- /dev/null +++ b/MultiTerm.Wpf/Controls/CommandableSubMenu.cs @@ -0,0 +1,148 @@ +using MultiTerm.Wpf.ValueConverters; +using System.Collections; +using System.Collections.Generic; +using System.ComponentModel; +using System.Globalization; +using System.Windows; +using System.Windows.Controls; +using System; + +namespace MultiTerm.Wpf.Controls; + +public class CommandableSubMenu : MenuItem +{ + #region Static Properties + private static readonly Dictionary RegisteredSubItemsAndParent = new(); + #endregion + + #region Dependency Properties + public static readonly DependencyProperty TitleProperty = + DependencyProperty.Register("Title", + typeof(string), typeof(CommandableSubMenu), + new PropertyMetadata(String.Empty, OnTitleChanged)); + + public static readonly DependencyProperty OptionsSourceProperty = + DependencyProperty.Register("OptionsSource", + typeof(IEnumerable), typeof(CommandableSubMenu), + new PropertyMetadata(null, OnOptionsSourceChanged)); + + public static readonly DependencyProperty CommandParameterTypeProperty = + DependencyProperty.Register("CommandParameterType", + typeof(Type), typeof(CommandableSubMenu), + new PropertyMetadata(null, OnCommandParameterTypePropertyChanged)); + #endregion + + #region Dotnet Properties + /// + /// .NET Property for OptionsSource. + /// + [Bindable(true)] + public IEnumerable OptionsSource + { + get { return (IEnumerable)GetValue(OptionsSourceProperty); } + set { SetValue(OptionsSourceProperty, value); } + } + + /// + /// .NET Property for Title. + /// + [Bindable(false)] + public string Title + { + get { return (string)GetValue(TitleProperty); } + set { SetValue(TitleProperty, value); } + } + + /// + /// .NET Property for CommandParameterType. + /// + [Bindable(false)] + public Type CommandParameterType + { + get { return (Type)GetValue(CommandParameterTypeProperty); } + set { SetValue(CommandParameterTypeProperty, value);} + } + #endregion + + /// + /// Title Changed Handler. + /// Disables CommandableSubMenu and sets header to title. + /// + private static void OnTitleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + // extract instance and guard null + if (d is not CommandableSubMenu csm) { return; } + + csm.Header = csm.Title; + csm.IsEnabled = true; + } + + private static void OnCommandParameterTypePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + // nothing to do + } + + /// + /// Options Source Changed Handler. + /// Builds list with options and adds them to parent ItemsControl (must be subtype of ItemsControl). + /// Registers menu Items in locally stored list. + /// Cannot handle changing OptionsSources. Internal list will build up. + /// + private static void OnOptionsSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + // extract instance and guard null + if (d is not CommandableSubMenu csm) { return; } + // extract parent instance of CSM and guard null + if (csm.Parent is not ItemsControl parent) { throw new ArgumentException($"Wrong parent type."); } + + // iterate through new OptionsSource Values and build up list of menuItems + foreach (var item in (IEnumerable)e.NewValue) + { + // create new menu item + var converter = new EnumDescriptionToMenuItemConverter(); + var newMenuItem = (MenuItem)converter.Convert(item, typeof(MenuItem), new object(), CultureInfo.CurrentCulture); + newMenuItem.IsCheckable = false; + + // assign to event handler and register in dictionary + newMenuItem.Click += OnAnyItemClicked; + RegisteredSubItemsAndParent.Add(newMenuItem, csm); + + // add to parent (which is expected to be a menu item) + parent.Items.Add(newMenuItem); + } + } + + /// + /// Event handler that handles registered menu items being clicked. + /// + /// MenuItem that was clicked + /// routed event args + private static void OnAnyItemClicked(object sender, RoutedEventArgs e) + { + // extract sender menuItem and guard null + if (sender is not MenuItem menuItem) { return; } + + // get parent csm + var parentCsm = GetParentCommandableSubMenu(menuItem); + if (parentCsm.CommandParameterType == null) + { + throw new Exception($"'OnAnyItemClicked()' Parent CommandableSubMenu has Property {nameof(CommandParameterType)} not set."); + } + + // convert back to enum type + var converter = new EnumDescriptionToMenuItemConverter(); + var enumValue = (Enum)converter.ConvertBack(menuItem, parentCsm.CommandParameterType, new object(), CultureInfo.CurrentCulture); + + // run command if not null + parentCsm.Command?.Execute(enumValue); + } + + #region Helpers + private static CommandableSubMenu GetParentCommandableSubMenu(MenuItem menuItem) + { + return RegisteredSubItemsAndParent[menuItem]; + } + + #endregion + +} diff --git a/MultiTerm.Wpf/View/ShellView.xaml b/MultiTerm.Wpf/View/ShellView.xaml index d45afb3..0ce3b5e 100644 --- a/MultiTerm.Wpf/View/ShellView.xaml +++ b/MultiTerm.Wpf/View/ShellView.xaml @@ -31,6 +31,13 @@ + + + + + @@ -81,17 +88,24 @@ - + + + + + Command="{Binding Data.AppendTerminalCommand, Source={StaticResource proxy}}" + CommandParameter="{Binding RelativeSource={RelativeSource Self}}"> - + -->