diff --git a/MultiTerm.Core/ViewModel/TerminalViewModel.cs b/MultiTerm.Core/ViewModel/TerminalViewModel.cs index 44bf8ad..73272d0 100644 --- a/MultiTerm.Core/ViewModel/TerminalViewModel.cs +++ b/MultiTerm.Core/ViewModel/TerminalViewModel.cs @@ -26,13 +26,12 @@ public abstract partial class TerminalViewModel : ObservableObject, ITerminalVie // register event handler for connection request from viewmodel if(value != null) { - protocolSettings!.ConnectRequested += OnViewModelRequestedConnect; ; + protocolSettings!.ConnectRequested += OnViewModelRequestedConnect; ; ; protocolSettings!.DisconnectRequested += OnViewModelRequestedDisconnect; } } } - /// /// Method to override if any closing actions are required. /// Closing can be cancelled using the return value. @@ -49,13 +48,19 @@ public abstract partial class TerminalViewModel : ObservableObject, ITerminalVie } } - private void OnViewModelRequestedConnect(object? sender, IProtocolSettings e) + private void OnViewModelRequestedConnect(object? sender, ConnectionRequestEventArgs e) { - this.CommunicationProtocol?.Connect(e); + // guard uninitialized CommunicationProtocol + if (CommunicationProtocol == null) { throw new Exception($"To call '{nameof(OnViewModelRequestedConnect)}()', CommunicationProtocol must not be null!"); } + + e.Success = this.CommunicationProtocol.Connect(e.Settings); } private void OnViewModelRequestedDisconnect(object? sender, EventArgs e) { - this.CommunicationProtocol?.Disconnect(); + // guard uninitialized CommunicationProtocol + if (CommunicationProtocol == null) { throw new Exception($"To call '{nameof(OnViewModelRequestedConnect)}()', CommunicationProtocol must not be null!"); } + + this.CommunicationProtocol.Disconnect(); } } diff --git a/MultiTerm.Protocols/CommunicationProtocol.cs b/MultiTerm.Protocols/CommunicationProtocol.cs index b506f67..68b5e27 100644 --- a/MultiTerm.Protocols/CommunicationProtocol.cs +++ b/MultiTerm.Protocols/CommunicationProtocol.cs @@ -59,13 +59,13 @@ public abstract class CommunicationProtocol : ICommunicationProtocol /// cancellation token protected abstract void InternalRead(CancellationToken ct); - public void Connect(IProtocolSettings settings) + public bool Connect(IProtocolSettings settings) { // check if settings are valid, cancel if not if (settings.AreValid() == false) { this.logger.LogError($"'{nameof(Connect)}()' failed since the provided protocol settings are invalid", nameof(CommunicationProtocol)); - return; + return false; } // try connecting if serttings are valid @@ -76,10 +76,12 @@ public abstract class CommunicationProtocol : ICommunicationProtocol // start internal reading thread this.readingThread = new Thread(() => this.InternalRead(this.cancellationTokenSource.Token)); this.readingThread.Start(); + return true; } else { this.logger.LogWarn($"'{nameof(Connect)}()' failed to connect to protocol, did not start reading thread.", nameof(CommunicationProtocol)); + return false; } } diff --git a/MultiTerm.Protocols/ConnectionRequestEventArgs.cs b/MultiTerm.Protocols/ConnectionRequestEventArgs.cs new file mode 100644 index 0000000..9247633 --- /dev/null +++ b/MultiTerm.Protocols/ConnectionRequestEventArgs.cs @@ -0,0 +1,25 @@ +namespace MultiTerm.Protocols; + +public class ConnectionRequestEventArgs : EventArgs +{ + /// + /// Settings object, contains all settings that are required to connect. + /// + public IProtocolSettings Settings { get; private set; } + + /// + /// Indicates wether the connection could be successfully made. + /// + public bool Success { get; set; } + + /// + /// Creates instance of event args with given . + /// Defaults to . + /// + /// settings object + public ConnectionRequestEventArgs(IProtocolSettings settings) + { + this.Settings = settings; + this.Success = true; + } +} diff --git a/MultiTerm.Protocols/ICommunicationProtocol.cs b/MultiTerm.Protocols/ICommunicationProtocol.cs index 72a3a90..c0c42f5 100644 --- a/MultiTerm.Protocols/ICommunicationProtocol.cs +++ b/MultiTerm.Protocols/ICommunicationProtocol.cs @@ -26,7 +26,7 @@ public interface ICommunicationProtocol /// Connect to the device. /// /// settings required to connect and use the protocol - void Connect(IProtocolSettings settings); + bool Connect(IProtocolSettings settings); /// /// Disconnect from the device. Ends all internal activities. diff --git a/MultiTerm.Protocols/IProtocolSettingsViewModel.cs b/MultiTerm.Protocols/IProtocolSettingsViewModel.cs index 4cc1d02..9f61bd5 100644 --- a/MultiTerm.Protocols/IProtocolSettingsViewModel.cs +++ b/MultiTerm.Protocols/IProtocolSettingsViewModel.cs @@ -13,7 +13,7 @@ public interface IProtocolSettingsViewModel /// Event that is thrown when the user requested to connect to the device with the entered settings. /// Provides protocol settings to use for connection. /// - event EventHandler ConnectRequested; + event EventHandler ConnectRequested; /// /// Event that is thrown when the user requested to disconnect from the device. diff --git a/MultiTerm.Protocols/ProtocolSettingsViewModel.cs b/MultiTerm.Protocols/ProtocolSettingsViewModel.cs index 0474a16..83c7bc1 100644 --- a/MultiTerm.Protocols/ProtocolSettingsViewModel.cs +++ b/MultiTerm.Protocols/ProtocolSettingsViewModel.cs @@ -16,7 +16,7 @@ public abstract partial class ProtocolSettingsViewModel : ObservableObject, IPro private const string disconnectedStateButtonText = "Connect"; protected readonly IMessenger messenger; - public event EventHandler? ConnectRequested; + public event EventHandler? ConnectRequested; public event EventHandler? DisconnectRequested; public abstract ProtocolType ProtocolType { get; } @@ -50,8 +50,23 @@ public abstract partial class ProtocolSettingsViewModel : ObservableObject, IPro { // CONNECT this.AreEditable = false; - this.ConnectRequested?.Invoke(this, (IProtocolSettings)this); // implementing class must also implement IProtocolSettings! - this.ConnectDisconnectButtonText = connectedStateButtonText; + + // create event args. Important: derivative classes must also implement IProtocolSettings! + var eventArgs = new ConnectionRequestEventArgs((IProtocolSettings)this); + // fire event + this.ConnectRequested?.Invoke(this, eventArgs); + + // after invoke: connection was made successfully? + if (eventArgs.Success) + { + // set button to connected state + this.ConnectDisconnectButtonText = connectedStateButtonText; + } + else + { + // rollback + this.AreEditable = true; + } } // if currently connected else if (this.ConnectDisconnectButtonText == connectedStateButtonText)