Use single subscriber tab for replies
This commit is contained in:
parent
6e8029b552
commit
76d4c8fa85
@ -3,7 +3,7 @@ using System.Collections.Generic;
|
|||||||
|
|
||||||
namespace PettingZoo.Core.Connection
|
namespace PettingZoo.Core.Connection
|
||||||
{
|
{
|
||||||
public interface ISubscriber : IAsyncDisposable
|
public interface ISubscriber : IDisposable
|
||||||
{
|
{
|
||||||
string? QueueName { get; }
|
string? QueueName { get; }
|
||||||
string? Exchange {get; }
|
string? Exchange {get; }
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Threading.Tasks;
|
|
||||||
using PettingZoo.Core.Connection;
|
using PettingZoo.Core.Connection;
|
||||||
|
|
||||||
namespace PettingZoo.Core.ExportImport
|
namespace PettingZoo.Core.ExportImport
|
||||||
@ -13,7 +12,10 @@ namespace PettingZoo.Core.ExportImport
|
|||||||
public string? QueueName { get; }
|
public string? QueueName { get; }
|
||||||
public string? Exchange => null;
|
public string? Exchange => null;
|
||||||
public string? RoutingKey => null;
|
public string? RoutingKey => null;
|
||||||
|
|
||||||
|
#pragma warning disable CS0067 // "The event ... is never used" - it's part of the interface so it's required.
|
||||||
public event EventHandler<MessageReceivedEventArgs>? MessageReceived;
|
public event EventHandler<MessageReceivedEventArgs>? MessageReceived;
|
||||||
|
#pragma warning restore CS0067
|
||||||
|
|
||||||
|
|
||||||
public ImportSubscriber(string filename, IReadOnlyList<ReceivedMessageInfo> messages)
|
public ImportSubscriber(string filename, IReadOnlyList<ReceivedMessageInfo> messages)
|
||||||
@ -23,10 +25,9 @@ namespace PettingZoo.Core.ExportImport
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public ValueTask DisposeAsync()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
GC.SuppressFinalize(this);
|
GC.SuppressFinalize(this);
|
||||||
return default;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -58,7 +58,7 @@ namespace PettingZoo.Core.ExportImport
|
|||||||
public StreamWrapper(StreamProgressDecorator owner, Stream decoratedStream)
|
public StreamWrapper(StreamProgressDecorator owner, Stream decoratedStream)
|
||||||
{
|
{
|
||||||
this.owner = owner;
|
this.owner = owner;
|
||||||
this.DecoratedStream = decoratedStream;
|
DecoratedStream = decoratedStream;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
|
||||||
using PettingZoo.Core.Connection;
|
using PettingZoo.Core.Connection;
|
||||||
using RabbitMQ.Client;
|
using RabbitMQ.Client;
|
||||||
using RabbitMQ.Client.Events;
|
using RabbitMQ.Client.Events;
|
||||||
@ -29,14 +28,12 @@ namespace PettingZoo.RabbitMQ
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public ValueTask DisposeAsync()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
GC.SuppressFinalize(this);
|
GC.SuppressFinalize(this);
|
||||||
|
|
||||||
if (model != null && consumerTag != null && model.IsOpen)
|
if (model != null && consumerTag != null && model.IsOpen)
|
||||||
model.BasicCancelNoWait(consumerTag);
|
model.BasicCancelNoWait(consumerTag);
|
||||||
|
|
||||||
return default;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -5,7 +5,6 @@ using System.Linq;
|
|||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Threading;
|
|
||||||
using PettingZoo.Core.Generator;
|
using PettingZoo.Core.Generator;
|
||||||
using PettingZoo.Core.Settings;
|
using PettingZoo.Core.Settings;
|
||||||
using PettingZoo.Tapeti.AssemblyLoader;
|
using PettingZoo.Tapeti.AssemblyLoader;
|
||||||
|
@ -4,9 +4,6 @@
|
|||||||
|
|
||||||
Should-have
|
Should-have
|
||||||
-----------
|
-----------
|
||||||
- Single tab for responses, don't create a new subscriber tab for 1 message each time
|
|
||||||
Use the CorrelationId in the list for such cases instead of the routing key (which is the name of the dynamic queue for the responses).
|
|
||||||
Set the CorrelationId to the request routing key for example, so the different responses can be somewhat identified.
|
|
||||||
|
|
||||||
|
|
||||||
Nice-to-have
|
Nice-to-have
|
||||||
|
@ -170,7 +170,7 @@ namespace PettingZoo.UI.Main
|
|||||||
if (connectionSettings.Subscribe)
|
if (connectionSettings.Subscribe)
|
||||||
{
|
{
|
||||||
var subscriber = connection.Subscribe(connectionSettings.Exchange, connectionSettings.RoutingKey);
|
var subscriber = connection.Subscribe(connectionSettings.Exchange, connectionSettings.RoutingKey);
|
||||||
AddTab(tabFactory.CreateSubscriberTab(connection, subscriber));
|
tabFactory.CreateSubscriberTab(connection, subscriber);
|
||||||
}
|
}
|
||||||
|
|
||||||
ConnectionChanged();
|
ConnectionChanged();
|
||||||
@ -214,7 +214,7 @@ namespace PettingZoo.UI.Main
|
|||||||
subscribeDialogParams = newParams;
|
subscribeDialogParams = newParams;
|
||||||
|
|
||||||
var subscriber = connection.Subscribe(subscribeDialogParams.Exchange, subscribeDialogParams.RoutingKey);
|
var subscriber = connection.Subscribe(subscribeDialogParams.Exchange, subscribeDialogParams.RoutingKey);
|
||||||
AddTab(tabFactory.CreateSubscriberTab(connection, subscriber));
|
tabFactory.CreateSubscriberTab(connection, subscriber);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -223,7 +223,7 @@ namespace PettingZoo.UI.Main
|
|||||||
if (connection == null)
|
if (connection == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
AddTab(tabFactory.CreatePublisherTab(connection));
|
tabFactory.CreatePublisherTab(connection);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -235,7 +235,8 @@ namespace PettingZoo.UI.Main
|
|||||||
|
|
||||||
private void CloseTabExecute()
|
private void CloseTabExecute()
|
||||||
{
|
{
|
||||||
RemoveActiveTab();
|
var tab = RemoveActiveTab();
|
||||||
|
(tab as IDisposable)?.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -300,8 +301,7 @@ namespace PettingZoo.UI.Main
|
|||||||
progressWindow.Close();
|
progressWindow.Close();
|
||||||
progressWindow = null;
|
progressWindow = null;
|
||||||
|
|
||||||
AddTab(tabFactory.CreateSubscriberTab(connection,
|
tabFactory.CreateSubscriberTab(connection, new ImportSubscriber(filename, messages));
|
||||||
new ImportSubscriber(filename, messages)));
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
catch (OperationCanceledException)
|
catch (OperationCanceledException)
|
||||||
@ -377,6 +377,15 @@ namespace PettingZoo.UI.Main
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void ActivateTab(ITab tab)
|
||||||
|
{
|
||||||
|
if (undockedTabs.TryGetValue(tab, out var window))
|
||||||
|
window.Activate();
|
||||||
|
else if (Tabs.Contains(tab))
|
||||||
|
ActiveTab = tab;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public void DockTab(ITab tab)
|
public void DockTab(ITab tab)
|
||||||
{
|
{
|
||||||
if (undockedTabs.Remove(tab, out var tabHostWindow))
|
if (undockedTabs.Remove(tab, out var tabHostWindow))
|
||||||
|
@ -2,13 +2,10 @@
|
|||||||
|
|
||||||
namespace PettingZoo.UI.Tab
|
namespace PettingZoo.UI.Tab
|
||||||
{
|
{
|
||||||
// Passing the closeTabCommand is necessary because I haven't figured out how to bind the main window's
|
|
||||||
// context menu items for the tab to the main window's datacontext yet. RelativeSource doesn't seem to work
|
|
||||||
// because the popup is it's own window. Refactor if a better solution is found.
|
|
||||||
|
|
||||||
public interface ITabFactory
|
public interface ITabFactory
|
||||||
{
|
{
|
||||||
ITab CreateSubscriberTab(IConnection? connection, ISubscriber subscriber);
|
void CreateSubscriberTab(IConnection? connection, ISubscriber subscriber);
|
||||||
ITab CreatePublisherTab(IConnection connection, ReceivedMessageInfo? fromReceivedMessage = null);
|
string CreateReplySubscriberTab(IConnection connection);
|
||||||
|
void CreatePublisherTab(IConnection connection, ReceivedMessageInfo? fromReceivedMessage = null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
public interface ITabHost
|
public interface ITabHost
|
||||||
{
|
{
|
||||||
void AddTab(ITab tab);
|
void AddTab(ITab tab);
|
||||||
|
void ActivateTab(ITab tab);
|
||||||
|
|
||||||
void DockTab(ITab tab);
|
void DockTab(ITab tab);
|
||||||
void UndockedTabClosed(ITab tab);
|
void UndockedTabClosed(ITab tab);
|
||||||
|
@ -5,6 +5,6 @@
|
|||||||
string Exchange { get; }
|
string Exchange { get; }
|
||||||
string RoutingKey { get; }
|
string RoutingKey { get; }
|
||||||
|
|
||||||
string? GetReplyTo();
|
string? GetReplyTo(ref string? correlationId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,6 @@ namespace PettingZoo.UI.Tab.Publisher
|
|||||||
private readonly IConnection connection;
|
private readonly IConnection connection;
|
||||||
private readonly IExampleGenerator exampleGenerator;
|
private readonly IExampleGenerator exampleGenerator;
|
||||||
private readonly ITabFactory tabFactory;
|
private readonly ITabFactory tabFactory;
|
||||||
private readonly ITabHostProvider tabHostProvider;
|
|
||||||
|
|
||||||
private bool sendToExchange = true;
|
private bool sendToExchange = true;
|
||||||
private string exchange = "";
|
private string exchange = "";
|
||||||
@ -156,12 +155,11 @@ namespace PettingZoo.UI.Tab.Publisher
|
|||||||
string IPublishDestination.RoutingKey => SendToExchange ? RoutingKey : Queue;
|
string IPublishDestination.RoutingKey => SendToExchange ? RoutingKey : Queue;
|
||||||
|
|
||||||
|
|
||||||
public PublisherViewModel(ITabHostProvider tabHostProvider, ITabFactory tabFactory, IConnection connection, IExampleGenerator exampleGenerator, ReceivedMessageInfo? fromReceivedMessage = null)
|
public PublisherViewModel(ITabFactory tabFactory, IConnection connection, IExampleGenerator exampleGenerator, ReceivedMessageInfo? fromReceivedMessage = null)
|
||||||
{
|
{
|
||||||
this.connection = connection;
|
this.connection = connection;
|
||||||
this.exampleGenerator = exampleGenerator;
|
this.exampleGenerator = exampleGenerator;
|
||||||
this.tabFactory = tabFactory;
|
this.tabFactory = tabFactory;
|
||||||
this.tabHostProvider = tabHostProvider;
|
|
||||||
|
|
||||||
publishCommand = new DelegateCommand(PublishExecute, PublishCanExecute);
|
publishCommand = new DelegateCommand(PublishExecute, PublishCanExecute);
|
||||||
|
|
||||||
@ -280,17 +278,13 @@ namespace PettingZoo.UI.Tab.Publisher
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public string? GetReplyTo()
|
public string? GetReplyTo(ref string? correlationId)
|
||||||
{
|
{
|
||||||
if (ReplyToSpecified)
|
if (ReplyToSpecified)
|
||||||
return string.IsNullOrEmpty(ReplyTo) ? null : ReplyTo;
|
return string.IsNullOrEmpty(ReplyTo) ? null : ReplyTo;
|
||||||
|
|
||||||
var subscriber = connection.Subscribe();
|
correlationId = SendToExchange ? RoutingKey : Queue;
|
||||||
var tab = tabFactory.CreateSubscriberTab(connection, subscriber);
|
return tabFactory.CreateReplySubscriberTab(connection);
|
||||||
tabHostProvider.Instance.AddTab(tab);
|
|
||||||
|
|
||||||
subscriber.Start();
|
|
||||||
return subscriber.QueueName;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -305,7 +299,7 @@ namespace PettingZoo.UI.Tab.Publisher
|
|||||||
|
|
||||||
public class DesignTimePublisherViewModel : PublisherViewModel
|
public class DesignTimePublisherViewModel : PublisherViewModel
|
||||||
{
|
{
|
||||||
public DesignTimePublisherViewModel() : base(null!, null!, null!, null!)
|
public DesignTimePublisherViewModel() : base(null!, null!, null!)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -244,6 +244,8 @@ namespace PettingZoo.UI.Tab.Publisher
|
|||||||
|
|
||||||
|
|
||||||
var headers = Headers.Where(h => h.IsValid()).ToDictionary(h => h.Key, h => h.Value);
|
var headers = Headers.Where(h => h.IsValid()).ToDictionary(h => h.Key, h => h.Value);
|
||||||
|
var publishCorrelationId = NullIfEmpty(CorrelationId);
|
||||||
|
var replyTo = publishDestination.GetReplyTo(ref publishCorrelationId);
|
||||||
|
|
||||||
connection.Publish(new PublishMessageInfo(
|
connection.Publish(new PublishMessageInfo(
|
||||||
publishDestination.Exchange,
|
publishDestination.Exchange,
|
||||||
@ -254,12 +256,12 @@ namespace PettingZoo.UI.Tab.Publisher
|
|||||||
AppId = NullIfEmpty(AppId),
|
AppId = NullIfEmpty(AppId),
|
||||||
ContentEncoding = NullIfEmpty(ContentEncoding),
|
ContentEncoding = NullIfEmpty(ContentEncoding),
|
||||||
ContentType = NullIfEmpty(ContentType),
|
ContentType = NullIfEmpty(ContentType),
|
||||||
CorrelationId = NullIfEmpty(CorrelationId),
|
CorrelationId = publishCorrelationId,
|
||||||
DeliveryMode = deliveryMode,
|
DeliveryMode = deliveryMode,
|
||||||
Expiration = NullIfEmpty(Expiration),
|
Expiration = NullIfEmpty(Expiration),
|
||||||
MessageId = NullIfEmpty(MessageId),
|
MessageId = NullIfEmpty(MessageId),
|
||||||
Priority = priorityValue,
|
Priority = priorityValue,
|
||||||
ReplyTo = publishDestination.GetReplyTo(),
|
ReplyTo = replyTo,
|
||||||
Timestamp = timestampValue,
|
Timestamp = timestampValue,
|
||||||
Type = NullIfEmpty(TypeProperty),
|
Type = NullIfEmpty(TypeProperty),
|
||||||
UserId = NullIfEmpty(UserId)
|
UserId = NullIfEmpty(UserId)
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Input;
|
using System.Windows.Input;
|
||||||
using System.Windows.Threading;
|
|
||||||
using PettingZoo.Core.Connection;
|
using PettingZoo.Core.Connection;
|
||||||
using PettingZoo.Core.Generator;
|
using PettingZoo.Core.Generator;
|
||||||
using PettingZoo.Core.Validation;
|
using PettingZoo.Core.Validation;
|
||||||
@ -151,7 +150,10 @@ namespace PettingZoo.UI.Tab.Publisher
|
|||||||
{
|
{
|
||||||
return string.IsNullOrEmpty(value) ? null : value;
|
return string.IsNullOrEmpty(value) ? null : value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var publishCorrelationId = NullIfEmpty(CorrelationId);
|
||||||
|
var replyTo = publishDestination.GetReplyTo(ref publishCorrelationId);
|
||||||
|
|
||||||
connection.Publish(new PublishMessageInfo(
|
connection.Publish(new PublishMessageInfo(
|
||||||
publishDestination.Exchange,
|
publishDestination.Exchange,
|
||||||
publishDestination.RoutingKey,
|
publishDestination.RoutingKey,
|
||||||
@ -162,9 +164,9 @@ namespace PettingZoo.UI.Tab.Publisher
|
|||||||
})
|
})
|
||||||
{
|
{
|
||||||
ContentType = @"application/json",
|
ContentType = @"application/json",
|
||||||
CorrelationId = NullIfEmpty(CorrelationId),
|
CorrelationId = publishCorrelationId,
|
||||||
DeliveryMode = MessageDeliveryMode.Persistent,
|
DeliveryMode = MessageDeliveryMode.Persistent,
|
||||||
ReplyTo = publishDestination.GetReplyTo()
|
ReplyTo = replyTo
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,23 +0,0 @@
|
|||||||
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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -13,9 +13,6 @@
|
|||||||
d:DesignWidth="800"
|
d:DesignWidth="800"
|
||||||
d:DataContext="{d:DesignInstance res:DesignTimeSubscriberViewModel, IsDesignTimeCreatable=True}"
|
d:DataContext="{d:DesignInstance res:DesignTimeSubscriberViewModel, IsDesignTimeCreatable=True}"
|
||||||
Background="White">
|
Background="White">
|
||||||
<UserControl.Resources>
|
|
||||||
<res:SameMessageVisibilityConverter x:Key="SameMessageVisibilityConverter" />
|
|
||||||
</UserControl.Resources>
|
|
||||||
<Grid Margin="4">
|
<Grid Margin="4">
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition Width="*" />
|
<ColumnDefinition Width="*" />
|
||||||
@ -64,7 +61,10 @@
|
|||||||
</Grid.ColumnDefinitions>
|
</Grid.ColumnDefinitions>
|
||||||
|
|
||||||
<TextBlock Grid.Column="0" Text="{Binding ReceivedTimestamp, StringFormat=g}" Style="{StaticResource Timestamp}" />
|
<TextBlock Grid.Column="0" Text="{Binding ReceivedTimestamp, StringFormat=g}" Style="{StaticResource Timestamp}" />
|
||||||
<TextBlock Grid.Column="1" Text="{Binding RoutingKey}" Style="{StaticResource RoutingKey}" />
|
<!-- ReSharper disable Xaml.BindingWithContextNotResolved -->
|
||||||
|
<TextBlock Grid.Column="1" Text="{Binding RoutingKey}" Style="{StaticResource RoutingKey}" Visibility="{Binding Data.StandardTabVisibility, Source={StaticResource ContextMenuProxy}}" />
|
||||||
|
<TextBlock Grid.Column="1" Text="{Binding Properties.CorrelationId}" Style="{StaticResource RoutingKey}" Visibility="{Binding Data.ReplyToTabVisibility, Source={StaticResource ContextMenuProxy}}" />
|
||||||
|
<!-- ReSharper restore Xaml.BindingWithContextNotResolved -->
|
||||||
|
|
||||||
<Grid.ContextMenu>
|
<Grid.ContextMenu>
|
||||||
<ContextMenu>
|
<ContextMenu>
|
||||||
|
@ -21,10 +21,9 @@ using Timer = System.Threading.Timer;
|
|||||||
|
|
||||||
namespace PettingZoo.UI.Tab.Subscriber
|
namespace PettingZoo.UI.Tab.Subscriber
|
||||||
{
|
{
|
||||||
public class SubscriberViewModel : BaseViewModel, ITabToolbarCommands, ITabActivate
|
public class SubscriberViewModel : BaseViewModel, IDisposable, ITabToolbarCommands, ITabActivate
|
||||||
{
|
{
|
||||||
private readonly ILogger logger;
|
private readonly ILogger logger;
|
||||||
private readonly ITabHostProvider tabHostProvider;
|
|
||||||
private readonly ITabFactory tabFactory;
|
private readonly ITabFactory tabFactory;
|
||||||
private readonly IConnection? connection;
|
private readonly IConnection? connection;
|
||||||
private readonly ISubscriber subscriber;
|
private readonly ISubscriber subscriber;
|
||||||
@ -76,16 +75,43 @@ namespace PettingZoo.UI.Tab.Subscriber
|
|||||||
set => SetField(ref selectedMessageProperties, value);
|
set => SetField(ref selectedMessageProperties, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Title =>
|
public string Title
|
||||||
(subscriber.Exchange != null ? $"{subscriber.Exchange} - {subscriber.RoutingKey}" : $"{subscriber.QueueName}") +
|
{
|
||||||
(tabActive || unreadCount == 0 ? "" : $" ({unreadCount})");
|
get
|
||||||
|
{
|
||||||
|
var title = new StringBuilder();
|
||||||
|
|
||||||
|
if (IsReplyTab)
|
||||||
|
title.Append(SubscriberViewStrings.ReplyTabTitle);
|
||||||
|
else if (subscriber.Exchange != null)
|
||||||
|
title.Append(subscriber.Exchange).Append(" - ").Append(subscriber.RoutingKey);
|
||||||
|
else
|
||||||
|
title.Append(subscriber.QueueName);
|
||||||
|
|
||||||
|
if (!tabActive && unreadCount > 0)
|
||||||
|
title.Append(" (").Append(unreadCount).Append(')');
|
||||||
|
|
||||||
|
return title.ToString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public IEnumerable<TabToolbarCommand> ToolbarCommands => toolbarCommands;
|
public IEnumerable<TabToolbarCommand> ToolbarCommands => toolbarCommands;
|
||||||
|
|
||||||
|
|
||||||
public SubscriberViewModel(ILogger logger, ITabHostProvider tabHostProvider, ITabFactory tabFactory, IConnection? connection, ISubscriber subscriber, IExportImportFormatProvider exportImportFormatProvider)
|
public bool IsReplyTab { get; }
|
||||||
|
|
||||||
|
// ReSharper disable UnusedMember.Global - used via BindingProxy
|
||||||
|
public Visibility StandardTabVisibility => !IsReplyTab ? Visibility.Visible : Visibility.Collapsed;
|
||||||
|
public Visibility ReplyTabVisibility => IsReplyTab ? Visibility.Visible : Visibility.Collapsed;
|
||||||
|
// ReSharper restore UnusedMember.Global
|
||||||
|
|
||||||
|
|
||||||
|
public SubscriberViewModel(ILogger logger, ITabFactory tabFactory, IConnection? connection, ISubscriber subscriber, IExportImportFormatProvider exportImportFormatProvider, bool isReplyTab)
|
||||||
{
|
{
|
||||||
|
IsReplyTab = isReplyTab;
|
||||||
|
|
||||||
this.logger = logger;
|
this.logger = logger;
|
||||||
this.tabHostProvider = tabHostProvider;
|
|
||||||
this.tabFactory = tabFactory;
|
this.tabFactory = tabFactory;
|
||||||
this.connection = connection;
|
this.connection = connection;
|
||||||
this.subscriber = subscriber;
|
this.subscriber = subscriber;
|
||||||
@ -111,6 +137,15 @@ namespace PettingZoo.UI.Tab.Subscriber
|
|||||||
subscriber.Start();
|
subscriber.Start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
GC.SuppressFinalize(this);
|
||||||
|
newMessageTimer?.Dispose();
|
||||||
|
subscriber.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private void ClearExecute()
|
private void ClearExecute()
|
||||||
{
|
{
|
||||||
Messages.Clear();
|
Messages.Clear();
|
||||||
@ -222,8 +257,7 @@ namespace PettingZoo.UI.Tab.Subscriber
|
|||||||
if (connection == null)
|
if (connection == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var publisherTab = tabFactory.CreatePublisherTab(connection, SelectedMessage);
|
tabFactory.CreatePublisherTab(connection, SelectedMessage);
|
||||||
tabHostProvider.Instance.AddTab(publisherTab);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -320,7 +354,7 @@ namespace PettingZoo.UI.Tab.Subscriber
|
|||||||
|
|
||||||
public class DesignTimeSubscriberViewModel : SubscriberViewModel
|
public class DesignTimeSubscriberViewModel : SubscriberViewModel
|
||||||
{
|
{
|
||||||
public DesignTimeSubscriberViewModel() : base(null!, null!, null!, null!, new DesignTimeSubscriber(), null!)
|
public DesignTimeSubscriberViewModel() : base(null!, null!, null!, new DesignTimeSubscriber(), null!, false)
|
||||||
{
|
{
|
||||||
for (var i = 1; i <= 5; i++)
|
for (var i = 1; i <= 5; i++)
|
||||||
(i > 2 ? UnreadMessages : Messages).Add(new ReceivedMessageInfo(
|
(i > 2 ? UnreadMessages : Messages).Add(new ReceivedMessageInfo(
|
||||||
@ -340,9 +374,9 @@ namespace PettingZoo.UI.Tab.Subscriber
|
|||||||
|
|
||||||
private class DesignTimeSubscriber : ISubscriber
|
private class DesignTimeSubscriber : ISubscriber
|
||||||
{
|
{
|
||||||
public ValueTask DisposeAsync()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
return default;
|
GC.SuppressFinalize(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -185,5 +185,14 @@ namespace PettingZoo.UI.Tab.Subscriber {
|
|||||||
return ResourceManager.GetString("PropertyValue", resourceCulture);
|
return ResourceManager.GetString("PropertyValue", resourceCulture);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Replies.
|
||||||
|
/// </summary>
|
||||||
|
public static string ReplyTabTitle {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("ReplyTabTitle", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -159,4 +159,7 @@
|
|||||||
<data name="PropertyValue" xml:space="preserve">
|
<data name="PropertyValue" xml:space="preserve">
|
||||||
<value>Value</value>
|
<value>Value</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="ReplyTabTitle" xml:space="preserve">
|
||||||
|
<value>Replies</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
@ -1,4 +1,5 @@
|
|||||||
using System.Collections.Generic;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
@ -13,6 +14,7 @@ namespace PettingZoo.UI.Tab.Undocked
|
|||||||
private readonly ITabHostProvider tabHostProvider;
|
private readonly ITabHostProvider tabHostProvider;
|
||||||
private readonly ITab tab;
|
private readonly ITab tab;
|
||||||
private readonly DelegateCommand dockCommand;
|
private readonly DelegateCommand dockCommand;
|
||||||
|
private bool docked;
|
||||||
|
|
||||||
|
|
||||||
public string Title => tab.Title;
|
public string Title => tab.Title;
|
||||||
@ -43,13 +45,18 @@ namespace PettingZoo.UI.Tab.Undocked
|
|||||||
|
|
||||||
private void DockCommandExecute()
|
private void DockCommandExecute()
|
||||||
{
|
{
|
||||||
|
docked = true;
|
||||||
tabHostProvider.Instance.DockTab(tab);
|
tabHostProvider.Instance.DockTab(tab);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void WindowClosed()
|
public void WindowClosed()
|
||||||
{
|
{
|
||||||
|
if (docked)
|
||||||
|
return;
|
||||||
|
|
||||||
tabHostProvider.Instance.UndockedTabClosed(tab);
|
tabHostProvider.Instance.UndockedTabClosed(tab);
|
||||||
|
(tab as IDisposable)?.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
using System;
|
using System.Windows;
|
||||||
using System.Windows;
|
|
||||||
using System.Windows.Controls;
|
using System.Windows.Controls;
|
||||||
using System.Windows.Threading;
|
|
||||||
|
|
||||||
namespace PettingZoo.UI.Tab.Undocked
|
namespace PettingZoo.UI.Tab.Undocked
|
||||||
{
|
{
|
||||||
|
@ -8,7 +8,7 @@ using System.Windows.Controls;
|
|||||||
|
|
||||||
namespace PettingZoo.UI.Tab
|
namespace PettingZoo.UI.Tab
|
||||||
{
|
{
|
||||||
public class ViewTab<TView, TViewModel> : ITab, ITabToolbarCommands, ITabActivate, ITabHostWindowNotify where TView : ContentControl where TViewModel : INotifyPropertyChanged
|
public class ViewTab<TView, TViewModel> : IDisposable, ITab, ITabToolbarCommands, ITabActivate, ITabHostWindowNotify where TView : ContentControl where TViewModel : INotifyPropertyChanged
|
||||||
{
|
{
|
||||||
public string Title => getTitle(viewModel);
|
public string Title => getTitle(viewModel);
|
||||||
public ContentControl Content { get; }
|
public ContentControl Content { get; }
|
||||||
@ -63,5 +63,12 @@ namespace PettingZoo.UI.Tab
|
|||||||
{
|
{
|
||||||
(viewModel as ITabHostWindowNotify)?.HostWindowChanged(hostWindow);
|
(viewModel as ITabHostWindowNotify)?.HostWindowChanged(hostWindow);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
GC.SuppressFinalize(this);
|
||||||
|
(viewModel as IDisposable)?.Dispose();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
using PettingZoo.Core.Connection;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using PettingZoo.Core.Connection;
|
||||||
using PettingZoo.Core.ExportImport;
|
using PettingZoo.Core.ExportImport;
|
||||||
using PettingZoo.Core.Generator;
|
using PettingZoo.Core.Generator;
|
||||||
using PettingZoo.UI.Tab.Publisher;
|
using PettingZoo.UI.Tab.Publisher;
|
||||||
@ -14,6 +16,10 @@ namespace PettingZoo.UI.Tab
|
|||||||
private readonly IExampleGenerator exampleGenerator;
|
private readonly IExampleGenerator exampleGenerator;
|
||||||
private readonly IExportImportFormatProvider exportImportFormatProvider;
|
private readonly IExportImportFormatProvider exportImportFormatProvider;
|
||||||
|
|
||||||
|
// Not the cleanest way, but this factory itself can't be singleton without (justifyable) upsetting SimpleInjector
|
||||||
|
private static ISubscriber? replySubscriber;
|
||||||
|
private static ITab? replySubscriberTab;
|
||||||
|
|
||||||
|
|
||||||
public ViewTabFactory(ILogger logger, ITabHostProvider tabHostProvider, IExampleGenerator exampleGenerator, IExportImportFormatProvider exportImportFormatProvider)
|
public ViewTabFactory(ILogger logger, ITabHostProvider tabHostProvider, IExampleGenerator exampleGenerator, IExportImportFormatProvider exportImportFormatProvider)
|
||||||
{
|
{
|
||||||
@ -24,23 +30,101 @@ namespace PettingZoo.UI.Tab
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public ITab CreateSubscriberTab(IConnection? connection, ISubscriber subscriber)
|
public void CreateSubscriberTab(IConnection? connection, ISubscriber subscriber)
|
||||||
{
|
{
|
||||||
var viewModel = new SubscriberViewModel(logger, tabHostProvider, this, connection, subscriber, exportImportFormatProvider);
|
InternalCreateSubscriberTab(connection, subscriber, false);
|
||||||
return new ViewTab<SubscriberView, SubscriberViewModel>(
|
|
||||||
new SubscriberView(viewModel),
|
|
||||||
viewModel,
|
|
||||||
vm => vm.Title);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public ITab CreatePublisherTab(IConnection connection, ReceivedMessageInfo? fromReceivedMessage = null)
|
public string CreateReplySubscriberTab(IConnection connection)
|
||||||
{
|
{
|
||||||
var viewModel = new PublisherViewModel(tabHostProvider, this, connection, exampleGenerator, fromReceivedMessage);
|
if (replySubscriber?.QueueName != null && replySubscriberTab != null)
|
||||||
return new ViewTab<PublisherView, PublisherViewModel>(
|
{
|
||||||
|
tabHostProvider.Instance.ActivateTab(replySubscriberTab);
|
||||||
|
return replySubscriber.QueueName;
|
||||||
|
}
|
||||||
|
|
||||||
|
replySubscriber = new SubscriberDecorator(connection.Subscribe(), () =>
|
||||||
|
{
|
||||||
|
replySubscriber = null;
|
||||||
|
replySubscriberTab = null;
|
||||||
|
});
|
||||||
|
|
||||||
|
replySubscriber.Start();
|
||||||
|
|
||||||
|
replySubscriberTab = InternalCreateSubscriberTab(connection, replySubscriber, true);
|
||||||
|
return replySubscriber.QueueName!;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void CreatePublisherTab(IConnection connection, ReceivedMessageInfo? fromReceivedMessage = null)
|
||||||
|
{
|
||||||
|
var viewModel = new PublisherViewModel(this, connection, exampleGenerator, fromReceivedMessage);
|
||||||
|
var tab = new ViewTab<PublisherView, PublisherViewModel>(
|
||||||
new PublisherView(viewModel),
|
new PublisherView(viewModel),
|
||||||
viewModel,
|
viewModel,
|
||||||
vm => vm.Title);
|
vm => vm.Title);
|
||||||
|
|
||||||
|
tabHostProvider.Instance.AddTab(tab);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private ITab InternalCreateSubscriberTab(IConnection? connection, ISubscriber subscriber, bool isReplyTab)
|
||||||
|
{
|
||||||
|
var viewModel = new SubscriberViewModel(logger, this, connection, subscriber, exportImportFormatProvider, isReplyTab);
|
||||||
|
var tab = new ViewTab<SubscriberView, SubscriberViewModel>(
|
||||||
|
new SubscriberView(viewModel),
|
||||||
|
viewModel,
|
||||||
|
vm => vm.Title);
|
||||||
|
|
||||||
|
tabHostProvider.Instance.AddTab(tab);
|
||||||
|
return tab;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private class SubscriberDecorator : ISubscriber
|
||||||
|
{
|
||||||
|
private readonly ISubscriber decoratedSubscriber;
|
||||||
|
private readonly Action onDispose;
|
||||||
|
|
||||||
|
|
||||||
|
public string? QueueName => decoratedSubscriber.QueueName;
|
||||||
|
public string? Exchange => decoratedSubscriber.Exchange;
|
||||||
|
public string? RoutingKey => decoratedSubscriber.RoutingKey;
|
||||||
|
|
||||||
|
public event EventHandler<MessageReceivedEventArgs>? MessageReceived;
|
||||||
|
|
||||||
|
|
||||||
|
public SubscriberDecorator(ISubscriber decoratedSubscriber, Action onDispose)
|
||||||
|
{
|
||||||
|
this.decoratedSubscriber = decoratedSubscriber;
|
||||||
|
this.onDispose = onDispose;
|
||||||
|
|
||||||
|
decoratedSubscriber.MessageReceived += (sender, args) =>
|
||||||
|
{
|
||||||
|
MessageReceived?.Invoke(sender, args);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
GC.SuppressFinalize(this);
|
||||||
|
decoratedSubscriber.Dispose();
|
||||||
|
onDispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public IEnumerable<ReceivedMessageInfo> GetInitialMessages()
|
||||||
|
{
|
||||||
|
return decoratedSubscriber.GetInitialMessages();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Start()
|
||||||
|
{
|
||||||
|
decoratedSubscriber.Start();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user