implemented progress bar and auto remove status bar message after duration,

moved TabContent to Wpf Project instead of CustomControl Project,
added ProgressBarSmoother,
fixed exception in destructor of MultiFormatTextBox,
added message on unintentional disconnect,
added detection in TCP when socket was closed
master
Jonas Arnold 3 years ago
parent 897908bf13
commit 12a3b6792f
  1. 40
      MultiTerm.Core/ViewModel/ShellViewModel.cs
  2. 3
      MultiTerm.Protocols/CommunicationProtocol.cs
  3. 8
      MultiTerm.Protocols/Tcp/TcpClientProtocol.cs
  4. 6
      MultiTerm.Wpf.CustomControl/MultiFormatTextBox/MultiFormatTextBox.cs
  5. 4
      MultiTerm.Wpf.CustomControl/MultiTerm.Wpf.CustomControl.csproj
  6. 38
      MultiTerm.Wpf/Behaviours/ProgressBarSmoother.cs
  7. 2
      MultiTerm.Wpf/Behaviours/TabContent.cs
  8. 18
      MultiTerm.Wpf/View/ShellView.xaml

@ -9,6 +9,7 @@ using MultiTerm.Core.Types;
using MultiTerm.Protocols.Types; using MultiTerm.Protocols.Types;
using CommunityToolkit.Mvvm.Messaging; using CommunityToolkit.Mvvm.Messaging;
using Common.Messaging; using Common.Messaging;
using System.Timers;
namespace MultiTerm.Core.ViewModel; namespace MultiTerm.Core.ViewModel;
@ -16,6 +17,7 @@ public partial class ShellViewModel : ObservableObject, IRecipient<IUserInterfac
{ {
private const string defaultReceiveNewlineSeparatorAppSettingsKey = "DefaultReceiveNewlineSeparator"; private const string defaultReceiveNewlineSeparatorAppSettingsKey = "DefaultReceiveNewlineSeparator";
private const string defaultSendNewlineSeparatorAppSettingsKey = "DefaultSendNewlineSeparator"; private const string defaultSendNewlineSeparatorAppSettingsKey = "DefaultSendNewlineSeparator";
private const int statusBarMessageDurationMs = 12000; // how long the status bar shall be displayed
#region Terminal collection #region Terminal collection
[ObservableProperty] [ObservableProperty]
@ -39,11 +41,17 @@ public partial class ShellViewModel : ObservableObject, IRecipient<IUserInterfac
#endregion #endregion
#region Status Bar #region Status Bar
private System.Timers.Timer? statusBarMessageTimer;
private const int statusBarMessageTimerIntervalMs = 100; // After x milliseconds the timer shall be called
[ObservableProperty] [ObservableProperty]
private string statusBarMessage = ""; private string statusBarMessage = "";
[ObservableProperty] [ObservableProperty]
private MessageImportance statusBarMessageImportance = MessageImportance.Normal; private MessageImportance statusBarMessageImportance = MessageImportance.Normal;
[ObservableProperty]
private double statusBarMessageDurationPercentage = 0;
#endregion #endregion
private readonly ITerminalViewModelFactory terminalViewModelFactory; private readonly ITerminalViewModelFactory terminalViewModelFactory;
@ -142,8 +150,40 @@ public partial class ShellViewModel : ObservableObject, IRecipient<IUserInterfac
#region Messaging handling #region Messaging handling
public void Receive(IUserInterfaceMessage message) public void Receive(IUserInterfaceMessage message)
{ {
// reset percentage
this.StatusBarMessageDurationPercentage = 100;
// display message
this.StatusBarMessage = message.ToString(); this.StatusBarMessage = message.ToString();
this.StatusBarMessageImportance = message.Importance; this.StatusBarMessageImportance = message.Importance;
// start timer
if(this.statusBarMessageTimer == null)
{
this.statusBarMessageTimer = new System.Timers.Timer(statusBarMessageTimerIntervalMs);
this.statusBarMessageTimer.Elapsed += StatusBarMessageTimer_Elapsed;
this.statusBarMessageTimer.AutoReset = true; // restart after elapsed
this.statusBarMessageTimer.Enabled = true; // start timer
}
}
private void StatusBarMessageTimer_Elapsed(object? sender, ElapsedEventArgs e)
{
float differencePercentage = (statusBarMessageDurationMs / statusBarMessageTimerIntervalMs) / 100;
// if not yet done
if(this.StatusBarMessageDurationPercentage - differencePercentage > 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 #endregion
} }

@ -68,6 +68,9 @@ public abstract class CommunicationProtocol : ICommunicationProtocol
// update state // update state
this.State = ProtocolConnectionState.UnintentionallyDisconnected; this.State = ProtocolConnectionState.UnintentionallyDisconnected;
// inform user
this.messenger.Send<IUserInterfaceMessage>(new GenericUserInterfaceMessage($"'{this.GetProtocolAndInstanceIdentifier()}' unintentionally disconnected.", MessageImportance.High));
}); });
} }

@ -105,6 +105,14 @@ public class TcpClientProtocol : CommunicationProtocol
{ {
while (ct.IsCancellationRequested == false) 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 // try receive message with a buffer
int readByte = -1; int readByte = -1;
try try

@ -83,8 +83,10 @@ public class MultiFormatTextBox : Control
~MultiFormatTextBox() ~MultiFormatTextBox()
{ {
// unregister events // unregister events
var incc = this.CurrentMultiFormatString as INotifyCollectionChanged; if (this.CurrentMultiFormatString is INotifyCollectionChanged incc)
incc.CollectionChanged -= this.MultiFormatString_CollectionChanged; {
incc.CollectionChanged -= this.MultiFormatString_CollectionChanged;
}
} }
public override void OnApplyTemplate() public override void OnApplyTemplate()

@ -14,8 +14,4 @@
<ProjectReference Include="..\MultiTerm.Core\MultiTerm.Core.csproj" /> <ProjectReference Include="..\MultiTerm.Core\MultiTerm.Core.csproj" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<Folder Include="Behaviours\" />
</ItemGroup>
</Project> </Project>

@ -0,0 +1,38 @@
using System;
using System.Windows.Controls;
using System.Windows.Media.Animation;
using System.Windows;
namespace MultiTerm.Wpf.Behaviours;
/// <summary>
/// From https://stackoverflow.com/questions/14485818/how-to-update-a-progress-bar-so-it-increases-smoothly
/// </summary>
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);
}
}

@ -9,7 +9,7 @@ using System.Windows.Controls;
using System.Windows.Data; using System.Windows.Data;
using System.Windows.Markup; using System.Windows.Markup;
namespace MultiTerm.Wpf.CustomControl; namespace MultiTerm.Wpf.Behaviours;
/// <summary> /// <summary>
/// Attached properties for persistent tab control /// Attached properties for persistent tab control

@ -9,6 +9,7 @@
xmlns:custom_controls="clr-namespace:MultiTerm.Wpf.CustomControl;assembly=MultiTerm.Wpf.CustomControl" xmlns:custom_controls="clr-namespace:MultiTerm.Wpf.CustomControl;assembly=MultiTerm.Wpf.CustomControl"
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:behaviours="clr-namespace:MultiTerm.Wpf.Behaviours"
xmlns:types="clr-namespace:MultiTerm.Core.Types;assembly=MultiTerm.Core" xmlns:types="clr-namespace:MultiTerm.Core.Types;assembly=MultiTerm.Core"
xmlns:protocol_types="clr-namespace:MultiTerm.Protocols.Types;assembly=MultiTerm.Protocols" xmlns:protocol_types="clr-namespace:MultiTerm.Protocols.Types;assembly=MultiTerm.Protocols"
xmlns:helpers="clr-namespace:MultiTerm.Wpf.Helpers" xmlns:helpers="clr-namespace:MultiTerm.Wpf.Helpers"
@ -76,9 +77,16 @@
</Menu> </Menu>
<!-- Bottom status bar with separator --> <!-- Bottom status bar with separator -->
<StatusBar DockPanel.Dock="Bottom"> <StatusBar DockPanel.Dock="Bottom" Height="30">
<StatusBarItem> <StatusBarItem>
<TextBlock Text="{Binding StatusBarMessage}" FontSize="15" <ProgressBar Height="20" Width="40" Margin="3 0 0 0"
behaviours:ProgressBarSmoother.SmoothValue="{Binding Path=StatusBarMessageDurationPercentage}"
Foreground="{Binding Path=StatusBarMessageImportance, Converter={StaticResource MsgImportanceBrushConverter}}"
Opacity="0.6" BorderBrush="Transparent" Background="Transparent" FlowDirection="RightToLeft"/>
</StatusBarItem>
<Separator/>
<StatusBarItem VerticalContentAlignment="Center">
<TextBlock Text="{Binding StatusBarMessage}" FontSize="15" VerticalAlignment="Bottom"
Foreground="{Binding Path=StatusBarMessageImportance, Converter={StaticResource MsgImportanceBrushConverter}}" Foreground="{Binding Path=StatusBarMessageImportance, Converter={StaticResource MsgImportanceBrushConverter}}"
FontWeight="{Binding Path=StatusBarMessageImportance, Converter={StaticResource MsgImportanceFontWeightConverter}}"/> FontWeight="{Binding Path=StatusBarMessageImportance, Converter={StaticResource MsgImportanceFontWeightConverter}}"/>
</StatusBarItem> </StatusBarItem>
@ -132,7 +140,7 @@
<custom_controls:ExtendedTabControl Grid.Row="1" Grid.Column="1" <custom_controls:ExtendedTabControl Grid.Row="1" Grid.Column="1"
x:Name="terminalTabControl" x:Name="terminalTabControl"
IsSynchronizedWithCurrentItem="True" IsSynchronizedWithCurrentItem="True"
custom_controls:TabContent.IsCached="True" behaviours:TabContent.IsCached="True"
ItemsSource="{Binding TerminalViewModels}" ItemsSource="{Binding TerminalViewModels}"
SelectedItem="{Binding SelectedTerminalViewModel}"> SelectedItem="{Binding SelectedTerminalViewModel}">
@ -144,11 +152,11 @@
</custom_controls:ExtendedTabControl.Resources> </custom_controls:ExtendedTabControl.Resources>
<!-- Content of tab with special caching behaviour --> <!-- Content of tab with special caching behaviour -->
<custom_controls:TabContent.Template> <behaviours:TabContent.Template>
<DataTemplate> <DataTemplate>
<ContentControl Content="{Binding}"/> <ContentControl Content="{Binding}"/>
</DataTemplate> </DataTemplate>
</custom_controls:TabContent.Template> </behaviours:TabContent.Template>
<!-- Tab Header Template --> <!-- Tab Header Template -->
<custom_controls:ExtendedTabControl.ItemTemplate> <custom_controls:ExtendedTabControl.ItemTemplate>

Loading…
Cancel
Save