Implemented raw publishing
This commit is contained in:
parent
503507422d
commit
229fc9415d
@ -8,7 +8,7 @@ namespace PettingZoo.Core.Connection
|
||||
event EventHandler<StatusChangedEventArgs> StatusChanged;
|
||||
|
||||
ISubscriber Subscribe(string exchange, string routingKey);
|
||||
Task Publish(MessageInfo messageInfo);
|
||||
Task Publish(PublishMessageInfo messageInfo);
|
||||
}
|
||||
|
||||
|
||||
|
@ -15,10 +15,10 @@ namespace PettingZoo.Core.Connection
|
||||
|
||||
public class MessageReceivedEventArgs : EventArgs
|
||||
{
|
||||
public MessageInfo MessageInfo { get; }
|
||||
public ReceivedMessageInfo MessageInfo { get; }
|
||||
|
||||
|
||||
public MessageReceivedEventArgs(MessageInfo messageInfo)
|
||||
public MessageReceivedEventArgs(ReceivedMessageInfo messageInfo)
|
||||
{
|
||||
MessageInfo = messageInfo;
|
||||
}
|
||||
|
@ -3,21 +3,72 @@ using System.Collections.Generic;
|
||||
|
||||
namespace PettingZoo.Core.Connection
|
||||
{
|
||||
public class MessageInfo
|
||||
public class BaseMessageInfo
|
||||
{
|
||||
public DateTime Timestamp { get; }
|
||||
public string Exchange { get; }
|
||||
public string RoutingKey { get; }
|
||||
public byte[] Body { get; }
|
||||
public IDictionary<string, string> Properties { get; }
|
||||
public MessageProperties Properties { get; }
|
||||
|
||||
public MessageInfo(string exchange, string routingKey, byte[] body, IDictionary<string, string> properties, DateTime timestamp)
|
||||
public BaseMessageInfo(string exchange, string routingKey, byte[] body, MessageProperties properties)
|
||||
{
|
||||
Exchange = exchange;
|
||||
RoutingKey = routingKey;
|
||||
Body = body;
|
||||
Properties = properties;
|
||||
Timestamp = timestamp;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public class ReceivedMessageInfo : BaseMessageInfo
|
||||
{
|
||||
public DateTime ReceivedTimestamp { get; }
|
||||
|
||||
public ReceivedMessageInfo(string exchange, string routingKey, byte[] body, MessageProperties properties, DateTime receivedTimestamp)
|
||||
: base(exchange, routingKey, body, properties)
|
||||
{
|
||||
ReceivedTimestamp = receivedTimestamp;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public class PublishMessageInfo : BaseMessageInfo
|
||||
{
|
||||
public PublishMessageInfo(string exchange, string routingKey, byte[] body, MessageProperties properties)
|
||||
: base(exchange, routingKey, body, properties)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public enum MessageDeliveryMode
|
||||
{
|
||||
NonPersistent = 1,
|
||||
Persistent = 2
|
||||
}
|
||||
|
||||
|
||||
public class MessageProperties
|
||||
{
|
||||
private static readonly IReadOnlyDictionary<string, string> EmptyHeaders = new Dictionary<string, string>();
|
||||
|
||||
public MessageProperties(IReadOnlyDictionary<string, string>? headers)
|
||||
{
|
||||
Headers = headers ?? EmptyHeaders;
|
||||
}
|
||||
|
||||
public string? AppId { get; init; }
|
||||
public string? ContentEncoding { get; init; }
|
||||
public string? ContentType { get; init; }
|
||||
public string? CorrelationId { get; init; }
|
||||
public MessageDeliveryMode? DeliveryMode { get; init; }
|
||||
public string? Expiration { get; init; }
|
||||
public IReadOnlyDictionary<string, string> Headers { get; }
|
||||
public string? MessageId { get; init; }
|
||||
public byte? Priority { get; init; }
|
||||
public string? ReplyTo { get; init; }
|
||||
public DateTime? Timestamp { get; init; }
|
||||
public string? Type { get; init; }
|
||||
public string? UserId { get; init; }
|
||||
}
|
||||
}
|
||||
|
@ -9,4 +9,19 @@
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Update="Rendering\MessagePropertiesRendererStrings.Designer.cs">
|
||||
<DesignTime>True</DesignTime>
|
||||
<AutoGen>True</AutoGen>
|
||||
<DependentUpon>MessagePropertiesRendererStrings.resx</DependentUpon>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Update="Rendering\MessagePropertiesRendererStrings.resx">
|
||||
<Generator>ResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>MessagePropertiesRendererStrings.Designer.cs</LastGenOutput>
|
||||
</EmbeddedResource>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
@ -13,9 +13,9 @@ namespace PettingZoo.Core.Rendering
|
||||
};
|
||||
|
||||
|
||||
public static string Render(byte[] body, string contentType = "")
|
||||
public static string Render(byte[] body, string? contentType)
|
||||
{
|
||||
return ContentTypeHandlers.TryGetValue(contentType, out var handler)
|
||||
return (contentType != null) && ContentTypeHandlers.TryGetValue(contentType, out var handler)
|
||||
? handler(body)
|
||||
: Encoding.UTF8.GetString(body);
|
||||
|
||||
|
60
PettingZoo.Core/Rendering/MessagePropertiesRenderer.cs
Normal file
60
PettingZoo.Core/Rendering/MessagePropertiesRenderer.cs
Normal file
@ -0,0 +1,60 @@
|
||||
using System.Collections.Generic;
|
||||
using PettingZoo.Core.Connection;
|
||||
|
||||
namespace PettingZoo.Core.Rendering
|
||||
{
|
||||
public class MessagePropertiesRenderer
|
||||
{
|
||||
public static IDictionary<string, string> Render(MessageProperties properties)
|
||||
{
|
||||
var result = new Dictionary<string, string>();
|
||||
|
||||
if (properties.AppId != null)
|
||||
result.Add(MessagePropertiesRendererStrings.AppId, properties.AppId);
|
||||
|
||||
if (properties.ContentEncoding != null)
|
||||
result.Add(MessagePropertiesRendererStrings.ContentEncoding, properties.ContentEncoding);
|
||||
|
||||
if (properties.ContentType != null)
|
||||
result.Add(MessagePropertiesRendererStrings.ContentType, properties.ContentType);
|
||||
|
||||
if (properties.CorrelationId != null)
|
||||
result.Add(MessagePropertiesRendererStrings.CorrelationId, properties.CorrelationId);
|
||||
|
||||
if (properties.DeliveryMode != null)
|
||||
result.Add(MessagePropertiesRendererStrings.DeliveryMode,
|
||||
properties.DeliveryMode == MessageDeliveryMode.Persistent
|
||||
? MessagePropertiesRendererStrings.DeliveryModePersistent
|
||||
: MessagePropertiesRendererStrings.DeliveryModeNonPersistent);
|
||||
|
||||
if (properties.Expiration != null)
|
||||
result.Add(MessagePropertiesRendererStrings.Expiration, properties.Expiration);
|
||||
|
||||
if (properties.MessageId != null)
|
||||
result.Add(MessagePropertiesRendererStrings.MessageId, properties.MessageId);
|
||||
|
||||
if (properties.Priority != null)
|
||||
result.Add(MessagePropertiesRendererStrings.Priority, properties.Priority.Value.ToString());
|
||||
|
||||
if (properties.ReplyTo != null)
|
||||
result.Add(MessagePropertiesRendererStrings.ReplyTo, properties.ReplyTo);
|
||||
|
||||
if (properties.Timestamp != null)
|
||||
result.Add(MessagePropertiesRendererStrings.Timestamp, properties.Timestamp.Value.ToString("G"));
|
||||
|
||||
if (properties.Type != null)
|
||||
result.Add(MessagePropertiesRendererStrings.Type, properties.Type);
|
||||
|
||||
if (properties.UserId != null)
|
||||
result.Add(MessagePropertiesRendererStrings.UserId, properties.UserId);
|
||||
|
||||
foreach (var (key, value) in properties.Headers)
|
||||
{
|
||||
if (!result.TryAdd(key, value))
|
||||
result.TryAdd(MessagePropertiesRendererStrings.HeaderPrefix + key, value);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
198
PettingZoo.Core/Rendering/MessagePropertiesRendererStrings.Designer.cs
generated
Normal file
198
PettingZoo.Core/Rendering/MessagePropertiesRendererStrings.Designer.cs
generated
Normal file
@ -0,0 +1,198 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by a tool.
|
||||
// Runtime Version:4.0.30319.42000
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace PettingZoo.Core.Rendering {
|
||||
using System;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// A strongly-typed resource class, for looking up localized strings, etc.
|
||||
/// </summary>
|
||||
// This class was auto-generated by the StronglyTypedResourceBuilder
|
||||
// class via a tool like ResGen or Visual Studio.
|
||||
// To add or remove a member, edit your .ResX file then rerun ResGen
|
||||
// with the /str option, or rebuild your VS project.
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
internal class MessagePropertiesRendererStrings {
|
||||
|
||||
private static global::System.Resources.ResourceManager resourceMan;
|
||||
|
||||
private static global::System.Globalization.CultureInfo resourceCulture;
|
||||
|
||||
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
||||
internal MessagePropertiesRendererStrings() {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the cached ResourceManager instance used by this class.
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
internal static global::System.Resources.ResourceManager ResourceManager {
|
||||
get {
|
||||
if (object.ReferenceEquals(resourceMan, null)) {
|
||||
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("PettingZoo.Core.Rendering.MessagePropertiesRendererStrings", typeof(MessagePropertiesRendererStrings).Assembly);
|
||||
resourceMan = temp;
|
||||
}
|
||||
return resourceMan;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Overrides the current thread's CurrentUICulture property for all
|
||||
/// resource lookups using this strongly typed resource class.
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
internal static global::System.Globalization.CultureInfo Culture {
|
||||
get {
|
||||
return resourceCulture;
|
||||
}
|
||||
set {
|
||||
resourceCulture = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to App ID.
|
||||
/// </summary>
|
||||
internal static string AppId {
|
||||
get {
|
||||
return ResourceManager.GetString("AppId", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Content encoding.
|
||||
/// </summary>
|
||||
internal static string ContentEncoding {
|
||||
get {
|
||||
return ResourceManager.GetString("ContentEncoding", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Content type.
|
||||
/// </summary>
|
||||
internal static string ContentType {
|
||||
get {
|
||||
return ResourceManager.GetString("ContentType", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Correlation ID.
|
||||
/// </summary>
|
||||
internal static string CorrelationId {
|
||||
get {
|
||||
return ResourceManager.GetString("CorrelationId", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Delivery mode.
|
||||
/// </summary>
|
||||
internal static string DeliveryMode {
|
||||
get {
|
||||
return ResourceManager.GetString("DeliveryMode", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Transient (1).
|
||||
/// </summary>
|
||||
internal static string DeliveryModeNonPersistent {
|
||||
get {
|
||||
return ResourceManager.GetString("DeliveryModeNonPersistent", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Persistent (2).
|
||||
/// </summary>
|
||||
internal static string DeliveryModePersistent {
|
||||
get {
|
||||
return ResourceManager.GetString("DeliveryModePersistent", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Expiration.
|
||||
/// </summary>
|
||||
internal static string Expiration {
|
||||
get {
|
||||
return ResourceManager.GetString("Expiration", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Header: .
|
||||
/// </summary>
|
||||
internal static string HeaderPrefix {
|
||||
get {
|
||||
return ResourceManager.GetString("HeaderPrefix", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Message ID.
|
||||
/// </summary>
|
||||
internal static string MessageId {
|
||||
get {
|
||||
return ResourceManager.GetString("MessageId", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Priority.
|
||||
/// </summary>
|
||||
internal static string Priority {
|
||||
get {
|
||||
return ResourceManager.GetString("Priority", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Reply To.
|
||||
/// </summary>
|
||||
internal static string ReplyTo {
|
||||
get {
|
||||
return ResourceManager.GetString("ReplyTo", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Timestamp.
|
||||
/// </summary>
|
||||
internal static string Timestamp {
|
||||
get {
|
||||
return ResourceManager.GetString("Timestamp", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Type.
|
||||
/// </summary>
|
||||
internal static string Type {
|
||||
get {
|
||||
return ResourceManager.GetString("Type", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to User ID.
|
||||
/// </summary>
|
||||
internal static string UserId {
|
||||
get {
|
||||
return ResourceManager.GetString("UserId", resourceCulture);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
165
PettingZoo.Core/Rendering/MessagePropertiesRendererStrings.resx
Normal file
165
PettingZoo.Core/Rendering/MessagePropertiesRendererStrings.resx
Normal file
@ -0,0 +1,165 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<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>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<data name="AppId" xml:space="preserve">
|
||||
<value>App ID</value>
|
||||
</data>
|
||||
<data name="ContentEncoding" xml:space="preserve">
|
||||
<value>Content encoding</value>
|
||||
</data>
|
||||
<data name="ContentType" xml:space="preserve">
|
||||
<value>Content type</value>
|
||||
</data>
|
||||
<data name="CorrelationId" xml:space="preserve">
|
||||
<value>Correlation ID</value>
|
||||
</data>
|
||||
<data name="DeliveryMode" xml:space="preserve">
|
||||
<value>Delivery mode</value>
|
||||
</data>
|
||||
<data name="DeliveryModeNonPersistent" xml:space="preserve">
|
||||
<value>Transient (1)</value>
|
||||
</data>
|
||||
<data name="DeliveryModePersistent" xml:space="preserve">
|
||||
<value>Persistent (2)</value>
|
||||
</data>
|
||||
<data name="Expiration" xml:space="preserve">
|
||||
<value>Expiration</value>
|
||||
</data>
|
||||
<data name="HeaderPrefix" xml:space="preserve">
|
||||
<value>Header: </value>
|
||||
</data>
|
||||
<data name="MessageId" xml:space="preserve">
|
||||
<value>Message ID</value>
|
||||
</data>
|
||||
<data name="Priority" xml:space="preserve">
|
||||
<value>Priority</value>
|
||||
</data>
|
||||
<data name="ReplyTo" xml:space="preserve">
|
||||
<value>Reply To</value>
|
||||
</data>
|
||||
<data name="Timestamp" xml:space="preserve">
|
||||
<value>Timestamp</value>
|
||||
</data>
|
||||
<data name="Type" xml:space="preserve">
|
||||
<value>Type</value>
|
||||
</data>
|
||||
<data name="UserId" xml:space="preserve">
|
||||
<value>User ID</value>
|
||||
</data>
|
||||
</root>
|
@ -81,7 +81,7 @@ namespace PettingZoo.RabbitMQ
|
||||
}
|
||||
|
||||
|
||||
public Task Publish(MessageInfo messageInfo)
|
||||
public Task Publish(PublishMessageInfo messageInfo)
|
||||
{
|
||||
if (model == null)
|
||||
throw new InvalidOperationException("Not connected");
|
||||
|
@ -1,136 +1,135 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using PettingZoo.Core.Connection;
|
||||
using RabbitMQ.Client;
|
||||
|
||||
namespace PettingZoo.RabbitMQ
|
||||
{
|
||||
public static class RabbitMQClientPropertiesConverter
|
||||
{
|
||||
public static IDictionary<string, string> Convert(IBasicProperties basicProperties)
|
||||
public static MessageProperties Convert(IBasicProperties basicProperties)
|
||||
{
|
||||
var properties = new Dictionary<string, string>();
|
||||
|
||||
if (basicProperties.IsDeliveryModePresent())
|
||||
properties.Add(RabbitMQProperties.DeliveryMode, basicProperties.DeliveryMode.ToString(CultureInfo.InvariantCulture));
|
||||
|
||||
if (basicProperties.IsContentTypePresent())
|
||||
properties.Add(RabbitMQProperties.ContentType, basicProperties.ContentType);
|
||||
|
||||
if (basicProperties.IsContentEncodingPresent())
|
||||
properties.Add(RabbitMQProperties.ContentEncoding, basicProperties.ContentEncoding);
|
||||
|
||||
if (basicProperties.IsPriorityPresent())
|
||||
properties.Add(RabbitMQProperties.Priority, basicProperties.Priority.ToString(CultureInfo.InvariantCulture));
|
||||
|
||||
if (basicProperties.IsCorrelationIdPresent())
|
||||
properties.Add(RabbitMQProperties.Priority, basicProperties.CorrelationId);
|
||||
|
||||
if (basicProperties.IsReplyToPresent())
|
||||
properties.Add(RabbitMQProperties.ReplyTo, basicProperties.ReplyTo);
|
||||
|
||||
if (basicProperties.IsExpirationPresent())
|
||||
properties.Add(RabbitMQProperties.Expiration, basicProperties.Expiration);
|
||||
|
||||
if (basicProperties.IsMessageIdPresent())
|
||||
properties.Add(RabbitMQProperties.MessageId, basicProperties.MessageId);
|
||||
|
||||
if (basicProperties.IsTimestampPresent())
|
||||
properties.Add(RabbitMQProperties.Timestamp, basicProperties.Timestamp.UnixTime.ToString(CultureInfo.InvariantCulture));
|
||||
|
||||
if (basicProperties.IsTypePresent())
|
||||
properties.Add(RabbitMQProperties.Type, basicProperties.Type);
|
||||
|
||||
if (basicProperties.IsUserIdPresent())
|
||||
properties.Add(RabbitMQProperties.UserId, basicProperties.UserId);
|
||||
|
||||
if (basicProperties.IsAppIdPresent())
|
||||
properties.Add(RabbitMQProperties.UserId, basicProperties.AppId);
|
||||
|
||||
if (basicProperties.IsClusterIdPresent())
|
||||
properties.Add(RabbitMQProperties.ClusterId, basicProperties.ClusterId);
|
||||
|
||||
// ReSharper disable once InvertIf
|
||||
if (basicProperties.Headers != null)
|
||||
return new MessageProperties(basicProperties.Headers?.ToDictionary(p => p.Key, p => Encoding.UTF8.GetString((byte[])p.Value)))
|
||||
{
|
||||
foreach (var (key, value) in basicProperties.Headers)
|
||||
properties.Add(key, Encoding.UTF8.GetString((byte[]) value));
|
||||
}
|
||||
DeliveryMode = basicProperties.IsDeliveryModePresent()
|
||||
? basicProperties.DeliveryMode == 2 ? MessageDeliveryMode.Persistent :
|
||||
MessageDeliveryMode.NonPersistent
|
||||
: null,
|
||||
|
||||
return properties;
|
||||
ContentType = basicProperties.IsContentTypePresent()
|
||||
? basicProperties.ContentType
|
||||
: null,
|
||||
|
||||
ContentEncoding = basicProperties.IsContentEncodingPresent()
|
||||
? basicProperties.ContentEncoding
|
||||
: null,
|
||||
|
||||
Priority = basicProperties.IsPriorityPresent()
|
||||
? basicProperties.Priority
|
||||
: null,
|
||||
|
||||
CorrelationId = basicProperties.IsCorrelationIdPresent()
|
||||
? basicProperties.CorrelationId
|
||||
: null,
|
||||
|
||||
ReplyTo = basicProperties.IsReplyToPresent()
|
||||
? basicProperties.ReplyTo
|
||||
: null,
|
||||
|
||||
Expiration = basicProperties.IsExpirationPresent()
|
||||
? basicProperties.Expiration
|
||||
: null,
|
||||
|
||||
MessageId = basicProperties.IsMessageIdPresent()
|
||||
? basicProperties.MessageId
|
||||
: null,
|
||||
|
||||
Timestamp = basicProperties.IsTimestampPresent()
|
||||
? DateTimeOffset.FromUnixTimeMilliseconds(basicProperties.Timestamp.UnixTime).LocalDateTime
|
||||
: null,
|
||||
|
||||
Type = basicProperties.IsTypePresent()
|
||||
? basicProperties.Type
|
||||
: null,
|
||||
|
||||
UserId = basicProperties.IsUserIdPresent()
|
||||
? basicProperties.UserId
|
||||
: null,
|
||||
|
||||
AppId = basicProperties.IsAppIdPresent()
|
||||
? basicProperties.AppId
|
||||
: null
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
public static IBasicProperties Convert(IDictionary<string, string> properties, IBasicProperties targetProperties)
|
||||
public static IBasicProperties Convert(MessageProperties properties, IBasicProperties targetProperties)
|
||||
{
|
||||
foreach (var (key, value) in properties)
|
||||
{
|
||||
switch (key)
|
||||
{
|
||||
case RabbitMQProperties.DeliveryMode:
|
||||
if (byte.TryParse(value, out var deliveryMode))
|
||||
targetProperties.DeliveryMode = deliveryMode;
|
||||
if (properties.DeliveryMode != null)
|
||||
targetProperties.DeliveryMode = properties.DeliveryMode == MessageDeliveryMode.Persistent ? (byte)2 : (byte)1;
|
||||
else
|
||||
targetProperties.ClearDeliveryMode();
|
||||
|
||||
break;
|
||||
if (properties.ContentType != null)
|
||||
targetProperties.ContentType = properties.ContentType;
|
||||
else
|
||||
targetProperties.ClearContentType();
|
||||
|
||||
case RabbitMQProperties.ContentType:
|
||||
targetProperties.ContentType = value;
|
||||
break;
|
||||
if (properties.ContentEncoding != null)
|
||||
targetProperties.ContentEncoding = properties.ContentEncoding;
|
||||
else
|
||||
targetProperties.ClearContentEncoding();
|
||||
|
||||
case RabbitMQProperties.ContentEncoding:
|
||||
targetProperties.ContentEncoding = value;
|
||||
break;
|
||||
if (properties.Priority != null)
|
||||
targetProperties.Priority = properties.Priority.Value;
|
||||
else
|
||||
targetProperties.ClearPriority();
|
||||
|
||||
case RabbitMQProperties.Priority:
|
||||
if (byte.TryParse(value, out var priority))
|
||||
targetProperties.Priority = priority;
|
||||
if (properties.CorrelationId != null)
|
||||
targetProperties.CorrelationId = properties.CorrelationId;
|
||||
else
|
||||
targetProperties.ClearCorrelationId();
|
||||
|
||||
break;
|
||||
if (properties.ReplyTo != null)
|
||||
targetProperties.ReplyTo = properties.ReplyTo;
|
||||
else
|
||||
targetProperties.ClearReplyTo();
|
||||
|
||||
case RabbitMQProperties.CorrelationId:
|
||||
targetProperties.CorrelationId = value;
|
||||
break;
|
||||
if (properties.Expiration != null)
|
||||
targetProperties.Expiration = properties.Expiration;
|
||||
else
|
||||
targetProperties.ClearExpiration();
|
||||
|
||||
case RabbitMQProperties.ReplyTo:
|
||||
targetProperties.ReplyTo = value;
|
||||
break;
|
||||
if (properties.MessageId != null)
|
||||
targetProperties.MessageId = properties.MessageId;
|
||||
else
|
||||
targetProperties.ClearMessageId();
|
||||
|
||||
case RabbitMQProperties.Expiration:
|
||||
targetProperties.Expiration = value;
|
||||
break;
|
||||
if (properties.Timestamp != null)
|
||||
targetProperties.Timestamp = new AmqpTimestamp(new DateTimeOffset(properties.Timestamp.Value).ToUnixTimeMilliseconds());
|
||||
else
|
||||
targetProperties.ClearTimestamp();
|
||||
|
||||
case RabbitMQProperties.MessageId:
|
||||
targetProperties.MessageId = value;
|
||||
break;
|
||||
if (properties.Type != null)
|
||||
targetProperties.Type = properties.Type;
|
||||
else
|
||||
targetProperties.ClearType();
|
||||
|
||||
case RabbitMQProperties.Timestamp:
|
||||
if (long.TryParse(value, out var timestamp))
|
||||
targetProperties.Timestamp = new AmqpTimestamp(timestamp);
|
||||
if (properties.UserId != null)
|
||||
targetProperties.UserId = properties.UserId;
|
||||
else
|
||||
targetProperties.ClearUserId();
|
||||
|
||||
break;
|
||||
if (properties.AppId != null)
|
||||
targetProperties.AppId = properties.AppId;
|
||||
else
|
||||
targetProperties.ClearAppId();
|
||||
|
||||
case RabbitMQProperties.Type:
|
||||
targetProperties.Type = value;
|
||||
break;
|
||||
|
||||
case RabbitMQProperties.UserId:
|
||||
targetProperties.UserId = value;
|
||||
break;
|
||||
|
||||
case RabbitMQProperties.AppId:
|
||||
targetProperties.AppId = value;
|
||||
break;
|
||||
|
||||
case RabbitMQProperties.ClusterId:
|
||||
targetProperties.ClusterId = value;
|
||||
break;
|
||||
|
||||
default:
|
||||
targetProperties.Headers ??= new Dictionary<string, object>();
|
||||
targetProperties.Headers.Add(key, Encoding.UTF8.GetBytes(value));
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (properties.Headers.Count > 0)
|
||||
targetProperties.Headers = properties.Headers.ToDictionary(p => p.Key, p => (object)Encoding.UTF8.GetBytes(p.Value));
|
||||
else
|
||||
targetProperties.ClearHeaders();
|
||||
|
||||
return targetProperties;
|
||||
}
|
||||
|
@ -63,7 +63,7 @@ namespace PettingZoo.RabbitMQ
|
||||
private void ClientReceived(object? sender, BasicDeliverEventArgs args)
|
||||
{
|
||||
MessageReceived?.Invoke(this, new MessageReceivedEventArgs(
|
||||
new MessageInfo(
|
||||
new ReceivedMessageInfo(
|
||||
args.Exchange,
|
||||
args.RoutingKey,
|
||||
args.Body.ToArray(),
|
||||
|
@ -1,19 +0,0 @@
|
||||
namespace PettingZoo.RabbitMQ
|
||||
{
|
||||
public static class RabbitMQProperties
|
||||
{
|
||||
public const string ContentType = "content-type";
|
||||
public const string ContentEncoding = "content-encoding";
|
||||
public const string DeliveryMode = "delivery-mode";
|
||||
public const string Priority = "priority";
|
||||
public const string CorrelationId = "correlation-id";
|
||||
public const string ReplyTo = "reply-to";
|
||||
public const string Expiration = "expiration";
|
||||
public const string MessageId = "message-id";
|
||||
public const string Timestamp = "timestamp";
|
||||
public const string Type = "type";
|
||||
public const string UserId = "user-id";
|
||||
public const string AppId = "app-id";
|
||||
public const string ClusterId = "cluster-id";
|
||||
}
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace PettingZoo.RabbitMQ
|
||||
{
|
||||
public static class RabbitMQPropertiesExtensions
|
||||
{
|
||||
public static string ContentType(this IDictionary<string, string> properties)
|
||||
{
|
||||
return properties.TryGetValue(RabbitMQProperties.ContentType, out var value)
|
||||
? value
|
||||
: "";
|
||||
}
|
||||
}
|
||||
}
|
@ -56,6 +56,11 @@
|
||||
<DesignTime>True</DesignTime>
|
||||
<AutoGen>True</AutoGen>
|
||||
</Compile>
|
||||
<Compile Update="UI\Tab\Publisher\RawPublisherViewStrings.Designer.cs">
|
||||
<DependentUpon>RawPublisherViewStrings.resx</DependentUpon>
|
||||
<DesignTime>True</DesignTime>
|
||||
<AutoGen>True</AutoGen>
|
||||
</Compile>
|
||||
<Compile Update="UI\Tab\Publisher\PublisherViewStrings.Designer.cs">
|
||||
<DependentUpon>PublisherViewStrings.resx</DependentUpon>
|
||||
<DesignTime>True</DesignTime>
|
||||
@ -81,6 +86,10 @@
|
||||
<LastGenOutput>SubscribeWindowStrings.Designer.cs</LastGenOutput>
|
||||
<Generator>PublicResXFileCodeGenerator</Generator>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Update="UI\Tab\Publisher\RawPublisherViewStrings.resx">
|
||||
<LastGenOutput>RawPublisherViewStrings.Designer.cs</LastGenOutput>
|
||||
<Generator>PublicResXFileCodeGenerator</Generator>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Update="UI\Tab\Publisher\PublisherViewStrings.resx">
|
||||
<LastGenOutput>PublisherViewStrings.Designer.cs</LastGenOutput>
|
||||
<Generator>PublicResXFileCodeGenerator</Generator>
|
||||
|
@ -12,7 +12,6 @@ using PettingZoo.UI.Connection;
|
||||
using PettingZoo.UI.Main;
|
||||
using PettingZoo.UI.Subscribe;
|
||||
using PettingZoo.UI.Tab;
|
||||
using PettingZoo.UI.Tab.Subscriber;
|
||||
using SimpleInjector;
|
||||
|
||||
namespace PettingZoo
|
||||
|
@ -10,6 +10,11 @@
|
||||
<Setter Property="Padding" Value="8,4"/>
|
||||
</Style>
|
||||
|
||||
<Style TargetType="{x:Type TextBox}">
|
||||
<Setter Property="Padding" Value="3" />
|
||||
</Style>
|
||||
|
||||
|
||||
<!-- Explicit styling -->
|
||||
<Style x:Key="SidePanel" TargetType="{x:Type Border}">
|
||||
<Setter Property="BorderThickness" Value="1"/>
|
||||
@ -59,8 +64,17 @@
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="RoutingKey">
|
||||
</Style>
|
||||
|
||||
<Style x:Key="TypeSelection" TargetType="{x:Type FrameworkElement}">
|
||||
<Setter Property="Margin" Value="0 0 8 0" />
|
||||
<Setter Property="VerticalAlignment" Value="Center" />
|
||||
</Style>
|
||||
|
||||
|
||||
<Style x:Key="SectionLabel" TargetType="{x:Type Label}">
|
||||
<Setter Property="FontWeight" Value="Bold"/>
|
||||
</Style>
|
||||
|
||||
</ResourceDictionary>
|
@ -9,7 +9,7 @@
|
||||
mc:Ignorable="d"
|
||||
d:DataContext="{d:DesignInstance main:DesignTimeMainWindowViewModel, IsDesignTimeCreatable=True}"
|
||||
Width="800"
|
||||
Height="600"
|
||||
Height="800"
|
||||
ResizeMode="CanResizeWithGrip"
|
||||
Style="{StaticResource WindowStyle}"
|
||||
Title="{x:Static main:MainWindowStrings.WindowTitle}"
|
||||
|
@ -37,7 +37,8 @@ namespace PettingZoo.UI.Main
|
||||
|
||||
private void MainWindow_OnLoaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
viewModel.ConnectCommand.Execute(null);
|
||||
// TODO support command-line parameters for easier testing
|
||||
//viewModel.ConnectCommand.Execute(null);
|
||||
}
|
||||
|
||||
|
||||
|
@ -93,8 +93,11 @@ namespace PettingZoo.UI.Main
|
||||
|
||||
private async void ConnectExecute()
|
||||
{
|
||||
//var newParams = connectionDialog.Show(connectionDialogParams);
|
||||
var newParams = new ConnectionDialogParams("localhost", "/", 5672, "guest", "guest", true, "lef", "#");
|
||||
var newParams = connectionDialog.Show(connectionDialogParams);
|
||||
|
||||
// TODO support command-line parameters for easier testing
|
||||
// var newParams = new ConnectionDialogParams("localhost", "/", 5672, "guest", "guest", true, "test", "#");
|
||||
|
||||
if (newParams == null)
|
||||
return;
|
||||
|
||||
|
@ -9,13 +9,20 @@
|
||||
d:DesignWidth="800"
|
||||
d:DataContext="{d:DesignInstance res:DesignTimePublisherViewModel, IsDesignTimeCreatable=True}"
|
||||
Background="White">
|
||||
<StackPanel Margin="4">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock Text="{x:Static res:PublisherViewStrings.LabelMessageType}" Style="{StaticResource TypeSelection}" />
|
||||
<Grid Margin="4">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<StackPanel Orientation="Horizontal" Grid.Row="0">
|
||||
<Label Content="{x:Static res:PublisherViewStrings.LabelMessageType}" Style="{StaticResource TypeSelection}" />
|
||||
<RadioButton Content="{x:Static res:PublisherViewStrings.OptionMessageTypeRaw}" Style="{StaticResource TypeSelection}" IsChecked="{Binding MessageTypeRaw}" />
|
||||
<RadioButton Content="{x:Static res:PublisherViewStrings.OptionMessageTypeTapeti}" Style="{StaticResource TypeSelection}" IsChecked="{Binding MessageTypeTapeti}" />
|
||||
</StackPanel>
|
||||
|
||||
<TextBlock>TODO: implement publish forms</TextBlock>
|
||||
</StackPanel>
|
||||
<ScrollViewer Grid.Row="1" VerticalScrollBarVisibility="Auto">
|
||||
<ContentControl Margin="0 8 0 0" Content="{Binding MessageTypeControl}" />
|
||||
</ScrollViewer>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
|
@ -1,4 +1,6 @@
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Input;
|
||||
using PettingZoo.Core.Connection;
|
||||
|
||||
@ -16,6 +18,11 @@ namespace PettingZoo.UI.Tab.Publisher
|
||||
private readonly IConnection connection;
|
||||
|
||||
private MessageType messageType;
|
||||
private UserControl? messageTypeControl;
|
||||
private ICommand? messageTypePublishCommand;
|
||||
|
||||
private UserControl? rawPublisherView;
|
||||
private UserControl? tapetiPublisherView;
|
||||
|
||||
private readonly DelegateCommand publishCommand;
|
||||
private readonly TabToolbarCommand[] toolbarCommands;
|
||||
@ -24,13 +31,18 @@ namespace PettingZoo.UI.Tab.Publisher
|
||||
public MessageType MessageType
|
||||
{
|
||||
get => messageType;
|
||||
set => SetField(ref messageType, value,
|
||||
set
|
||||
{
|
||||
if (SetField(ref messageType, value,
|
||||
otherPropertiesChanged: new[]
|
||||
{
|
||||
nameof(MessageTypeRaw),
|
||||
nameof(MessageTypeTapeti)
|
||||
});
|
||||
|
||||
}))
|
||||
{
|
||||
SetMessageTypeControl(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool MessageTypeRaw
|
||||
@ -46,6 +58,13 @@ namespace PettingZoo.UI.Tab.Publisher
|
||||
}
|
||||
|
||||
|
||||
public UserControl? MessageTypeControl
|
||||
{
|
||||
get => messageTypeControl;
|
||||
set => SetField(ref messageTypeControl, value);
|
||||
}
|
||||
|
||||
|
||||
public ICommand PublishCommand => publishCommand;
|
||||
|
||||
|
||||
@ -64,19 +83,49 @@ namespace PettingZoo.UI.Tab.Publisher
|
||||
{
|
||||
new TabToolbarCommand(PublishCommand, PublisherViewStrings.CommandPublish, SvgIconHelper.LoadFromResource("/Images/PublishSend.svg"))
|
||||
};
|
||||
|
||||
SetMessageTypeControl(MessageType.Raw);
|
||||
}
|
||||
|
||||
|
||||
private void PublishExecute()
|
||||
{
|
||||
// TODO
|
||||
messageTypePublishCommand?.Execute(null);
|
||||
}
|
||||
|
||||
|
||||
private bool PublishCanExecute()
|
||||
{
|
||||
// TODO validate input
|
||||
return true;
|
||||
return messageTypePublishCommand?.CanExecute(null) ?? false;
|
||||
}
|
||||
|
||||
|
||||
private void SetMessageTypeControl(MessageType value)
|
||||
{
|
||||
switch (value)
|
||||
{
|
||||
case MessageType.Raw:
|
||||
var rawPublisherViewModel = new RawPublisherViewModel(connection);
|
||||
rawPublisherView ??= new RawPublisherView(rawPublisherViewModel);
|
||||
MessageTypeControl = rawPublisherView;
|
||||
|
||||
messageTypePublishCommand = rawPublisherViewModel.PublishCommand;
|
||||
publishCommand.RaiseCanExecuteChanged();
|
||||
break;
|
||||
|
||||
case MessageType.Tapeti:
|
||||
// TODO
|
||||
var tapetiPublisherViewModel = new RawPublisherViewModel(connection);
|
||||
tapetiPublisherView ??= new RawPublisherView(tapetiPublisherViewModel);
|
||||
MessageTypeControl = tapetiPublisherView;
|
||||
|
||||
messageTypePublishCommand = tapetiPublisherViewModel.PublishCommand;
|
||||
publishCommand.RaiseCanExecuteChanged();
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new ArgumentException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
166
PettingZoo/UI/Tab/Publisher/RawPublisherView.xaml
Normal file
166
PettingZoo/UI/Tab/Publisher/RawPublisherView.xaml
Normal file
@ -0,0 +1,166 @@
|
||||
<UserControl x:Class="PettingZoo.UI.Tab.Publisher.RawPublisherView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:publisher="clr-namespace:PettingZoo.UI.Tab.Publisher"
|
||||
xmlns:ui="clr-namespace:PettingZoo.UI"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="800" d:DesignWidth="800"
|
||||
d:DataContext="{d:DesignInstance publisher:DesignTimeRawPublisherViewModel, IsDesignTimeCreatable=True}"
|
||||
Background="White">
|
||||
<ui:GridLayout Style="{StaticResource Form}">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<ui:GridLayout.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="16"/>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="16"/>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</ui:GridLayout.RowDefinitions>
|
||||
|
||||
|
||||
<Label Grid.Row="0" Grid.Column="1">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<RadioButton Content="{x:Static publisher:RawPublisherViewStrings.LabelSendToExchange}" IsChecked="{Binding SendToExchange}" Style="{StaticResource TypeSelection}" />
|
||||
<RadioButton Content="{x:Static publisher:RawPublisherViewStrings.LabelSendToQueue}" IsChecked="{Binding SendToQueue}" Style="{StaticResource TypeSelection}" />
|
||||
</StackPanel>
|
||||
</Label>
|
||||
|
||||
<Label Grid.Row="1" Grid.Column="0" Content="{x:Static publisher:RawPublisherViewStrings.LabelExchange}" Visibility="{Binding ExchangeVisibility}" />
|
||||
<TextBox Grid.Row="1" Grid.Column="1" Text="{Binding Exchange}" Visibility="{Binding ExchangeVisibility}" />
|
||||
|
||||
<Label Grid.Row="2" Grid.Column="0" Content="{x:Static publisher:RawPublisherViewStrings.LabelRoutingKey}" Visibility="{Binding ExchangeVisibility}" />
|
||||
<TextBox Grid.Row="2" Grid.Column="1" Text="{Binding RoutingKey}" Visibility="{Binding ExchangeVisibility}" />
|
||||
|
||||
<Label Grid.Row="3" Grid.Column="0" Content="{x:Static publisher:RawPublisherViewStrings.LabelQueue}" Visibility="{Binding QueueVisibility}" />
|
||||
<TextBox Grid.Row="3" Grid.Column="1" Text="{Binding Queue}" Visibility="{Binding QueueVisibility}" />
|
||||
|
||||
|
||||
<Label Grid.Row="5" Grid.Column="0" Content="{x:Static publisher:RawPublisherViewStrings.LabelDeliveryMode}" />
|
||||
<ComboBox Grid.Row="5" Grid.Column="1" SelectedIndex="{Binding DeliveryModeIndex}">
|
||||
<ComboBoxItem Content="{x:Static publisher:RawPublisherViewStrings.DeliveryModeNonPersistent}" />
|
||||
<ComboBoxItem Content="{x:Static publisher:RawPublisherViewStrings.DeliveryModePersistent}" />
|
||||
</ComboBox>
|
||||
|
||||
<Label Grid.Row="6" Grid.Column="0" Content="{x:Static publisher:RawPublisherViewStrings.LabelHeaders}" />
|
||||
<ItemsControl Grid.Row="6" Grid.Column="1" ItemsSource="{Binding Headers}">
|
||||
<ItemsControl.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<StackPanel Orientation="Vertical" />
|
||||
</ItemsPanelTemplate>
|
||||
</ItemsControl.ItemsPanel>
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Grid Margin="0 0 0 8">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Grid Grid.Column="0" >
|
||||
<TextBox Text="{Binding Key, UpdateSourceTrigger=PropertyChanged}" LostFocus="Header_OnLostFocus" Margin="0 0 8 0" x:Name="HeaderKey" />
|
||||
<TextBlock IsHitTestVisible="False" Text="{x:Static publisher:RawPublisherViewStrings.HeaderName}" VerticalAlignment="Center" HorizontalAlignment="Left" Margin="10,0,0,0" Foreground="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}">
|
||||
<TextBlock.Style>
|
||||
<Style TargetType="{x:Type TextBlock}">
|
||||
<Setter Property="Visibility" Value="Collapsed"/>
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding Text, ElementName=HeaderKey}" Value="">
|
||||
<Setter Property="Visibility" Value="Visible"/>
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</TextBlock.Style>
|
||||
</TextBlock>
|
||||
</Grid>
|
||||
|
||||
<Grid Grid.Column="1">
|
||||
<TextBox Text="{Binding Value, UpdateSourceTrigger=PropertyChanged}" LostFocus="Header_OnLostFocus" x:Name="HeaderValue" />
|
||||
<TextBlock IsHitTestVisible="False" Text="{x:Static publisher:RawPublisherViewStrings.HeaderValue}" VerticalAlignment="Center" HorizontalAlignment="Left" Margin="10,0,0,0" Foreground="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}">
|
||||
<TextBlock.Style>
|
||||
<Style TargetType="{x:Type TextBlock}">
|
||||
<Setter Property="Visibility" Value="Collapsed"/>
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding Text, ElementName=HeaderValue}" Value="">
|
||||
<Setter Property="Visibility" Value="Visible"/>
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</TextBlock.Style>
|
||||
</TextBlock>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
|
||||
<Label Grid.Row="7" Grid.Column="0" Content="{x:Static publisher:RawPublisherViewStrings.LabelProperties}" Style="{StaticResource SectionLabel}"/>
|
||||
|
||||
<Label Grid.Row="8" Grid.Column="0" Content="{x:Static publisher:RawPublisherViewStrings.LabelContentType}" />
|
||||
<TextBox Grid.Row="8" Grid.Column="1" Text="{Binding ContentType}" />
|
||||
|
||||
<Label Grid.Row="9" Grid.Column="0" Content="{x:Static publisher:RawPublisherViewStrings.LabelCorrelationId}" />
|
||||
<TextBox Grid.Row="9" Grid.Column="1" Text="{Binding CorrelationId}" />
|
||||
|
||||
<Label Grid.Row="10" Grid.Column="0" Content="{x:Static publisher:RawPublisherViewStrings.LabelReplyTo}" />
|
||||
<TextBox Grid.Row="10" Grid.Column="1" Text="{Binding ReplyTo}" />
|
||||
|
||||
<Label Grid.Row="11" Grid.Column="0" Content="{x:Static publisher:RawPublisherViewStrings.LabelAppId}" Visibility="{Binding PropertiesExpandedVisibility}" />
|
||||
<TextBox Grid.Row="11" Grid.Column="1" Text="{Binding AppId}" Visibility="{Binding PropertiesExpandedVisibility}" />
|
||||
|
||||
<Label Grid.Row="12" Grid.Column="0" Content="{x:Static publisher:RawPublisherViewStrings.LabelContentEncoding}" Visibility="{Binding PropertiesExpandedVisibility}" />
|
||||
<TextBox Grid.Row="12" Grid.Column="1" Text="{Binding ContentEncoding}" Visibility="{Binding PropertiesExpandedVisibility}" />
|
||||
|
||||
<Label Grid.Row="13" Grid.Column="0" Content="{x:Static publisher:RawPublisherViewStrings.LabelExpiration}" Visibility="{Binding PropertiesExpandedVisibility}" />
|
||||
<TextBox Grid.Row="13" Grid.Column="1" Text="{Binding Expiration}" Visibility="{Binding PropertiesExpandedVisibility}" />
|
||||
|
||||
<Label Grid.Row="14" Grid.Column="0" Content="{x:Static publisher:RawPublisherViewStrings.LabelMessageId}" Visibility="{Binding PropertiesExpandedVisibility}" />
|
||||
<TextBox Grid.Row="14" Grid.Column="1" Text="{Binding MessageId}" Visibility="{Binding PropertiesExpandedVisibility}" />
|
||||
|
||||
<Label Grid.Row="15" Grid.Column="0" Content="{x:Static publisher:RawPublisherViewStrings.LabelPriority}" Visibility="{Binding PropertiesExpandedVisibility}" />
|
||||
<TextBox Grid.Row="15" Grid.Column="1" Text="{Binding Priority}" Visibility="{Binding PropertiesExpandedVisibility}" />
|
||||
|
||||
<Label Grid.Row="16" Grid.Column="0" Content="{x:Static publisher:RawPublisherViewStrings.LabelTimestamp}" Visibility="{Binding PropertiesExpandedVisibility}" />
|
||||
<TextBox Grid.Row="16" Grid.Column="1" Text="{Binding Timestamp}" Visibility="{Binding PropertiesExpandedVisibility}" />
|
||||
|
||||
<Label Grid.Row="17" Grid.Column="0" Content="{x:Static publisher:RawPublisherViewStrings.LabelType}" Visibility="{Binding PropertiesExpandedVisibility}" />
|
||||
<TextBox Grid.Row="17" Grid.Column="1" Text="{Binding TypeProperty}" Visibility="{Binding PropertiesExpandedVisibility}" />
|
||||
|
||||
<Label Grid.Row="18" Grid.Column="0" Content="{x:Static publisher:RawPublisherViewStrings.LabelUserId}" Visibility="{Binding PropertiesExpandedVisibility}" />
|
||||
<TextBox Grid.Row="18" Grid.Column="1" Text="{Binding UserId}" Visibility="{Binding PropertiesExpandedVisibility}" />
|
||||
|
||||
|
||||
<Button Grid.Row="19" Grid.Column="1" Content="{Binding PropertiesExpandedCollapsedText}" Command="{Binding PropertiesExpandCollapseCommand}" Cursor="Hand">
|
||||
<Button.Template>
|
||||
<ControlTemplate TargetType="{x:Type Button}">
|
||||
<ContentPresenter />
|
||||
</ControlTemplate>
|
||||
</Button.Template>
|
||||
</Button>
|
||||
|
||||
<Label Grid.Row="21" Grid.Column="0" Content="{x:Static publisher:RawPublisherViewStrings.LabelPayload}" />
|
||||
<TextBox Grid.Row="21" Grid.Column="1" Text="{Binding Payload}" AcceptsReturn="True" VerticalScrollBarVisibility="Visible" Height="150" />
|
||||
</ui:GridLayout>
|
||||
</UserControl>
|
67
PettingZoo/UI/Tab/Publisher/RawPublisherView.xaml.cs
Normal file
67
PettingZoo/UI/Tab/Publisher/RawPublisherView.xaml.cs
Normal file
@ -0,0 +1,67 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Threading;
|
||||
|
||||
namespace PettingZoo.UI.Tab.Publisher
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for RawPublisherView.xaml
|
||||
/// </summary>
|
||||
public partial class RawPublisherView
|
||||
{
|
||||
private RawPublisherViewModel viewModel;
|
||||
private DispatcherTimer checkEmptyHeaderTimer;
|
||||
|
||||
|
||||
public RawPublisherView(RawPublisherViewModel viewModel)
|
||||
{
|
||||
this.viewModel = viewModel;
|
||||
|
||||
InitializeComponent();
|
||||
DataContext = viewModel;
|
||||
|
||||
checkEmptyHeaderTimer = new DispatcherTimer();
|
||||
checkEmptyHeaderTimer.Tick += CheckEmptyHeaderTimerOnTick;
|
||||
checkEmptyHeaderTimer.Interval = TimeSpan.FromMilliseconds(50);
|
||||
}
|
||||
|
||||
private void Header_OnLostFocus(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var dataContext = (sender as FrameworkElement)?.DataContext;
|
||||
if (dataContext is not RawPublisherViewModel.Header header)
|
||||
return;
|
||||
|
||||
if (!header.IsEmpty())
|
||||
return;
|
||||
|
||||
// At this point the focused element is null, so we need to check again in a bit. This will prevent
|
||||
// the header line from being removed when jumping between empty key and value textboxes
|
||||
checkEmptyHeaderTimer.Stop();
|
||||
checkEmptyHeaderTimer.Start();
|
||||
}
|
||||
|
||||
|
||||
private void CheckEmptyHeaderTimerOnTick(object? sender, EventArgs e)
|
||||
{
|
||||
checkEmptyHeaderTimer.Stop();
|
||||
|
||||
RawPublisherViewModel.Header? focusedHeader = null;
|
||||
|
||||
var focusedControl = Keyboard.FocusedElement;
|
||||
if (focusedControl is FrameworkElement { DataContext: RawPublisherViewModel.Header header })
|
||||
focusedHeader = header;
|
||||
|
||||
var emptyheaders = viewModel.Headers
|
||||
.Take(viewModel.Headers.Count - 1)
|
||||
.Where(h => h != focusedHeader && h.IsEmpty())
|
||||
.ToArray();
|
||||
|
||||
foreach (var emptyHeader in emptyheaders)
|
||||
viewModel.Headers.Remove(emptyHeader);
|
||||
}
|
||||
}
|
||||
}
|
322
PettingZoo/UI/Tab/Publisher/RawPublisherViewModel.cs
Normal file
322
PettingZoo/UI/Tab/Publisher/RawPublisherViewModel.cs
Normal file
@ -0,0 +1,322 @@
|
||||
using System;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Windows;
|
||||
using System.Windows.Input;
|
||||
using PettingZoo.Core.Connection;
|
||||
|
||||
namespace PettingZoo.UI.Tab.Publisher
|
||||
{
|
||||
public class RawPublisherViewModel : BaseViewModel
|
||||
{
|
||||
private readonly IConnection connection;
|
||||
private readonly DelegateCommand publishCommand;
|
||||
private readonly DelegateCommand propertiesExpandCollapseCommand;
|
||||
private bool propertiesExpanded;
|
||||
|
||||
private bool sendToExchange = true;
|
||||
private string exchange = "";
|
||||
private string routingKey = "";
|
||||
private string queue = "";
|
||||
|
||||
private MessageDeliveryMode deliveryMode;
|
||||
|
||||
private string contentType = "application/json";
|
||||
private string correlationId = "";
|
||||
private string replyTo = "";
|
||||
private string appId = "";
|
||||
private string contentEncoding = "";
|
||||
private string expiration = "";
|
||||
private string messageId = "";
|
||||
private string priority = "";
|
||||
private string timestamp = "";
|
||||
private string typeProperty = "";
|
||||
private string userId = "";
|
||||
private string payload = "";
|
||||
|
||||
|
||||
public bool SendToExchange
|
||||
{
|
||||
get => sendToExchange;
|
||||
set => SetField(ref sendToExchange, value, otherPropertiesChanged: new[] { nameof(SendToQueue), nameof(ExchangeVisibility), nameof(QueueVisibility) });
|
||||
}
|
||||
|
||||
|
||||
public bool SendToQueue
|
||||
{
|
||||
get => !SendToExchange;
|
||||
set => SendToExchange = !value;
|
||||
}
|
||||
|
||||
|
||||
public string Exchange
|
||||
{
|
||||
get => exchange;
|
||||
set => SetField(ref exchange, value);
|
||||
}
|
||||
|
||||
|
||||
public string RoutingKey
|
||||
{
|
||||
get => routingKey;
|
||||
set => SetField(ref routingKey, value);
|
||||
}
|
||||
|
||||
|
||||
public string Queue
|
||||
{
|
||||
get => queue;
|
||||
set => SetField(ref queue, value);
|
||||
}
|
||||
|
||||
|
||||
public virtual Visibility ExchangeVisibility => SendToExchange ? Visibility.Visible : Visibility.Collapsed;
|
||||
public virtual Visibility QueueVisibility => SendToQueue ? Visibility.Visible : Visibility.Collapsed;
|
||||
|
||||
|
||||
public int DeliveryModeIndex
|
||||
{
|
||||
get => deliveryMode == MessageDeliveryMode.Persistent ? 1 : 0;
|
||||
set => SetField(ref deliveryMode, value == 1 ? MessageDeliveryMode.Persistent : MessageDeliveryMode.NonPersistent);
|
||||
}
|
||||
|
||||
|
||||
public string ContentType
|
||||
{
|
||||
get => contentType;
|
||||
set => SetField(ref contentType, value);
|
||||
}
|
||||
|
||||
|
||||
public string CorrelationId
|
||||
{
|
||||
get => correlationId;
|
||||
set => SetField(ref correlationId, value);
|
||||
}
|
||||
|
||||
|
||||
public string ReplyTo
|
||||
{
|
||||
get => replyTo;
|
||||
set => SetField(ref replyTo, value);
|
||||
}
|
||||
|
||||
|
||||
public string AppId
|
||||
{
|
||||
get => appId;
|
||||
set => SetField(ref appId, value);
|
||||
}
|
||||
|
||||
|
||||
public string ContentEncoding
|
||||
{
|
||||
get => contentEncoding;
|
||||
set => SetField(ref contentEncoding, value);
|
||||
}
|
||||
|
||||
|
||||
public string Expiration
|
||||
{
|
||||
get => expiration;
|
||||
set => SetField(ref expiration, value);
|
||||
}
|
||||
|
||||
|
||||
public string MessageId
|
||||
{
|
||||
get => messageId;
|
||||
set => SetField(ref messageId, value);
|
||||
}
|
||||
|
||||
|
||||
public string Priority
|
||||
{
|
||||
get => priority;
|
||||
set => SetField(ref priority, value);
|
||||
}
|
||||
|
||||
|
||||
public string Timestamp
|
||||
{
|
||||
get => timestamp;
|
||||
set => SetField(ref timestamp, value);
|
||||
}
|
||||
|
||||
|
||||
public string TypeProperty
|
||||
{
|
||||
get => typeProperty;
|
||||
set => SetField(ref typeProperty, value);
|
||||
}
|
||||
|
||||
|
||||
public string UserId
|
||||
{
|
||||
get => userId;
|
||||
set => SetField(ref userId, value);
|
||||
}
|
||||
|
||||
|
||||
public string Payload
|
||||
{
|
||||
get => payload;
|
||||
set => SetField(ref payload, value);
|
||||
}
|
||||
|
||||
|
||||
public ObservableCollection<Header> Headers { get; } = new();
|
||||
|
||||
|
||||
public ICommand PublishCommand => publishCommand;
|
||||
public ICommand PropertiesExpandCollapseCommand => propertiesExpandCollapseCommand;
|
||||
|
||||
|
||||
public bool PropertiesExpanded
|
||||
{
|
||||
get => propertiesExpanded;
|
||||
set => SetField(ref propertiesExpanded, value, otherPropertiesChanged: new[]
|
||||
{
|
||||
nameof(PropertiesExpandedVisibility),
|
||||
nameof(PropertiesExpandedCollapsedText)
|
||||
});
|
||||
}
|
||||
|
||||
public Visibility PropertiesExpandedVisibility => propertiesExpanded ? Visibility.Visible : Visibility.Collapsed;
|
||||
public string PropertiesExpandedCollapsedText => propertiesExpanded
|
||||
? RawPublisherViewStrings.PropertiesCollapse
|
||||
: RawPublisherViewStrings.PropertiesExpand;
|
||||
|
||||
|
||||
protected Header lastHeader;
|
||||
|
||||
|
||||
public RawPublisherViewModel(IConnection connection)
|
||||
{
|
||||
this.connection = connection;
|
||||
|
||||
publishCommand = new DelegateCommand(PublishExecute, PublishCanExecute);
|
||||
propertiesExpandCollapseCommand = new DelegateCommand(PropertiesExpandCollapseExecute);
|
||||
|
||||
AddHeader();
|
||||
}
|
||||
|
||||
|
||||
private void LastHeaderChanged(object? sender, PropertyChangedEventArgs e)
|
||||
{
|
||||
lastHeader.PropertyChanged -= LastHeaderChanged;
|
||||
AddHeader();
|
||||
}
|
||||
|
||||
|
||||
[MemberNotNull(nameof(lastHeader))]
|
||||
private void AddHeader()
|
||||
{
|
||||
lastHeader = new Header();
|
||||
lastHeader.PropertyChanged += LastHeaderChanged;
|
||||
Headers.Add(lastHeader);
|
||||
}
|
||||
|
||||
|
||||
private void PropertiesExpandCollapseExecute()
|
||||
{
|
||||
PropertiesExpanded = !PropertiesExpanded;
|
||||
}
|
||||
|
||||
|
||||
private void PublishExecute()
|
||||
{
|
||||
static string? NullIfEmpty(string? value)
|
||||
{
|
||||
return string.IsNullOrEmpty(value) ? null : value;
|
||||
}
|
||||
|
||||
// TODO check parsing of priority and timestamp
|
||||
// TODO support for Reply To to dynamic queue which waits for a message (or opens a new subscriber tab?)
|
||||
|
||||
var headers = Headers.Where(h => h.IsValid()).ToDictionary(h => h.Key, h => h.Value);
|
||||
|
||||
// TODO background worker / async
|
||||
|
||||
connection.Publish(new PublishMessageInfo(
|
||||
SendToExchange ? Exchange : "",
|
||||
SendToExchange ? RoutingKey : Queue,
|
||||
Encoding.UTF8.GetBytes(Payload),
|
||||
new MessageProperties(headers)
|
||||
{
|
||||
AppId = NullIfEmpty(AppId),
|
||||
ContentEncoding = NullIfEmpty(ContentEncoding),
|
||||
ContentType = NullIfEmpty(ContentType),
|
||||
CorrelationId = NullIfEmpty(CorrelationId),
|
||||
DeliveryMode = deliveryMode,
|
||||
Expiration = NullIfEmpty(Expiration),
|
||||
MessageId = NullIfEmpty(MessageId),
|
||||
Priority = !string.IsNullOrEmpty(Priority) && byte.TryParse(Priority, out var priorityValue) ? priorityValue : null,
|
||||
ReplyTo = NullIfEmpty(ReplyTo),
|
||||
Timestamp = !string.IsNullOrEmpty(Timestamp) && DateTime.TryParse(Timestamp, out var timestampValue) ? timestampValue : null,
|
||||
Type = NullIfEmpty(TypeProperty),
|
||||
UserId = NullIfEmpty(UserId)
|
||||
}));
|
||||
}
|
||||
|
||||
|
||||
private bool PublishCanExecute()
|
||||
{
|
||||
// TODO validate input
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
public class Header : BaseViewModel
|
||||
{
|
||||
private string key = "";
|
||||
private string value = "";
|
||||
|
||||
|
||||
public string Key
|
||||
{
|
||||
get => key;
|
||||
set => SetField(ref key, value);
|
||||
}
|
||||
|
||||
|
||||
public string Value
|
||||
{
|
||||
get => value;
|
||||
set => SetField(ref this.value, value);
|
||||
}
|
||||
|
||||
|
||||
public bool IsEmpty()
|
||||
{
|
||||
return string.IsNullOrEmpty(Key) && string.IsNullOrEmpty(Value);
|
||||
}
|
||||
|
||||
|
||||
public bool IsValid()
|
||||
{
|
||||
return !string.IsNullOrEmpty(Key) && !string.IsNullOrEmpty(Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public class DesignTimeRawPublisherViewModel : RawPublisherViewModel
|
||||
{
|
||||
public DesignTimeRawPublisherViewModel() : base(null!)
|
||||
{
|
||||
PropertiesExpanded = true;
|
||||
|
||||
var capturedLastHeader = lastHeader;
|
||||
capturedLastHeader.Key = "Example";
|
||||
capturedLastHeader.Value = "header";
|
||||
}
|
||||
|
||||
|
||||
public override Visibility ExchangeVisibility => Visibility.Visible;
|
||||
public override Visibility QueueVisibility => Visibility.Visible;
|
||||
}
|
||||
}
|
297
PettingZoo/UI/Tab/Publisher/RawPublisherViewStrings.Designer.cs
generated
Normal file
297
PettingZoo/UI/Tab/Publisher/RawPublisherViewStrings.Designer.cs
generated
Normal file
@ -0,0 +1,297 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by a tool.
|
||||
// Runtime Version:4.0.30319.42000
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace PettingZoo.UI.Tab.Publisher {
|
||||
using System;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// A strongly-typed resource class, for looking up localized strings, etc.
|
||||
/// </summary>
|
||||
// This class was auto-generated by the StronglyTypedResourceBuilder
|
||||
// class via a tool like ResGen or Visual Studio.
|
||||
// To add or remove a member, edit your .ResX file then rerun ResGen
|
||||
// with the /str option, or rebuild your VS project.
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
public class RawPublisherViewStrings {
|
||||
|
||||
private static global::System.Resources.ResourceManager resourceMan;
|
||||
|
||||
private static global::System.Globalization.CultureInfo resourceCulture;
|
||||
|
||||
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
||||
internal RawPublisherViewStrings() {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the cached ResourceManager instance used by this class.
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
public static global::System.Resources.ResourceManager ResourceManager {
|
||||
get {
|
||||
if (object.ReferenceEquals(resourceMan, null)) {
|
||||
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("PettingZoo.UI.Tab.Publisher.RawPublisherViewStrings", typeof(RawPublisherViewStrings).Assembly);
|
||||
resourceMan = temp;
|
||||
}
|
||||
return resourceMan;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Overrides the current thread's CurrentUICulture property for all
|
||||
/// resource lookups using this strongly typed resource class.
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
public static global::System.Globalization.CultureInfo Culture {
|
||||
get {
|
||||
return resourceCulture;
|
||||
}
|
||||
set {
|
||||
resourceCulture = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Transient (non-persistent).
|
||||
/// </summary>
|
||||
public static string DeliveryModeNonPersistent {
|
||||
get {
|
||||
return ResourceManager.GetString("DeliveryModeNonPersistent", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Persistent.
|
||||
/// </summary>
|
||||
public static string DeliveryModePersistent {
|
||||
get {
|
||||
return ResourceManager.GetString("DeliveryModePersistent", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Name.
|
||||
/// </summary>
|
||||
public static string HeaderName {
|
||||
get {
|
||||
return ResourceManager.GetString("HeaderName", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Value.
|
||||
/// </summary>
|
||||
public static string HeaderValue {
|
||||
get {
|
||||
return ResourceManager.GetString("HeaderValue", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to App ID.
|
||||
/// </summary>
|
||||
public static string LabelAppId {
|
||||
get {
|
||||
return ResourceManager.GetString("LabelAppId", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Content encoding.
|
||||
/// </summary>
|
||||
public static string LabelContentEncoding {
|
||||
get {
|
||||
return ResourceManager.GetString("LabelContentEncoding", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Content type.
|
||||
/// </summary>
|
||||
public static string LabelContentType {
|
||||
get {
|
||||
return ResourceManager.GetString("LabelContentType", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Correlation ID.
|
||||
/// </summary>
|
||||
public static string LabelCorrelationId {
|
||||
get {
|
||||
return ResourceManager.GetString("LabelCorrelationId", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Delivery mode.
|
||||
/// </summary>
|
||||
public static string LabelDeliveryMode {
|
||||
get {
|
||||
return ResourceManager.GetString("LabelDeliveryMode", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Exchange.
|
||||
/// </summary>
|
||||
public static string LabelExchange {
|
||||
get {
|
||||
return ResourceManager.GetString("LabelExchange", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Expiration.
|
||||
/// </summary>
|
||||
public static string LabelExpiration {
|
||||
get {
|
||||
return ResourceManager.GetString("LabelExpiration", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Headers.
|
||||
/// </summary>
|
||||
public static string LabelHeaders {
|
||||
get {
|
||||
return ResourceManager.GetString("LabelHeaders", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Message ID.
|
||||
/// </summary>
|
||||
public static string LabelMessageId {
|
||||
get {
|
||||
return ResourceManager.GetString("LabelMessageId", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Payload.
|
||||
/// </summary>
|
||||
public static string LabelPayload {
|
||||
get {
|
||||
return ResourceManager.GetString("LabelPayload", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Priority.
|
||||
/// </summary>
|
||||
public static string LabelPriority {
|
||||
get {
|
||||
return ResourceManager.GetString("LabelPriority", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Properties.
|
||||
/// </summary>
|
||||
public static string LabelProperties {
|
||||
get {
|
||||
return ResourceManager.GetString("LabelProperties", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Queue.
|
||||
/// </summary>
|
||||
public static string LabelQueue {
|
||||
get {
|
||||
return ResourceManager.GetString("LabelQueue", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Reply To.
|
||||
/// </summary>
|
||||
public static string LabelReplyTo {
|
||||
get {
|
||||
return ResourceManager.GetString("LabelReplyTo", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Routing key.
|
||||
/// </summary>
|
||||
public static string LabelRoutingKey {
|
||||
get {
|
||||
return ResourceManager.GetString("LabelRoutingKey", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Publish to exchange (topic).
|
||||
/// </summary>
|
||||
public static string LabelSendToExchange {
|
||||
get {
|
||||
return ResourceManager.GetString("LabelSendToExchange", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Publish to queue (direct).
|
||||
/// </summary>
|
||||
public static string LabelSendToQueue {
|
||||
get {
|
||||
return ResourceManager.GetString("LabelSendToQueue", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Timestamp.
|
||||
/// </summary>
|
||||
public static string LabelTimestamp {
|
||||
get {
|
||||
return ResourceManager.GetString("LabelTimestamp", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Type.
|
||||
/// </summary>
|
||||
public static string LabelType {
|
||||
get {
|
||||
return ResourceManager.GetString("LabelType", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to User ID.
|
||||
/// </summary>
|
||||
public static string LabelUserId {
|
||||
get {
|
||||
return ResourceManager.GetString("LabelUserId", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to ⏶ Collapse.
|
||||
/// </summary>
|
||||
public static string PropertiesCollapse {
|
||||
get {
|
||||
return ResourceManager.GetString("PropertiesCollapse", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to ⏷ Expand.
|
||||
/// </summary>
|
||||
public static string PropertiesExpand {
|
||||
get {
|
||||
return ResourceManager.GetString("PropertiesExpand", resourceCulture);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
198
PettingZoo/UI/Tab/Publisher/RawPublisherViewStrings.resx
Normal file
198
PettingZoo/UI/Tab/Publisher/RawPublisherViewStrings.resx
Normal file
@ -0,0 +1,198 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<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>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<data name="DeliveryModeNonPersistent" xml:space="preserve">
|
||||
<value>Transient (non-persistent)</value>
|
||||
</data>
|
||||
<data name="DeliveryModePersistent" xml:space="preserve">
|
||||
<value>Persistent</value>
|
||||
</data>
|
||||
<data name="HeaderName" xml:space="preserve">
|
||||
<value>Name</value>
|
||||
</data>
|
||||
<data name="HeaderValue" xml:space="preserve">
|
||||
<value>Value</value>
|
||||
</data>
|
||||
<data name="LabelAppId" xml:space="preserve">
|
||||
<value>App ID</value>
|
||||
</data>
|
||||
<data name="LabelContentEncoding" xml:space="preserve">
|
||||
<value>Content encoding</value>
|
||||
</data>
|
||||
<data name="LabelContentType" xml:space="preserve">
|
||||
<value>Content type</value>
|
||||
</data>
|
||||
<data name="LabelCorrelationId" xml:space="preserve">
|
||||
<value>Correlation ID</value>
|
||||
</data>
|
||||
<data name="LabelDeliveryMode" xml:space="preserve">
|
||||
<value>Delivery mode</value>
|
||||
</data>
|
||||
<data name="LabelExchange" xml:space="preserve">
|
||||
<value>Exchange</value>
|
||||
</data>
|
||||
<data name="LabelExpiration" xml:space="preserve">
|
||||
<value>Expiration</value>
|
||||
</data>
|
||||
<data name="LabelHeaders" xml:space="preserve">
|
||||
<value>Headers</value>
|
||||
</data>
|
||||
<data name="LabelMessageId" xml:space="preserve">
|
||||
<value>Message ID</value>
|
||||
</data>
|
||||
<data name="LabelPayload" xml:space="preserve">
|
||||
<value>Payload</value>
|
||||
</data>
|
||||
<data name="LabelPriority" xml:space="preserve">
|
||||
<value>Priority</value>
|
||||
</data>
|
||||
<data name="LabelProperties" xml:space="preserve">
|
||||
<value>Properties</value>
|
||||
</data>
|
||||
<data name="LabelQueue" xml:space="preserve">
|
||||
<value>Queue</value>
|
||||
</data>
|
||||
<data name="LabelReplyTo" xml:space="preserve">
|
||||
<value>Reply To</value>
|
||||
</data>
|
||||
<data name="LabelRoutingKey" xml:space="preserve">
|
||||
<value>Routing key</value>
|
||||
</data>
|
||||
<data name="LabelSendToExchange" xml:space="preserve">
|
||||
<value>Publish to exchange (topic)</value>
|
||||
</data>
|
||||
<data name="LabelSendToQueue" xml:space="preserve">
|
||||
<value>Publish to queue (direct)</value>
|
||||
</data>
|
||||
<data name="LabelTimestamp" xml:space="preserve">
|
||||
<value>Timestamp</value>
|
||||
</data>
|
||||
<data name="LabelType" xml:space="preserve">
|
||||
<value>Type</value>
|
||||
</data>
|
||||
<data name="LabelUserId" xml:space="preserve">
|
||||
<value>User ID</value>
|
||||
</data>
|
||||
<data name="PropertiesCollapse" xml:space="preserve">
|
||||
<value>⏶ Collapse</value>
|
||||
</data>
|
||||
<data name="PropertiesExpand" xml:space="preserve">
|
||||
<value>⏷ Expand</value>
|
||||
</data>
|
||||
</root>
|
@ -28,8 +28,8 @@
|
||||
<ColumnDefinition Width="Auto" MinWidth="150"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock Grid.Column="0" Grid.Row="0" Text="{Binding Timestamp, StringFormat=g}" Style="{StaticResource Timestamp}"></TextBlock>
|
||||
<TextBlock Grid.Column="1" Grid.Row="0" Text="{Binding RoutingKey}" Style="{StaticResource Routingkey}"></TextBlock>
|
||||
<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>
|
||||
</DataTemplate>
|
||||
</ListBox.ItemTemplate>
|
||||
|
@ -6,7 +6,6 @@ using System.Threading.Tasks;
|
||||
using System.Windows.Input;
|
||||
using PettingZoo.Core.Connection;
|
||||
using PettingZoo.Core.Rendering;
|
||||
using PettingZoo.RabbitMQ;
|
||||
|
||||
// TODO update title with unread message count if tab is not active
|
||||
|
||||
@ -16,36 +15,36 @@ namespace PettingZoo.UI.Tab.Subscriber
|
||||
{
|
||||
private readonly ISubscriber subscriber;
|
||||
private readonly TaskScheduler uiScheduler;
|
||||
private MessageInfo? selectedMessage;
|
||||
private ReceivedMessageInfo? selectedMessage;
|
||||
private readonly DelegateCommand clearCommand;
|
||||
private readonly TabToolbarCommand[] toolbarCommands;
|
||||
private IDictionary<string, string>? selectedMessageProperties;
|
||||
|
||||
|
||||
public ICommand ClearCommand => clearCommand;
|
||||
|
||||
public ObservableCollection<MessageInfo> Messages { get; }
|
||||
public ObservableCollection<ReceivedMessageInfo> Messages { get; }
|
||||
|
||||
public MessageInfo? SelectedMessage
|
||||
public ReceivedMessageInfo? SelectedMessage
|
||||
{
|
||||
get => selectedMessage;
|
||||
set
|
||||
{
|
||||
if (value == selectedMessage)
|
||||
return;
|
||||
|
||||
selectedMessage = value;
|
||||
RaisePropertyChanged();
|
||||
RaiseOtherPropertyChanged(nameof(SelectedMessageBody));
|
||||
RaiseOtherPropertyChanged(nameof(SelectedMessageProperties));
|
||||
if (SetField(ref selectedMessage, value, otherPropertiesChanged: new[] { nameof(SelectedMessageBody) }))
|
||||
UpdateSelectedMessageProperties();
|
||||
}
|
||||
}
|
||||
|
||||
public string SelectedMessageBody =>
|
||||
SelectedMessage != null
|
||||
? MessageBodyRenderer.Render(SelectedMessage.Body, SelectedMessage.Properties.ContentType())
|
||||
? MessageBodyRenderer.Render(SelectedMessage.Body, SelectedMessage.Properties.ContentType)
|
||||
: "";
|
||||
|
||||
public IDictionary<string, string>? SelectedMessageProperties => SelectedMessage?.Properties;
|
||||
public IDictionary<string, string>? SelectedMessageProperties
|
||||
{
|
||||
get => selectedMessageProperties;
|
||||
set => SetField(ref selectedMessageProperties, value);
|
||||
}
|
||||
|
||||
public string Title => $"{subscriber.Exchange} - {subscriber.RoutingKey}";
|
||||
public IEnumerable<TabToolbarCommand> ToolbarCommands => toolbarCommands;
|
||||
@ -57,7 +56,7 @@ namespace PettingZoo.UI.Tab.Subscriber
|
||||
|
||||
uiScheduler = TaskScheduler.FromCurrentSynchronizationContext();
|
||||
|
||||
Messages = new ObservableCollection<MessageInfo>();
|
||||
Messages = new ObservableCollection<ReceivedMessageInfo>();
|
||||
clearCommand = new DelegateCommand(ClearExecute, ClearCanExecute);
|
||||
|
||||
toolbarCommands = new[]
|
||||
@ -93,11 +92,18 @@ namespace PettingZoo.UI.Tab.Subscriber
|
||||
}
|
||||
|
||||
|
||||
private void UpdateSelectedMessageProperties()
|
||||
{
|
||||
SelectedMessageProperties = SelectedMessage != null
|
||||
? MessagePropertiesRenderer.Render(SelectedMessage.Properties)
|
||||
: null;
|
||||
}
|
||||
|
||||
|
||||
private void RunFromUiScheduler(Action action)
|
||||
{
|
||||
_ = Task.Factory.StartNew(action, CancellationToken.None, TaskCreationOptions.None, uiScheduler);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -116,8 +122,8 @@ namespace PettingZoo.UI.Tab.Subscriber
|
||||
}
|
||||
|
||||
|
||||
public string Exchange { get; } = "dummy";
|
||||
public string RoutingKey { get; } = "dummy";
|
||||
public string Exchange => "dummy";
|
||||
public string RoutingKey => "dummy";
|
||||
|
||||
#pragma warning disable CS0067
|
||||
public event EventHandler<MessageReceivedEventArgs>? MessageReceived;
|
||||
|
Loading…
Reference in New Issue
Block a user