diff --git a/MultiTerm.Core/Common/ProtocolType.cs b/MultiTerm.Core/Common/ProtocolType.cs new file mode 100644 index 0000000..ae241e8 --- /dev/null +++ b/MultiTerm.Core/Common/ProtocolType.cs @@ -0,0 +1,30 @@ +using System.ComponentModel; + +namespace MultiTerm.Core.Common; + +public enum ProtocolType +{ + /// + /// Serial Protocol + /// + [Description("Serial")] + Serial, + + /// + /// USB HID Protocol + /// + [Description("USB HID")] + UsbHid, + + /// + /// TCP Protocol + /// + [Description("TCP")] + Tcp, + + /// + /// UDP Protocol + /// + [Description("UCP")] + Udp +} diff --git a/MultiTerm.Core/Common/TerminalViewType.cs b/MultiTerm.Core/Common/TerminalViewType.cs new file mode 100644 index 0000000..66445d9 --- /dev/null +++ b/MultiTerm.Core/Common/TerminalViewType.cs @@ -0,0 +1,18 @@ +using System.ComponentModel; + +namespace MultiTerm.Core.Common; + +public enum TerminalViewType +{ + /// + /// SendReceive View + /// + [Description("Send/Receive")] + SendReceive, + + /// + /// Console View + /// + [Description("Console")] + Console +} diff --git a/MultiTerm.Core/ViewModel/ITerminalViewModel.cs b/MultiTerm.Core/ViewModel/ITerminalViewModel.cs index 511a5a7..52db3f6 100644 --- a/MultiTerm.Core/ViewModel/ITerminalViewModel.cs +++ b/MultiTerm.Core/ViewModel/ITerminalViewModel.cs @@ -1,4 +1,6 @@ -namespace MultiTerm.Core.ViewModel; +using MultiTerm.Core.Common; + +namespace MultiTerm.Core.ViewModel; public interface ITerminalViewModel { @@ -6,6 +8,16 @@ public interface ITerminalViewModel /// Title of the Terminal View. /// string Title { get; } + + /// + /// Type of view. + /// + TerminalViewType ViewType { get; } + + /// + /// Type of Protocol. + /// + ProtocolType ProtocolType { get; } /// /// Request Closing of Terminal. diff --git a/MultiTerm.Core/ViewModel/SendReceiveViewModel.cs b/MultiTerm.Core/ViewModel/SendReceiveViewModel.cs index 6bb8d5f..feb9da8 100644 --- a/MultiTerm.Core/ViewModel/SendReceiveViewModel.cs +++ b/MultiTerm.Core/ViewModel/SendReceiveViewModel.cs @@ -1,7 +1,15 @@ -namespace MultiTerm.Core.ViewModel; +using MultiTerm.Core.Common; + +namespace MultiTerm.Core.ViewModel; public partial class SendReceiveViewModel : TerminalViewModel { public override string Title => "SendReceive Tab"; + public override TerminalViewType ViewType => TerminalViewType.SendReceive; + + public SendReceiveViewModel() : base(ProtocolType.Serial) // TODO implement Protocol initialization + { + + } } diff --git a/MultiTerm.Core/ViewModel/ShellViewModel.cs b/MultiTerm.Core/ViewModel/ShellViewModel.cs index c6ac700..4c753ca 100644 --- a/MultiTerm.Core/ViewModel/ShellViewModel.cs +++ b/MultiTerm.Core/ViewModel/ShellViewModel.cs @@ -29,6 +29,12 @@ public partial class ShellViewModel : ObservableObject private NewlineSeparatorType defaultSendNewlineSeparator = NewlineSeparatorType.None; #endregion + #region New Terminal Context Menu + [ObservableProperty] + private TerminalViewType selectedTerminalViewType = TerminalViewType.SendReceive; + + #endregion + public ShellViewModel(IAbstractFactory sendReceiveViewModelFactory) { this.sendReceiveViewModelFactory = sendReceiveViewModelFactory; @@ -36,7 +42,8 @@ public partial class ShellViewModel : ObservableObject this.AppendTerminal(this.sendReceiveViewModelFactory.Create()); } - public void AppendTerminal(ITerminalViewModel newTerminal) + [RelayCommand] + private void AppendTerminal(ITerminalViewModel? newTerminal) { // guard null value if(newTerminal == null) { return; } @@ -50,11 +57,11 @@ public partial class ShellViewModel : ObservableObject private void Terminal_ClosingEvent(object? sender, EventArgs e) { - if(sender is not ITerminalViewModel tvm) { throw new ArgumentException(nameof(sender)); } + if(sender is not ITerminalViewModel tvm) { throw new ArgumentException($"{nameof(Terminal_ClosingEvent)} failed to convert sender to {nameof(ITerminalViewModel)}"); } this.RemoveTerminal(tvm); } - public void RemoveTerminal(ITerminalViewModel terminalToRemove) + private void RemoveTerminal(ITerminalViewModel terminalToRemove) { // guard null value if(terminalToRemove == null) { return; } @@ -73,7 +80,7 @@ public partial class ShellViewModel : ObservableObject } [RelayCommand] - public void TestButtonClicked() + private void TestButtonClicked() { this.DefaultReceiveNewlineSeparator = NewlineSeparatorType.CR_LF; } diff --git a/MultiTerm.Core/ViewModel/TerminalViewModel.cs b/MultiTerm.Core/ViewModel/TerminalViewModel.cs index 36ab34c..14a84cd 100644 --- a/MultiTerm.Core/ViewModel/TerminalViewModel.cs +++ b/MultiTerm.Core/ViewModel/TerminalViewModel.cs @@ -1,14 +1,22 @@ using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; +using MultiTerm.Core.Common; namespace MultiTerm.Core.ViewModel; public abstract partial class TerminalViewModel : ObservableObject, ITerminalViewModel { public abstract string Title { get; } + public abstract TerminalViewType ViewType { get; } + public ProtocolType ProtocolType { get; private set; } public event EventHandler? ClosingEvent; + public TerminalViewModel(ProtocolType protocolType) + { + this.ProtocolType = protocolType; + } + /// /// Method to override if any closing actions are required. /// Closing can be cancelled using the return value. diff --git a/MultiTerm.Wpf/App.xaml.cs b/MultiTerm.Wpf/App.xaml.cs index 406f307..ea899db 100644 --- a/MultiTerm.Wpf/App.xaml.cs +++ b/MultiTerm.Wpf/App.xaml.cs @@ -3,6 +3,7 @@ using Microsoft.Extensions.Hosting; using MultiTerm.Core.ViewModel; using Common.StartupHelpers; using System.Windows; +using MultiTerm.Core.Common; namespace MultiTerm.Wpf; diff --git a/MultiTerm.Wpf/Controls/SingleSelectSubMenu.cs b/MultiTerm.Wpf/Controls/SingleSelectSubMenu.cs index f9f82f4..ea08567 100644 --- a/MultiTerm.Wpf/Controls/SingleSelectSubMenu.cs +++ b/MultiTerm.Wpf/Controls/SingleSelectSubMenu.cs @@ -105,7 +105,7 @@ public class SingleSelectSubMenu : MenuItem /// /// Options Source Changed Handler. - /// Builds list with options and adds them to parent MenuItem (must be Menu Item!). + /// 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. /// @@ -114,7 +114,7 @@ public class SingleSelectSubMenu : MenuItem // extract instance and guard null if (d is not SingleSelectSubMenu sssm) { return; } // extract parent instance of SSSM and guard null - if (sssm.Parent is not MenuItem parent) { return; } + if (sssm.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) @@ -123,6 +123,7 @@ public class SingleSelectSubMenu : MenuItem var converter = new EnumDescriptionToMenuItemConverter(); var newMenuItem = (MenuItem)converter.Convert(item, typeof(MenuItem), new object(), CultureInfo.CurrentCulture); newMenuItem.IsCheckable = true; + newMenuItem.StaysOpenOnClick = true; // assign to event handler and register in dictionary newMenuItem.Checked += OnAnyItemChecked; diff --git a/MultiTerm.Wpf/Helpers/BindingProxy.cs b/MultiTerm.Wpf/Helpers/BindingProxy.cs new file mode 100644 index 0000000..f04196b --- /dev/null +++ b/MultiTerm.Wpf/Helpers/BindingProxy.cs @@ -0,0 +1,27 @@ +using System.Windows; + +namespace MultiTerm.Wpf.Helpers; + +/// +/// Serves as a Proxy to provide DataContext for Elements that are not part of the VisualTree. +/// From: https://thomaslevesque.com/2011/03/21/wpf-how-to-bind-to-data-when-the-datacontext-is-not-inherited/ +/// +public class BindingProxy : Freezable +{ + #region Overrides of Freezable + protected override Freezable CreateInstanceCore() + { + return new BindingProxy(); + } + #endregion + + public object Data + { + get { return (object)GetValue(DataProperty); } + set { SetValue(DataProperty, value); } + } + + // Using a DependencyProperty as the backing store for Data. This enables animation, styling, binding, etc... + public static readonly DependencyProperty DataProperty = + DependencyProperty.Register("Data", typeof(object), typeof(BindingProxy), new UIPropertyMetadata(null)); +} diff --git a/MultiTerm.Wpf/View/ShellView.xaml b/MultiTerm.Wpf/View/ShellView.xaml index dbe05a6..d45afb3 100644 --- a/MultiTerm.Wpf/View/ShellView.xaml +++ b/MultiTerm.Wpf/View/ShellView.xaml @@ -9,6 +9,7 @@ xmlns:vm="clr-namespace:MultiTerm.Core.ViewModel;assembly=MultiTerm.Core" xmlns:v="clr-namespace:MultiTerm.Wpf.View" xmlns:core_common="clr-namespace:MultiTerm.Core.Common;assembly=MultiTerm.Core" + xmlns:helpers="clr-namespace:MultiTerm.Wpf.Helpers" mc:Ignorable="d" d:DesignHeight="600" d:DesignWidth="1200"> @@ -23,6 +24,13 @@ + + + + + @@ -51,14 +59,68 @@ + SelectedMenuItem="{Binding DefaultSendNewlineSeparator, Mode=TwoWay, Converter={StaticResource EnumDescriptionConverter}}"> + +