diff --git a/MultiTerm.Core/ViewModel/ShellViewModel.cs b/MultiTerm.Core/ViewModel/ShellViewModel.cs index a65d4c1..49c85b0 100644 --- a/MultiTerm.Core/ViewModel/ShellViewModel.cs +++ b/MultiTerm.Core/ViewModel/ShellViewModel.cs @@ -9,6 +9,7 @@ using MultiTerm.Core.Types; using MultiTerm.Protocols.Types; using CommunityToolkit.Mvvm.Messaging; using Common.Messaging; +using System.Timers; namespace MultiTerm.Core.ViewModel; @@ -16,6 +17,7 @@ public partial class ShellViewModel : ObservableObject, IRecipient 0) + { + this.StatusBarMessageDurationPercentage -= differencePercentage; + return; + } + + // clear message and kill timer when finished + this.StatusBarMessage = ""; + this.StatusBarMessageDurationPercentage = 0; + this.statusBarMessageTimer!.Enabled = false; + this.statusBarMessageTimer.Dispose(); + this.statusBarMessageTimer = null; } #endregion } diff --git a/MultiTerm.Protocols/CommunicationProtocol.cs b/MultiTerm.Protocols/CommunicationProtocol.cs index a4b1c9b..8d92cad 100644 --- a/MultiTerm.Protocols/CommunicationProtocol.cs +++ b/MultiTerm.Protocols/CommunicationProtocol.cs @@ -68,6 +68,9 @@ public abstract class CommunicationProtocol : ICommunicationProtocol // update state this.State = ProtocolConnectionState.UnintentionallyDisconnected; + + // inform user + this.messenger.Send(new GenericUserInterfaceMessage($"'{this.GetProtocolAndInstanceIdentifier()}' unintentionally disconnected.", MessageImportance.High)); }); } diff --git a/MultiTerm.Protocols/Tcp/TcpClientProtocol.cs b/MultiTerm.Protocols/Tcp/TcpClientProtocol.cs index dd3d7ec..f24b6b9 100644 --- a/MultiTerm.Protocols/Tcp/TcpClientProtocol.cs +++ b/MultiTerm.Protocols/Tcp/TcpClientProtocol.cs @@ -105,6 +105,14 @@ public class TcpClientProtocol : CommunicationProtocol { while (ct.IsCancellationRequested == false) { + // check if client still connected + if (this.client == null || this.client?.Connected == false) + { + this.logger.LogError($"Client isnull={this.client == null} or not connected anymore while sending data in {nameof(InternalRead)}", nameof(TcpClientProtocol)); + this.OnUnintentionallyDisconnected(); + break; // break loop + } + // try receive message with a buffer int readByte = -1; try diff --git a/MultiTerm.Wpf.CustomControl/MultiFormatTextBox/MultiFormatTextBox.cs b/MultiTerm.Wpf.CustomControl/MultiFormatTextBox/MultiFormatTextBox.cs index b25b70d..e44b8af 100644 --- a/MultiTerm.Wpf.CustomControl/MultiFormatTextBox/MultiFormatTextBox.cs +++ b/MultiTerm.Wpf.CustomControl/MultiFormatTextBox/MultiFormatTextBox.cs @@ -83,8 +83,10 @@ public class MultiFormatTextBox : Control ~MultiFormatTextBox() { // unregister events - var incc = this.CurrentMultiFormatString as INotifyCollectionChanged; - incc.CollectionChanged -= this.MultiFormatString_CollectionChanged; + if (this.CurrentMultiFormatString is INotifyCollectionChanged incc) + { + incc.CollectionChanged -= this.MultiFormatString_CollectionChanged; + } } public override void OnApplyTemplate() diff --git a/MultiTerm.Wpf.CustomControl/MultiTerm.Wpf.CustomControl.csproj b/MultiTerm.Wpf.CustomControl/MultiTerm.Wpf.CustomControl.csproj index b8f9a24..e29b1fc 100644 --- a/MultiTerm.Wpf.CustomControl/MultiTerm.Wpf.CustomControl.csproj +++ b/MultiTerm.Wpf.CustomControl/MultiTerm.Wpf.CustomControl.csproj @@ -14,8 +14,4 @@ - - - - diff --git a/MultiTerm.Wpf/Behaviours/ProgressBarSmoother.cs b/MultiTerm.Wpf/Behaviours/ProgressBarSmoother.cs new file mode 100644 index 0000000..00e8dbb --- /dev/null +++ b/MultiTerm.Wpf/Behaviours/ProgressBarSmoother.cs @@ -0,0 +1,38 @@ +using System; +using System.Windows.Controls; +using System.Windows.Media.Animation; +using System.Windows; + +namespace MultiTerm.Wpf.Behaviours; + +/// +/// From https://stackoverflow.com/questions/14485818/how-to-update-a-progress-bar-so-it-increases-smoothly +/// +public class ProgressBarSmoother +{ + public static double GetSmoothValue(DependencyObject obj) + { + return (double)obj.GetValue(SmoothValueProperty); + } + + public static void SetSmoothValue(DependencyObject obj, double value) + { + obj.SetValue(SmoothValueProperty, value); + } + + public static readonly DependencyProperty SmoothValueProperty = + DependencyProperty.RegisterAttached( + "SmoothValue", + typeof(double), + typeof(ProgressBarSmoother), + new PropertyMetadata(0.0, Changing)); + + private static void Changing(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + // guard wrong type + if(d is not ProgressBar progressBar) { return; } + + var anim = new DoubleAnimation((double)e.OldValue, (double)e.NewValue, new TimeSpan(0, 0, 0, 0, 250)); + progressBar.BeginAnimation(ProgressBar.ValueProperty, anim, HandoffBehavior.Compose); + } +} diff --git a/MultiTerm.Wpf.CustomControl/Behaviours/TabContent.cs b/MultiTerm.Wpf/Behaviours/TabContent.cs similarity index 99% rename from MultiTerm.Wpf.CustomControl/Behaviours/TabContent.cs rename to MultiTerm.Wpf/Behaviours/TabContent.cs index ee6b3c2..c1e57c5 100644 --- a/MultiTerm.Wpf.CustomControl/Behaviours/TabContent.cs +++ b/MultiTerm.Wpf/Behaviours/TabContent.cs @@ -9,7 +9,7 @@ using System.Windows.Controls; using System.Windows.Data; using System.Windows.Markup; -namespace MultiTerm.Wpf.CustomControl; +namespace MultiTerm.Wpf.Behaviours; /// /// Attached properties for persistent tab control diff --git a/MultiTerm.Wpf/View/ShellView.xaml b/MultiTerm.Wpf/View/ShellView.xaml index 53ddcd7..7657cfd 100644 --- a/MultiTerm.Wpf/View/ShellView.xaml +++ b/MultiTerm.Wpf/View/ShellView.xaml @@ -9,6 +9,7 @@ xmlns:custom_controls="clr-namespace:MultiTerm.Wpf.CustomControl;assembly=MultiTerm.Wpf.CustomControl" xmlns:vm="clr-namespace:MultiTerm.Core.ViewModel;assembly=MultiTerm.Core" xmlns:v="clr-namespace:MultiTerm.Wpf.View" + xmlns:behaviours="clr-namespace:MultiTerm.Wpf.Behaviours" xmlns:types="clr-namespace:MultiTerm.Core.Types;assembly=MultiTerm.Core" xmlns:protocol_types="clr-namespace:MultiTerm.Protocols.Types;assembly=MultiTerm.Protocols" xmlns:helpers="clr-namespace:MultiTerm.Wpf.Helpers" @@ -76,9 +77,16 @@ - + - + + + + @@ -132,7 +140,7 @@ @@ -144,11 +152,11 @@ - + - +