worked on settings for NewlineSeparator in menubar,

updating binded datasource does not yet work
master
Jonas Arnold 3 years ago
parent c3a965875f
commit 07a86117e1
  1. 30
      MultiTerm.Core/Common/NewlineSeparatorType.cs
  2. 26
      MultiTerm.Core/ViewModel/ShellViewModel.cs
  3. 106
      MultiTerm.Wpf/Controls/MenuItemExtensions.cs
  4. 124
      MultiTerm.Wpf/Controls/SingleSelectSubMenu.cs
  5. 4
      MultiTerm.Wpf/MainWindow.xaml
  6. 60
      MultiTerm.Wpf/ValueConverters/EnumDescriptionConverter.cs
  7. 67
      MultiTerm.Wpf/View/ShellView.xaml
  8. 21
      MultiTerm.Wpf/View/ShellView.xaml.cs

@ -0,0 +1,30 @@
using System.ComponentModel;
namespace MultiTerm.Core.Common;
public enum NewlineSeparatorType
{
/// <summary>
/// No newline separator.
/// </summary>
[Description("None")]
None,
/// <summary>
/// Carriage return newline separator.
/// </summary>
[Description("CR")]
CR,
/// <summary>
/// Linefeed newline separator.
/// </summary>
[Description("LF")]
LF,
/// <summary>
/// Carriage return and linefeed as newline separator.
/// </summary>
[Description("CR+LF")]
CR_LF
}

@ -1,6 +1,9 @@
using Common.StartupHelpers; using Common.StartupHelpers;
using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using MultiTerm.Core.Common;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using System.Runtime.CompilerServices;
namespace MultiTerm.Core.ViewModel; namespace MultiTerm.Core.ViewModel;
@ -17,6 +20,21 @@ public partial class ShellViewModel : ObservableObject
[ObservableProperty] [ObservableProperty]
private ITerminalViewModel? selectedTerminalViewModel; private ITerminalViewModel? selectedTerminalViewModel;
#region Settings Menu Bar
public IEnumerable<NewlineSeparatorType> NewlineSeparatorTypeValues
{
get { return Enum.GetValues(typeof(NewlineSeparatorType)).Cast<NewlineSeparatorType>(); }
}
// TODO Initialize from File
[ObservableProperty]
private NewlineSeparatorType selectedReceiveNewlineSeparator = NewlineSeparatorType.None;
// TODO Initialize from File
[ObservableProperty]
private NewlineSeparatorType selectedSendNewlineSeparator = NewlineSeparatorType.None;
#endregion
public ShellViewModel(IAbstractFactory<SendReceiveViewModel> sendReceiveViewModelFactory) public ShellViewModel(IAbstractFactory<SendReceiveViewModel> sendReceiveViewModelFactory)
{ {
this.sendReceiveViewModelFactory = sendReceiveViewModelFactory; this.sendReceiveViewModelFactory = sendReceiveViewModelFactory;
@ -34,5 +52,11 @@ public partial class ShellViewModel : ObservableObject
// add to collection and set as selected // add to collection and set as selected
this.TerminalViewModels.Add(newTerminal); this.TerminalViewModels.Add(newTerminal);
this.SelectedTerminalViewModel = newTerminal; this.SelectedTerminalViewModel = newTerminal;
} }
partial void OnSelectedReceiveNewlineSeparatorChanged(NewlineSeparatorType value)
{
Console.WriteLine($"Changed to {value}");
}
} }

@ -0,0 +1,106 @@
using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
namespace MultiTerm.Wpf.Controls
{
/// <summary>
/// TODO ueberarbeiten
/// FROM:
/// https://stackoverflow.com/questions/3652688/mutually-exclusive-checkable-menu-items/11497189#11497189
/// </summary>
public class MenuItemExtensions : MenuItem
{
private static MenuItem? previouslySelectedMenuItem = null;
public static Dictionary<MenuItem, String> ElementToGroupNames = new Dictionary<MenuItem, String>();
public static readonly DependencyProperty GroupNameProperty =
DependencyProperty.RegisterAttached("GroupName",
typeof(String),
typeof(MenuItemExtensions),
new PropertyMetadata(String.Empty, OnGroupNameChanged));
public static readonly RoutedEvent IsCheckedChangedEvent =
EventManager.RegisterRoutedEvent("IsCheckedChanged",
RoutingStrategy.Bubble, typeof(RoutedEventArgs),
typeof(MenuItemExtensions));
public event RoutedEventHandler IsCheckedChanged
{
add { this.AddHandler(IsCheckedChangedEvent, value); }
remove { this.RemoveHandler(IsCheckedChangedEvent, value); }
}
public static void SetGroupName(MenuItem element, String value)
{
element.SetValue(GroupNameProperty, value);
}
public static String GetGroupName(MenuItem element)
{
return element.GetValue(GroupNameProperty).ToString();
}
private static void OnGroupNameChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
//Add an entry to the group name collection
var menuItem = d as MenuItem;
var parent = menuItem.Parent as MenuItem;
if (menuItem != null)
{
String newGroupName = e.NewValue.ToString();
String oldGroupName = e.OldValue.ToString();
if (String.IsNullOrEmpty(newGroupName))
{
//Removing the toggle button from grouping
RemoveCheckboxFromGrouping(menuItem);
}
else
{
//Switching to a new group
if (newGroupName != oldGroupName)
{
if (!String.IsNullOrEmpty(oldGroupName))
{
//Remove the old group mapping
RemoveCheckboxFromGrouping(menuItem);
}
ElementToGroupNames.Add(menuItem, e.NewValue.ToString());
menuItem.IsCheckable = true;
menuItem.Checked += MenuItemChecked;
}
}
}
}
private static void RemoveCheckboxFromGrouping(MenuItem checkBox)
{
ElementToGroupNames.Remove(checkBox);
checkBox.Checked -= MenuItemChecked;
}
static void MenuItemChecked(object sender, RoutedEventArgs e)
{
var menuItem = e.OriginalSource as MenuItem;
foreach (var item in ElementToGroupNames)
{
// uncheck all other menu items in group
if (item.Key != menuItem && item.Value == GetGroupName(menuItem))
{
item.Key.IsChecked = false;
}
}
// raise routed event
var menuItemExtensions = menuItem as MenuItemExtensions;
if(previouslySelectedMenuItem != null && previouslySelectedMenuItem != menuItem)
{
RoutedEventArgs args = new RoutedEventArgs(IsCheckedChangedEvent);
menuItemExtensions.RaiseEvent(args);
}
previouslySelectedMenuItem = menuItem;
}
}
}

@ -0,0 +1,124 @@
using MultiTerm.Wpf.ValueConverters;
using System.Linq;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Globalization;
using System.Runtime.CompilerServices;
using System.Windows;
using System.Windows.Controls;
using System;
using System.Printing;
namespace MultiTerm.Wpf.Controls;
public class SingleSelectSubMenu : MenuItem
{
public static Dictionary<MenuItem, SingleSelectSubMenu> RegisteredSubItemsAndParent = new Dictionary<MenuItem, SingleSelectSubMenu>();
public static readonly DependencyProperty OptionsSourceProperty =
DependencyProperty.Register("OptionsSource",
typeof(IEnumerable),
typeof(SingleSelectSubMenu),
new PropertyMetadata(null, OnOptionsSourceChanged));
public static readonly DependencyProperty SelectedMenuItemProperty =
DependencyProperty.Register("SelectedMenuItem",
typeof(object),
typeof(SingleSelectSubMenu),
new PropertyMetadata(null, OnSelectedMenuItemPropertyChanged));
private static void OnSelectedMenuItemPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var sssm = d as SingleSelectSubMenu;
if (sssm != null)
{
if(e.NewValue != null)
{
// get menu item with same name from registered items
MenuItem selectedMenuItem = null;
foreach (var item in RegisteredSubItemsAndParent)
{
if(String.Compare(item.Key.Header.ToString(), e.NewValue.ToString(), true) == 0)
{
selectedMenuItem = item.Key;
break;
}
}
// var selectedMenuItem = RegisteredSubItemsAndParent.Where(x => x.Key.Header == e.NewValue).FirstOrDefault();
if(selectedMenuItem != null)
{
selectedMenuItem.IsChecked = true;
//OnAnyItemChecked(selectedMenuItem, new RoutedEventArgs());
}
}
}
}
private static void OnOptionsSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var sssm = d as SingleSelectSubMenu;
if(sssm != null)
{
if(e.NewValue != null)
{
var parent = sssm.Parent as MenuItem;
if(parent != null)
{
foreach (var item in (IEnumerable)e.NewValue)
{
var converter = new EnumDescriptionConverter();
var newItem = new MenuItem()
{
Header = converter.Convert(item, typeof(object), null, CultureInfo.CurrentCulture),
IsCheckable = true
};
newItem.Checked += OnAnyItemChecked;
RegisteredSubItemsAndParent.Add(newItem, sssm);
parent.Items.Add(newItem);
Debug.WriteLine(item);
}
}
}
}
}
private static void OnAnyItemChecked(object sender, RoutedEventArgs e)
{
var menuItem = sender as MenuItem;
if(menuItem != null)
{
Debug.WriteLine($"menuitem checked: {menuItem}");
// uncheck others
foreach (var item in RegisteredSubItemsAndParent)
{
if (item.Key != null && item.Key != menuItem)
{
item.Key.IsChecked = false;
}
}
// set menu item for respective parent
RegisteredSubItemsAndParent[menuItem].SelectedMenuItem = menuItem;
}
}
[Bindable(true)]
public IEnumerable OptionsSource
{
get { return(IEnumerable)GetValue(OptionsSourceProperty); }
set { SetValue(OptionsSourceProperty, value); }
}
[Bindable(true)]
public object SelectedMenuItem
{
get { return GetValue(SelectedMenuItemProperty); }
set { SetValue (SelectedMenuItemProperty, value); }
}
}

@ -7,6 +7,8 @@
xmlns:vm="clr-namespace:MultiTerm.Core.ViewModel;assembly=MultiTerm.Core" xmlns:vm="clr-namespace:MultiTerm.Core.ViewModel;assembly=MultiTerm.Core"
xmlns:v="clr-namespace:MultiTerm.Wpf.View" xmlns:v="clr-namespace:MultiTerm.Wpf.View"
mc:Ignorable="d" mc:Ignorable="d"
Title="MultiTerm" Height="450" Width="800"> Height="900" Width="1600"
MinHeight="900" MinWidth="1600"
Title="MultiTerm">
<v:ShellView/> <v:ShellView/>
</Window> </Window>

@ -0,0 +1,60 @@
using System;
using System.ComponentModel;
using System.Globalization;
using System.Reflection;
using System.Windows.Data;
namespace MultiTerm.Wpf.ValueConverters;
public class EnumDescriptionConverter : IValueConverter
{
private string GetEnumDescription(Enum enumObject)
{
FieldInfo fieldInfo = enumObject.GetType().GetField(enumObject.ToString());
object[] attributeArray = fieldInfo.GetCustomAttributes(false);
if(attributeArray.Length == 0)
{
return enumObject.ToString();
}
else
{
DescriptionAttribute attribute = attributeArray[0] as DescriptionAttribute;
return attribute.Description;
}
}
/// <summary>
/// Convert from Data Source to Dependency Object type.
/// Here => Enum type to object.
/// </summary>
/// <param name="value"></param>
/// <param name="targetType"></param>
/// <param name="parameter"></param>
/// <param name="culture"></param>
/// <returns></returns>
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
Enum myEnum = (Enum)value;
string description = this.GetEnumDescription(myEnum);
return description;
}
/// <summary>
/// Convert from Dependency Object type to Data Source type.
/// Here => object to Enum type.
/// </summary>
/// <param name="value"></param>
/// <param name="targetType"></param>
/// <param name="parameter"></param>
/// <param name="culture"></param>
/// <returns></returns>
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
int returnValue = 0;
if (parameter is Type)
{
returnValue = (int)Enum.Parse((Type)parameter, value.ToString());
}
return returnValue;
}
}

@ -3,17 +3,74 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:MultiTerm.Wpf.View" xmlns:sys="clr-namespace:System;assembly=System.Core"
xmlns:conv="clr-namespace:MultiTerm.Wpf.ValueConverters"
xmlns:controls="clr-namespace:MultiTerm.Wpf.Controls"
xmlns:vm="clr-namespace:MultiTerm.Core.ViewModel;assembly=MultiTerm.Core" xmlns:vm="clr-namespace:MultiTerm.Core.ViewModel;assembly=MultiTerm.Core"
xmlns:v="clr-namespace:MultiTerm.Wpf.View" xmlns:v="clr-namespace:MultiTerm.Wpf.View"
xmlns:core_common="clr-namespace:MultiTerm.Core.Common;assembly=MultiTerm.Core"
mc:Ignorable="d" mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800"> d:DesignHeight="600" d:DesignWidth="1200">
<Grid> <UserControl.Resources>
<!-- Value Converters -->
<conv:EnumDescriptionConverter x:Key="EnumDescriptionConverter"/>
</UserControl.Resources>
<DockPanel>
<Menu DockPanel.Dock="Top">
<MenuItem Header="_File"/>
<MenuItem Header="_Edit">
<MenuItem Header="_Copy" InputGestureText="Ctrl + C">
<!-- <MenuItem.Icon> // TODO
<Image Width="16" Height="16" Source="copy.png"/>
</MenuItem.Icon>-->
</MenuItem>
<MenuItem Header="_Paste" InputGestureText="Ctrl + P">
<!-- <MenuItem.Icon> // TODO
<Image Width="16" Height="16" Source="paste.png"/>
</MenuItem.Icon>-->
</MenuItem>
</MenuItem>
<MenuItem Header="Test">
<MenuItem Header="Item1">
<controls:MenuItemExtensions.GroupName>test</controls:MenuItemExtensions.GroupName>
<MenuItem.IsCheckable>true</MenuItem.IsCheckable>
</MenuItem>
<MenuItem controls:MenuItemExtensions.GroupName="test" Header="Item2" IsCheckable="true"/>
</MenuItem>
<MenuItem Header="_Settings">
<controls:SingleSelectSubMenu Header="Newline Separator (Receive) TEST"
OptionsSource="{Binding NewlineSeparatorTypeValues}"
SelectedMenuItem="{Binding Path=SelectedReceiveNewlineSeparator, Converter={StaticResource EnumDescriptionConverter}}">
</controls:SingleSelectSubMenu>
<!--<MenuItem Header="Newline Separator (Receive)"
ItemsSource="{Binding NewlineSeparatorTypeValues}">
--><!--<controls:RadioButtonMenuItem.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Converter={StaticResource EnumDescriptionConverter}}"/>
</DataTemplate>
</controls:RadioButtonMenuItem.ItemTemplate>--><!--
<MenuItem.ItemContainerStyle>
<Style TargetType="{x:Type MenuItem}">
<Setter Property="IsCheckable" Value="True"/>
<Setter Property=""
--><!--<Setter Property="GroupName" Value="receive"/>--><!--
<Setter Property="Header" Value="{Binding Converter={StaticResource EnumDescriptionConverter}}"/>
</Style>
</MenuItem.ItemContainerStyle>
</MenuItem>-->
<MenuItem Header="Newline Separator On Send" x:Name="newlineSendMenuItem"/>
</MenuItem>
<MenuItem Header="_View"/>
<MenuItem Header="_About"/>
</Menu>
<TabControl <TabControl
x:Name="terminalTabControl" x:Name="terminalTabControl"
ItemsSource="{Binding TerminalViewModels}" ItemsSource="{Binding TerminalViewModels}"
SelectedItem="{Binding SelectedTerminalViewModel}"> SelectedItem="{Binding SelectedTerminalViewModel}">
<TabControl.Resources> <TabControl.Resources>
<DataTemplate DataType="{x:Type vm:SendReceiveViewModel}"> <DataTemplate DataType="{x:Type vm:SendReceiveViewModel}">
<v:SendReceiveView/> <v:SendReceiveView/>
@ -27,5 +84,5 @@
</TabControl.ItemContainerStyle> </TabControl.ItemContainerStyle>
</TabControl> </TabControl>
</Grid> </DockPanel>
</UserControl> </UserControl>

@ -1,4 +1,7 @@
using MultiTerm.Core.ViewModel; using MultiTerm.Core.Common;
using MultiTerm.Core.ViewModel;
using System;
using System.Linq;
using System.Windows.Controls; using System.Windows.Controls;
namespace MultiTerm.Wpf.View; namespace MultiTerm.Wpf.View;
@ -9,5 +12,21 @@ public partial class ShellView : UserControl
{ {
InitializeComponent(); InitializeComponent();
this.DataContext = App.AppHost!.Services.GetService(typeof(ShellViewModel)); this.DataContext = App.AppHost!.Services.GetService(typeof(ShellViewModel));
this.PopulateSettingsNewlineSelectors();
}
private void PopulateSettingsNewlineSelectors()
{
//var types = Enum.GetValues(typeof(NewlineSeparatorType)).Cast<NewlineSeparatorType>();
//foreach (var newlineSeparatorType in types)
//{
// this.newlineReceiveMenuItem.Items.Add(new MenuItem() { Header = newlineSeparatorType });
// this.newlineSendMenuItem.Items.Add(new MenuItem() { Header = newlineSeparatorType });
//}
}
private void MenuItem_IsCheckedChanged(object sender, System.Windows.RoutedEventArgs e)
{
Console.WriteLine("changed");
} }
} }

Loading…
Cancel
Save