Implemented indicator for new messages
This commit is contained in:
parent
c75ea0cc62
commit
79776fd813
@ -34,7 +34,7 @@ namespace PettingZoo.Test.Tapeti
|
||||
objectValue.Should().HaveElement("RecursiveValue").Which.Type.Should().Be(JTokenType.Null);
|
||||
|
||||
// Via type mapping
|
||||
// TODO
|
||||
// TODO test type mappings
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,23 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Windows;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace PettingZoo.UI.Tab.Subscriber
|
||||
{
|
||||
public class SameMessageVisibilityConverter : IMultiValueConverter
|
||||
{
|
||||
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
return ReferenceEquals(values[0], values[1])
|
||||
? Visibility.Visible
|
||||
: Visibility.Collapsed;
|
||||
}
|
||||
|
||||
|
||||
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
}
|
||||
}
|
@ -11,6 +11,9 @@
|
||||
d:DesignWidth="800"
|
||||
d:DataContext="{d:DesignInstance res:DesignTimeSubscriberViewModel, IsDesignTimeCreatable=True}"
|
||||
Background="White">
|
||||
<UserControl.Resources>
|
||||
<res:SameMessageVisibilityConverter x:Key="SameMessageVisibilityConverter" />
|
||||
</UserControl.Resources>
|
||||
<Grid Margin="4">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
@ -30,11 +33,37 @@
|
||||
<DataTemplate>
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" MinWidth="150"/>
|
||||
<ColumnDefinition Width="Auto" MinWidth="150" SharedSizeGroup="DateTime"/>
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock Grid.Column="0" Grid.Row="0" Text="{Binding ReceivedTimestamp, StringFormat=g}" Style="{StaticResource Timestamp}"></TextBlock>
|
||||
<TextBlock Grid.Column="1" Grid.Row="0" Text="{Binding RoutingKey}" Style="{StaticResource RoutingKey}"></TextBlock>
|
||||
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<!-- TODO insert as non-focusable item instead, so it's not part of the selection (and perhaps also fixes the bug mentioned in SubscriberViewModel) -->
|
||||
<Grid Grid.Column="0" Grid.Row="0" Grid.ColumnSpan="2">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition SharedSizeGroup="DateTime" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Grid.Visibility>
|
||||
<MultiBinding Converter="{StaticResource SameMessageVisibilityConverter}">
|
||||
<Binding RelativeSource="{RelativeSource Self}" Path="DataContext" />
|
||||
<Binding RelativeSource="{RelativeSource AncestorType={x:Type ListBox}}" Path="DataContext.NewMessage" />
|
||||
</MultiBinding>
|
||||
</Grid.Visibility>
|
||||
|
||||
<Separator Grid.Column="0" Margin="0,0,8,0" />
|
||||
<TextBlock Grid.Column="1" Text="{x:Static res:SubscriberViewStrings.LabelNewMessages}" HorizontalAlignment="Center" Background="{Binding Background, RelativeSource={RelativeSource AncestorType={x:Type ListBoxItem}}}" Foreground="{x:Static SystemColors.GrayTextBrush}" />
|
||||
<Separator Grid.Column="2" Margin="8,0,0,0" />
|
||||
</Grid>
|
||||
|
||||
<TextBlock Grid.Column="0" Grid.Row="1" Text="{Binding ReceivedTimestamp, StringFormat=g}" Style="{StaticResource Timestamp}" />
|
||||
<TextBlock Grid.Column="1" Grid.Row="1" Text="{Binding RoutingKey}" Style="{StaticResource RoutingKey}" />
|
||||
|
||||
<Grid.ContextMenu>
|
||||
<ContextMenu>
|
||||
@ -66,6 +95,8 @@
|
||||
<Border Grid.Column="0" Grid.Row="1" Style="{StaticResource SidePanel}">
|
||||
<DockPanel>
|
||||
<Label DockPanel.Dock="Top" Style="{StaticResource HeaderLabel}" Content="{x:Static res:SubscriberViewStrings.PanelTitleBody}"/>
|
||||
|
||||
<!-- TODO use AvalonEdit with syntax highlighting depending on content type -->
|
||||
<TextBox
|
||||
Text="{Binding SelectedMessageBody, Mode=OneWay}"
|
||||
BorderThickness="0"
|
||||
|
@ -1,14 +1,16 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Threading;
|
||||
using PettingZoo.Core.Connection;
|
||||
using PettingZoo.Core.Rendering;
|
||||
using PettingZoo.WPF.ViewModel;
|
||||
|
||||
// TODO visual hint of where the last read message was when activating the tab again
|
||||
// TODO if the "New message" line is visible when this tab is undocked, the line in the ListBox does not shrink. Haven't been able to figure out yet how to solve it
|
||||
|
||||
namespace PettingZoo.UI.Tab.Subscriber
|
||||
{
|
||||
@ -18,7 +20,7 @@ namespace PettingZoo.UI.Tab.Subscriber
|
||||
private readonly ITabFactory tabFactory;
|
||||
private readonly IConnection connection;
|
||||
private readonly ISubscriber subscriber;
|
||||
private readonly TaskScheduler uiScheduler;
|
||||
private readonly Dispatcher dispatcher;
|
||||
private ReceivedMessageInfo? selectedMessage;
|
||||
private readonly DelegateCommand clearCommand;
|
||||
private readonly TabToolbarCommand[] toolbarCommands;
|
||||
@ -27,6 +29,8 @@ namespace PettingZoo.UI.Tab.Subscriber
|
||||
private readonly DelegateCommand createPublisherCommand;
|
||||
|
||||
private bool tabActive;
|
||||
private ReceivedMessageInfo? newMessage;
|
||||
private Timer? newMessageTimer;
|
||||
private int unreadCount;
|
||||
|
||||
|
||||
@ -47,6 +51,14 @@ namespace PettingZoo.UI.Tab.Subscriber
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public ReceivedMessageInfo? NewMessage
|
||||
{
|
||||
get => newMessage;
|
||||
set => SetField(ref newMessage, value);
|
||||
}
|
||||
|
||||
|
||||
public string SelectedMessageBody =>
|
||||
SelectedMessage != null
|
||||
? MessageBodyRenderer.Render(SelectedMessage.Body, SelectedMessage.Properties.ContentType)
|
||||
@ -71,7 +83,7 @@ namespace PettingZoo.UI.Tab.Subscriber
|
||||
this.connection = connection;
|
||||
this.subscriber = subscriber;
|
||||
|
||||
uiScheduler = TaskScheduler.FromCurrentSynchronizationContext();
|
||||
dispatcher = Dispatcher.CurrentDispatcher;
|
||||
|
||||
Messages = new ObservableCollection<ReceivedMessageInfo>();
|
||||
clearCommand = new DelegateCommand(ClearExecute, ClearCanExecute);
|
||||
@ -116,12 +128,14 @@ namespace PettingZoo.UI.Tab.Subscriber
|
||||
|
||||
private void SubscriberMessageReceived(object? sender, MessageReceivedEventArgs args)
|
||||
{
|
||||
RunFromUiScheduler(() =>
|
||||
dispatcher.BeginInvoke(() =>
|
||||
{
|
||||
if (!tabActive)
|
||||
{
|
||||
unreadCount++;
|
||||
RaisePropertyChanged(nameof(Title));
|
||||
|
||||
NewMessage ??= args.MessageInfo;
|
||||
}
|
||||
|
||||
Messages.Add(args.MessageInfo);
|
||||
@ -140,22 +154,39 @@ namespace PettingZoo.UI.Tab.Subscriber
|
||||
}
|
||||
|
||||
|
||||
private void RunFromUiScheduler(Action action)
|
||||
{
|
||||
_ = Task.Factory.StartNew(action, CancellationToken.None, TaskCreationOptions.None, uiScheduler);
|
||||
}
|
||||
|
||||
|
||||
public void Activate()
|
||||
{
|
||||
tabActive = true;
|
||||
unreadCount = 0;
|
||||
|
||||
RaisePropertyChanged(nameof(Title));
|
||||
|
||||
if (NewMessage == null)
|
||||
return;
|
||||
|
||||
newMessageTimer?.Dispose();
|
||||
newMessageTimer = new Timer(
|
||||
_ =>
|
||||
{
|
||||
dispatcher.BeginInvoke(() =>
|
||||
{
|
||||
NewMessage = null;
|
||||
});
|
||||
},
|
||||
null,
|
||||
TimeSpan.FromSeconds(5),
|
||||
Timeout.InfiniteTimeSpan);
|
||||
}
|
||||
|
||||
public void Deactivate()
|
||||
{
|
||||
if (newMessageTimer != null)
|
||||
{
|
||||
newMessageTimer.Dispose();
|
||||
newMessageTimer = null;
|
||||
}
|
||||
|
||||
NewMessage = null;
|
||||
tabActive = false;
|
||||
}
|
||||
}
|
||||
@ -165,6 +196,20 @@ namespace PettingZoo.UI.Tab.Subscriber
|
||||
{
|
||||
public DesignTimeSubscriberViewModel() : base(null!, null!, null!, new DesignTimeSubscriber())
|
||||
{
|
||||
for (var i = 1; i <= 5; i++)
|
||||
Messages.Add(new ReceivedMessageInfo(
|
||||
"designtime",
|
||||
$"designtime.message.{i}",
|
||||
Encoding.UTF8.GetBytes(@"Design-time message"),
|
||||
new MessageProperties(null)
|
||||
{
|
||||
ContentType = "text/fake",
|
||||
ReplyTo = "/dev/null"
|
||||
},
|
||||
DateTime.Now));
|
||||
|
||||
SelectedMessage = Messages[2];
|
||||
NewMessage = Messages[2];
|
||||
}
|
||||
|
||||
|
||||
|
@ -96,6 +96,15 @@ namespace PettingZoo.UI.Tab.Subscriber {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to New messages.
|
||||
/// </summary>
|
||||
public static string LabelNewMessages {
|
||||
get {
|
||||
return ResourceManager.GetString("LabelNewMessages", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Body.
|
||||
/// </summary>
|
||||
|
@ -112,10 +112,10 @@
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<data name="CommandClear" xml:space="preserve">
|
||||
<value>Clear</value>
|
||||
@ -129,6 +129,9 @@
|
||||
<data name="DeliveryModePersistent" xml:space="preserve">
|
||||
<value>Persistent</value>
|
||||
</data>
|
||||
<data name="LabelNewMessages" xml:space="preserve">
|
||||
<value>New messages</value>
|
||||
</data>
|
||||
<data name="PanelTitleBody" xml:space="preserve">
|
||||
<value>Body</value>
|
||||
</data>
|
||||
|
@ -8,7 +8,7 @@ using PettingZoo.WPF.ViewModel;
|
||||
|
||||
namespace PettingZoo.UI.Tab.Undocked
|
||||
{
|
||||
public class UndockedTabHostViewModel : BaseViewModel
|
||||
public class UndockedTabHostViewModel : BaseViewModel, ITabActivate
|
||||
{
|
||||
private readonly ITabHost tabHost;
|
||||
private readonly ITab tab;
|
||||
@ -51,6 +51,17 @@ namespace PettingZoo.UI.Tab.Undocked
|
||||
{
|
||||
tabHost.UndockedTabClosed(tab);
|
||||
}
|
||||
|
||||
|
||||
public void Activate()
|
||||
{
|
||||
(tab as ITabActivate)?.Activate();
|
||||
}
|
||||
|
||||
public void Deactivate()
|
||||
{
|
||||
(tab as ITabActivate)?.Deactivate();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,5 +1,7 @@
|
||||
using System.Windows;
|
||||
using System;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Threading;
|
||||
|
||||
namespace PettingZoo.UI.Tab.Undocked
|
||||
{
|
||||
@ -30,6 +32,16 @@ namespace PettingZoo.UI.Tab.Undocked
|
||||
{
|
||||
viewModel.WindowClosed();
|
||||
};
|
||||
|
||||
Activated += (_, _) =>
|
||||
{
|
||||
viewModel.Activate();
|
||||
};
|
||||
|
||||
Deactivated += (_, _) =>
|
||||
{
|
||||
viewModel.Deactivate();
|
||||
};
|
||||
}
|
||||
|
||||
private void Toolbar_Loaded(object sender, RoutedEventArgs e)
|
||||
|
Loading…
Reference in New Issue
Block a user