added check if SettingsViewModel implements IProtocolSettings in CommunicationProtocolFactory,

implemented COM Port readout,
fixed functionality of AreEditable for the ProtocolSettingsViewModel,
implemented EnumValueToDescriptionConverter using Humanizer package,
implemented IntToStringConverter,
implemented SerialSettingsView
master
Jonas Arnold 3 years ago
parent 641e72b1bd
commit c8c53221d3
  1. 13
      MultiTerm.Protocols/Factories/CommunicationProtocolFactory.cs
  2. 5
      MultiTerm.Protocols/IProtocolSettingsViewModel.cs
  3. 10
      MultiTerm.Protocols/ProtocolSettingsViewModel.cs
  4. 20
      MultiTerm.Protocols/Serial/SerialProtocolSettingsViewModel.cs
  5. 1
      MultiTerm.Wpf/MultiTerm.Wpf.csproj
  6. 55
      MultiTerm.Wpf/ValueConverters/EnumValueToEnumDescriptionConverter.cs
  7. 22
      MultiTerm.Wpf/ValueConverters/IntToStringConverter.cs
  8. 2
      MultiTerm.Wpf/View/SendReceiveView.xaml
  9. 66
      MultiTerm.Wpf/View/SettingsView/SerialSettingsView.xaml
  10. 29
      MultiTerm.Wpf/View/SettingsView/SerialSettingsView.xaml.cs

@ -44,7 +44,8 @@ public class CommunicationProtocolFactory : ICommunicationProtocolFactory
} }
catch (Exception ex) catch (Exception ex)
{ {
throw new NotImplementedException($"'{nameof(CommunicationProtocolFactory)}' cannot create CommunicationProtocol with {nameof(ProtocolType)} {protocolType}", ex); throw new NotImplementedException($"'{nameof(CommunicationProtocolFactory)}' cannot create " +
$"CommunicationProtocol with {nameof(ProtocolType)} {protocolType}", ex);
} }
// search for correct type of settings View Model implementation by ProtocolType // search for correct type of settings View Model implementation by ProtocolType
@ -54,7 +55,15 @@ public class CommunicationProtocolFactory : ICommunicationProtocolFactory
} }
catch (Exception ex) catch (Exception ex)
{ {
throw new NotImplementedException($"'{nameof(CommunicationProtocolFactory)}' cannot create ProtocolSettingsViewModel with {nameof(ProtocolType)} {protocolType}", ex); throw new NotImplementedException($"'{nameof(CommunicationProtocolFactory)}' cannot create " +
$"ProtocolSettingsViewModel with {nameof(ProtocolType)} {protocolType}", ex);
}
// check if settings viewmodel also implements IProtocolSettings, which it must
if(settingsViewModel is not IProtocolSettings)
{
throw new NotImplementedException($"'{nameof(CommunicationProtocolFactory)}' cannot create " +
$"CommunicationProtocol since {settingsViewModel.GetType()} does not implement {nameof(IProtocolSettings)}.");
} }
// return the filled up instances // return the filled up instances

@ -9,6 +9,11 @@ public interface IProtocolSettingsViewModel
/// </summary> /// </summary>
ProtocolType ProtocolType { get; } ProtocolType ProtocolType { get; }
/// <summary>
/// Indicates wether the settings can currently be edited.
/// </summary>
bool AreEditable { get; }
/// <summary> /// <summary>
/// Event that is thrown when the user requested to connect to the device with the entered settings. /// Event that is thrown when the user requested to connect to the device with the entered settings.
/// Provides protocol settings to use for connection. /// Provides protocol settings to use for connection.

@ -21,15 +21,13 @@ public abstract partial class ProtocolSettingsViewModel : ObservableObject, IPro
public abstract ProtocolType ProtocolType { get; } public abstract ProtocolType ProtocolType { get; }
/// <summary>
/// Indicates wether the settings can currently be edited.
/// Initially are editable
/// </summary>
public bool AreEditable = true;
[ObservableProperty] [ObservableProperty]
private string connectDisconnectButtonText = disconnectedStateButtonText; private string connectDisconnectButtonText = disconnectedStateButtonText;
[ObservableProperty]
private bool areEditable = true; // initially editable
public ProtocolSettingsViewModel(IMessenger messenger) public ProtocolSettingsViewModel(IMessenger messenger)
{ {
this.messenger = messenger; this.messenger = messenger;

@ -1,5 +1,6 @@
using Common.Messaging; using Common.Messaging;
using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using CommunityToolkit.Mvvm.Messaging; using CommunityToolkit.Mvvm.Messaging;
using MultiTerm.Protocols.Types; using MultiTerm.Protocols.Types;
@ -13,7 +14,7 @@ public partial class SerialProtocolSettingsViewModel : ProtocolSettingsViewModel
private int baudRate = 115200; private int baudRate = 115200;
[ObservableProperty] [ObservableProperty]
private string portName = ""; private string portName;
[ObservableProperty] [ObservableProperty]
private Parity parity = Parity.None; private Parity parity = Parity.None;
@ -27,6 +28,14 @@ public partial class SerialProtocolSettingsViewModel : ProtocolSettingsViewModel
[ObservableProperty] [ObservableProperty]
private Handshake handshake = Handshake.None; private Handshake handshake = Handshake.None;
[ObservableProperty]
private IEnumerable<string> comPorts = new string[] { };
[RelayCommand]
private void ReloadComPorts()
{
this.ComPorts = SerialProtocol.GetPortNames();
}
// TODO // TODO
public string NewlineSequenceOnSend => throw new NotImplementedException(); public string NewlineSequenceOnSend => throw new NotImplementedException();
@ -34,7 +43,12 @@ public partial class SerialProtocolSettingsViewModel : ProtocolSettingsViewModel
public string NewlineOnReceivedSequence => throw new NotImplementedException(); public string NewlineOnReceivedSequence => throw new NotImplementedException();
public SerialProtocolSettingsViewModel(IMessenger messenger) : base(messenger) { } public SerialProtocolSettingsViewModel(IMessenger messenger) : base(messenger)
{
// load com ports initially
this.ReloadComPorts();
this.portName = this.ComPorts.FirstOrDefault(string.Empty);
}
public bool AreValid() public bool AreValid()
{ {
@ -48,7 +62,7 @@ public partial class SerialProtocolSettingsViewModel : ProtocolSettingsViewModel
this.messenger.Send<IUserInterfaceMessage>(new ProtocolSettingsInvalidMessage(nameof(this.PortName), "Must start with COM")); this.messenger.Send<IUserInterfaceMessage>(new ProtocolSettingsInvalidMessage(nameof(this.PortName), "Must start with COM"));
return false; return false;
} }
if (this.DataBits < 5 && this.DataBits > 8 && this.DataBits != 16) if ((this.DataBits < 5 || this.DataBits > 8) && this.DataBits != 16)
{ {
this.messenger.Send<IUserInterfaceMessage>(new ProtocolSettingsInvalidMessage(nameof(this.DataBits), "Must be 5...8 or 16")); this.messenger.Send<IUserInterfaceMessage>(new ProtocolSettingsInvalidMessage(nameof(this.DataBits), "Must be 5...8 or 16"));
return false; return false;

@ -8,6 +8,7 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Humanizer.Core" Version="2.14.1" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="7.0.0" /> <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="7.0.1" /> <PackageReference Include="Microsoft.Extensions.Hosting" Version="7.0.1" />
</ItemGroup> </ItemGroup>

@ -0,0 +1,55 @@
using Humanizer;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.Windows.Data;
namespace MultiTerm.Wpf.ValueConverters;
/// <summary>
/// Can convert an enum value to a human readable string. Therefore it uses the Description attribute if set.
/// </summary>
[ValueConversion(typeof(Enum), typeof(Enum))]
public class EnumValueToEnumDescriptionConverter : IValueConverter
{
/// <summary>
/// Converts complete enum to <see cref="IEnumerable"/> of <see cref="string"/>.
/// Also converts single enum values to <see cref="string"/>.
/// </summary>
/// <returns>description or humanized string of the enum value</returns>
/// <exception cref="NotImplementedException">if <paramref name="value"/> is another type than an <see cref="IEnumerable"/> or <see cref="Enum"/></exception>
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if(value is IEnumerable arrayOfEnumValues)
{
List<string> outputValues = new();
foreach (var item in arrayOfEnumValues)
{
outputValues.Add(((Enum)item).Humanize());
}
return outputValues;
}
else if(value is Enum)
{
return ((Enum)value).Humanize();
}
else
{
throw new NotImplementedException();
}
}
/// <summary>
/// Converts single string values to Enum of <paramref name="targetType"/>.
/// </summary>
/// <returns>enum value</returns>
/// <exception cref="ArgumentException">if value is not a string</exception>
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
// guard that it is a string, cannot be a collection
if (value is not string stringValue) { throw new ArgumentException("Can only convert string values."); }
return stringValue.DehumanizeTo(targetType);
}
}

@ -0,0 +1,22 @@
using System;
using System.Globalization;
using System.Windows.Data;
namespace MultiTerm.Wpf.ValueConverters;
public class IntToStringConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
// guard type
if(value is not int integerVal) { throw new ArgumentException("Can only convert from integer value"); }
return integerVal.ToString();
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
// guard type
if (value is not string stringVal) { throw new ArgumentException("Can only convert from string value"); }
return int.Parse(stringVal);
}
}

@ -20,7 +20,7 @@
<!-- Settings View Model --> <!-- Settings View Model -->
<GroupBox Header="Protocol Settings" Grid.Row="0" Grid.Column="0"> <GroupBox Header="Protocol Settings" Grid.Row="0" Grid.Column="0">
<!-- Register additional Settings ViewModels here --> <!-- Register additional Settings ViewModels here -->
<ContentControl Content="{Binding ProtocolSettings}" IsEnabled="{Binding AreEnabled}"> <ContentControl Content="{Binding ProtocolSettings}">
<ContentControl.Resources> <ContentControl.Resources>
<DataTemplate DataType="{x:Type protocol_serial:SerialProtocolSettingsViewModel}"> <DataTemplate DataType="{x:Type protocol_serial:SerialProtocolSettingsViewModel}">
<settings_view:SerialSettingsView/> <settings_view:SerialSettingsView/>

@ -3,10 +3,70 @@
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:sys="clr-namespace:System;assembly=mscorlib"
xmlns:local="clr-namespace:MultiTerm.Wpf.View.SettingsView" xmlns:local="clr-namespace:MultiTerm.Wpf.View.SettingsView"
xmlns:conv="clr-namespace:MultiTerm.Wpf.ValueConverters"
xmlns:serial_protocol="clr-namespace:MultiTerm.Protocols.Serial;assembly=MultiTerm.Protocols"
mc:Ignorable="d" mc:Ignorable="d"
d:DesignHeight="50" d:DesignWidth="800"> d:DesignHeight="50" d:DesignWidth="800">
<StackPanel Orientation="Horizontal"> <DockPanel>
<Button Command="{Binding ConnectDisconnectCommand}" Content="{Binding ConnectDisconnectButtonText}" Width="80"></Button> <Button DockPanel.Dock="Left" Command="{Binding ConnectDisconnectCommand}" Content="{Binding ConnectDisconnectButtonText}" Width="80"/>
</StackPanel>
<StackPanel Orientation="Horizontal" IsEnabled="{Binding AreEditable}">
<StackPanel.Resources>
<!-- Converter -->
<conv:EnumValueToEnumDescriptionConverter x:Key="EnumValToDescConverter"/>
<conv:IntToStringConverter x:Key="IntToStringConverter"/>
<!-- Data Sources -->
<ObjectDataProvider x:Key="ParityValues"
ObjectType="{x:Type sys:Enum}"
MethodName="GetValues">
<ObjectDataProvider.MethodParameters>
<x:Type TypeName="serial_protocol:Parity" />
</ObjectDataProvider.MethodParameters>
</ObjectDataProvider>
<ObjectDataProvider x:Key="StopBitsValues"
ObjectType="{x:Type sys:Enum}"
MethodName="GetValues">
<ObjectDataProvider.MethodParameters>
<x:Type TypeName="serial_protocol:StopBits" />
</ObjectDataProvider.MethodParameters>
</ObjectDataProvider>
<ObjectDataProvider x:Key="HandshakeValues"
ObjectType="{x:Type sys:Enum}"
MethodName="GetValues">
<ObjectDataProvider.MethodParameters>
<x:Type TypeName="serial_protocol:Handshake" />
</ObjectDataProvider.MethodParameters>
</ObjectDataProvider>
</StackPanel.Resources>
<Label Margin="10 0" VerticalAlignment="Center">Port: </Label>
<ComboBox Width="75" ItemsSource="{Binding Path=ComPorts}" SelectedItem="{Binding Path=PortName}"/>
<Button Margin="5 0" Content="R" Command="{Binding ReloadComPortsCommand}" Width="25"/>
<Label Margin="20 0 10 0" VerticalAlignment="Center">Baud Rate:</Label>
<TextBox Width="100" Text="{Binding Path=BaudRate, Converter={StaticResource IntToStringConverter}, Mode=TwoWay}" />
<Label Margin="10 0 10 0" VerticalAlignment="Center">Data Bits:</Label>
<TextBox Width="40" Text="{Binding Path=DataBits, Converter={StaticResource IntToStringConverter}, Mode=TwoWay}" />
<Label Margin="10 0 10 0" VerticalAlignment="Center">Parity:</Label>
<ComboBox Width="60"
ItemsSource="{Binding Source={StaticResource ParityValues}, Converter={StaticResource EnumValToDescConverter}}"
SelectedItem="{Binding Path=Parity, Converter={StaticResource EnumValToDescConverter}, Mode=TwoWay}"/>
<Label Margin="10 0 10 0" VerticalAlignment="Center">Stop Bits:</Label>
<ComboBox Width="50"
ItemsSource="{Binding Source={StaticResource StopBitsValues}, Converter={StaticResource EnumValToDescConverter}}"
SelectedItem="{Binding Path=StopBits, Converter={StaticResource EnumValToDescConverter}, Mode=TwoWay}"/>
<Label Margin="10 0 10 0" VerticalAlignment="Center">Handshake:</Label>
<ComboBox Width="100"
ItemsSource="{Binding Source={StaticResource HandshakeValues}, Converter={StaticResource EnumValToDescConverter}}"
SelectedItem="{Binding Path=Handshake, Converter={StaticResource EnumValToDescConverter}, Mode=TwoWay}"/>
</StackPanel>
</DockPanel>
</UserControl> </UserControl>

@ -1,28 +1,11 @@
using System; using System.Windows.Controls;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace MultiTerm.Wpf.View.SettingsView namespace MultiTerm.Wpf.View.SettingsView;
public partial class SerialSettingsView : UserControl
{ {
/// <summary> public SerialSettingsView()
/// Interaction logic for SerialSettingsView.xaml
/// </summary>
public partial class SerialSettingsView : UserControl
{ {
public SerialSettingsView() InitializeComponent();
{
InitializeComponent();
}
} }
} }

Loading…
Cancel
Save