Upgraded to .NET 6
Implemented Tapeti compatible publishing WIP: example generator from Tapeti message classes (UI still hidden)
This commit is contained in:
parent
229fc9415d
commit
057cac4e22
@ -1,164 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Immutable;
|
||||
using System.IO;
|
||||
using System.Reflection.Metadata;
|
||||
using System.Reflection.PortableExecutable;
|
||||
using System.Text;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace ParseTapetiMessagesPrototype
|
||||
{
|
||||
public static class MetadataReaderMessageParser
|
||||
{
|
||||
public static void ParseAssembly(string classLibraryFilename)
|
||||
{
|
||||
try
|
||||
{
|
||||
using var fileStream = new FileStream(classLibraryFilename, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
|
||||
using var peReader = new PEReader(fileStream);
|
||||
|
||||
var metadataReader = peReader.GetMetadataReader();
|
||||
|
||||
// ReSharper disable once ForeachCanBePartlyConvertedToQueryUsingAnotherGetEnumerator
|
||||
foreach (var typeDefinitionHandle in metadataReader.TypeDefinitions)
|
||||
{
|
||||
var typeDefinition = metadataReader.GetTypeDefinition(typeDefinitionHandle);
|
||||
HandleTypeDefinition(metadataReader, typeDefinition);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Console.WriteLine(e.Message);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static void HandleTypeDefinition(MetadataReader metadataReader, TypeDefinition typeDefinition)
|
||||
{
|
||||
var typeNamespace = metadataReader.GetString(typeDefinition.Namespace);
|
||||
var typeName = metadataReader.GetString(typeDefinition.Name);
|
||||
|
||||
// For this prototype, filter out anything not ending in Message
|
||||
// Might want to show a full tree in PettingZoo since this is just a convention
|
||||
if (!typeName.EndsWith("Message"))
|
||||
return;
|
||||
|
||||
Console.WriteLine($"{typeNamespace}.{typeName}");
|
||||
|
||||
var example = new JObject();
|
||||
|
||||
// ReSharper disable once ForeachCanBePartlyConvertedToQueryUsingAnotherGetEnumerator
|
||||
foreach (var propertyDefinitionHandle in typeDefinition.GetProperties())
|
||||
{
|
||||
// TODO get properties from base class
|
||||
|
||||
var propertyDefinition = metadataReader.GetPropertyDefinition(propertyDefinitionHandle);
|
||||
HandlePropertyDefinition(metadataReader, propertyDefinition, example);
|
||||
}
|
||||
|
||||
Console.WriteLine(example.ToString());
|
||||
Console.WriteLine();
|
||||
}
|
||||
|
||||
private static void HandlePropertyDefinition(MetadataReader metadataReader, PropertyDefinition propertyDefinition, JObject targetObject)
|
||||
{
|
||||
var fieldName = metadataReader.GetString(propertyDefinition.Name);
|
||||
var signature = propertyDefinition.DecodeSignature(new JsonSignatureProvider(), null);
|
||||
|
||||
targetObject.Add(fieldName, signature.ReturnType);
|
||||
}
|
||||
|
||||
|
||||
private class JsonSignatureProvider : ISignatureTypeProvider<JToken, object>
|
||||
{
|
||||
public JToken GetPrimitiveType(PrimitiveTypeCode typeCode)
|
||||
{
|
||||
return typeCode switch
|
||||
{
|
||||
PrimitiveTypeCode.Boolean => false,
|
||||
|
||||
PrimitiveTypeCode.Byte or
|
||||
PrimitiveTypeCode.Int16 or
|
||||
PrimitiveTypeCode.Int32 or
|
||||
PrimitiveTypeCode.Int64 or
|
||||
PrimitiveTypeCode.IntPtr or
|
||||
PrimitiveTypeCode.SByte or
|
||||
PrimitiveTypeCode.UInt16 or
|
||||
PrimitiveTypeCode.UInt32 or
|
||||
PrimitiveTypeCode.UInt64 or
|
||||
PrimitiveTypeCode.UIntPtr => 0,
|
||||
|
||||
PrimitiveTypeCode.Char or
|
||||
PrimitiveTypeCode.String => "",
|
||||
|
||||
PrimitiveTypeCode.Double or
|
||||
PrimitiveTypeCode.Single => 0.0,
|
||||
|
||||
// TODO recurse
|
||||
PrimitiveTypeCode.Object => "OBJECT",
|
||||
|
||||
_ => $"Unsupported primitive type code: {typeCode}"
|
||||
};
|
||||
}
|
||||
|
||||
public JToken GetTypeFromDefinition(MetadataReader reader, TypeDefinitionHandle handle, byte rawTypeKind = 0) => "typedef";
|
||||
|
||||
public JToken GetTypeFromReference(MetadataReader reader, TypeReferenceHandle handle, byte rawTypeKind = 0)
|
||||
{
|
||||
var typeReference = reader.GetTypeReference(handle);
|
||||
var typeName = reader.GetString(typeReference.Name);
|
||||
|
||||
return typeName;
|
||||
}
|
||||
|
||||
|
||||
public JToken GetTypeFromSpecification(MetadataReader reader, object genericContext, TypeSpecificationHandle handle, byte rawTypeKind = 0) => "typespec";
|
||||
|
||||
public JToken GetSZArrayType(JToken elementType) => new JValue(elementType + "[]");
|
||||
public JToken GetPointerType(JToken elementType) => null;
|
||||
public JToken GetByReferenceType(JToken elementType) => null;
|
||||
public JToken GetGenericMethodParameter(object genericContext, int index) => "!!" + index;
|
||||
public JToken GetGenericTypeParameter(object genericContext, int index) => "!" + index;
|
||||
|
||||
public JToken GetPinnedType(JToken elementType) => elementType + " pinned";
|
||||
public JToken GetGenericInstantiation(JToken genericType, ImmutableArray<JToken> typeArguments) => genericType + "<" + string.Join(",", typeArguments) + ">";
|
||||
public JToken GetModifiedType(JToken modifierType, JToken unmodifiedType, bool isRequired) => unmodifiedType + (isRequired ? " modreq(" : " modopt(") + modifierType + ")";
|
||||
|
||||
public JToken GetArrayType(JToken elementType, ArrayShape shape)
|
||||
{
|
||||
var builder = new StringBuilder();
|
||||
|
||||
builder.Append(elementType);
|
||||
builder.Append('[');
|
||||
|
||||
for (int i = 0; i < shape.Rank; i++)
|
||||
{
|
||||
int lowerBound = 0;
|
||||
|
||||
if (i < shape.LowerBounds.Length)
|
||||
{
|
||||
lowerBound = shape.LowerBounds[i];
|
||||
builder.Append(lowerBound);
|
||||
}
|
||||
|
||||
builder.Append("...");
|
||||
|
||||
if (i < shape.Sizes.Length)
|
||||
{
|
||||
builder.Append(lowerBound + shape.Sizes[i] - 1);
|
||||
}
|
||||
|
||||
if (i < shape.Rank - 1)
|
||||
{
|
||||
builder.Append(',');
|
||||
}
|
||||
}
|
||||
|
||||
builder.Append(']');
|
||||
return builder.ToString();
|
||||
}
|
||||
|
||||
public JToken GetFunctionPointerType(MethodSignature<JToken> signature) => "methodptr(something)";
|
||||
}
|
||||
}
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
@ -1,21 +0,0 @@
|
||||
namespace ParseTapetiMessagesPrototype
|
||||
{
|
||||
public class Program
|
||||
{
|
||||
public static void Main()
|
||||
{
|
||||
const string classLibraryFilename = "D:\\Temp\\lib\\netstandard2.0\\Messaging.Relatie.dll";
|
||||
|
||||
// There are advantages to using the MetadataReader, for example no code is run (LoadAssemblyForReflection is no longer
|
||||
// supported in .NET Core) and the assembly is not locked at all. This comes at the cost of complexity however, so
|
||||
// this prototype explores both options.
|
||||
//
|
||||
// In the final version perhaps we can work around loading the assembly into our own process by spawning a new process
|
||||
// to convert it into metadata used by the main process.
|
||||
|
||||
//MetadataReaderMessageParser.ParseAssembly(classLibraryFilename);
|
||||
|
||||
AssemblyLoaderMessageParser.ParseAssembly(classLibraryFilename);
|
||||
}
|
||||
}
|
||||
}
|
25
PettingZoo.Core/Generator/IExampleGenerator.cs
Normal file
25
PettingZoo.Core/Generator/IExampleGenerator.cs
Normal file
@ -0,0 +1,25 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace PettingZoo.Core.Generator
|
||||
{
|
||||
public interface IExampleSource : IDisposable
|
||||
{
|
||||
IExampleFolder GetRootFolder();
|
||||
}
|
||||
|
||||
|
||||
public interface IExampleFolder
|
||||
{
|
||||
public string Name { get; }
|
||||
|
||||
public IReadOnlyList<IExampleFolder> Folders { get; }
|
||||
public IReadOnlyList<IExampleMessage> Messages { get; }
|
||||
}
|
||||
|
||||
|
||||
public interface IExampleMessage
|
||||
{
|
||||
string Generate();
|
||||
}
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
|
15
PettingZoo.Tapeti/PettingZoo.Tapeti.csproj
Normal file
15
PettingZoo.Tapeti/PettingZoo.Tapeti.csproj
Normal file
@ -0,0 +1,15 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="System.Reflection.MetadataLoadContext" Version="6.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\PettingZoo.Core\PettingZoo.Core.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
187
PettingZoo.Tapeti/TapetiClassLibraryExampleSource.cs
Normal file
187
PettingZoo.Tapeti/TapetiClassLibraryExampleSource.cs
Normal file
@ -0,0 +1,187 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
using Newtonsoft.Json;
|
||||
using PettingZoo.Core.Generator;
|
||||
|
||||
namespace PettingZoo.Tapeti
|
||||
{
|
||||
public class TapetiClassLibraryExampleSource : IExampleSource
|
||||
{
|
||||
private readonly string classLibraryFilename;
|
||||
private readonly IEnumerable<string> extraAssemblies;
|
||||
private Lazy<AssemblySource> assemblySource;
|
||||
|
||||
|
||||
public TapetiClassLibraryExampleSource(string classLibraryFilename, IEnumerable<string> extraAssemblies)
|
||||
{
|
||||
this.classLibraryFilename = classLibraryFilename;
|
||||
this.extraAssemblies = extraAssemblies;
|
||||
|
||||
assemblySource = new Lazy<AssemblySource>(AssemblySourceFactory);
|
||||
}
|
||||
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (assemblySource.IsValueCreated)
|
||||
assemblySource.Value.Dispose();
|
||||
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
|
||||
public IExampleFolder GetRootFolder()
|
||||
{
|
||||
return assemblySource.Value.RootFolder;
|
||||
}
|
||||
|
||||
|
||||
private AssemblySource AssemblySourceFactory()
|
||||
{
|
||||
var runtimeAssemblies = Directory.GetFiles(RuntimeEnvironment.GetRuntimeDirectory(), "*.dll");
|
||||
|
||||
var paths = runtimeAssemblies
|
||||
.Concat(extraAssemblies)
|
||||
.Append(classLibraryFilename);
|
||||
|
||||
// TODO can we use a custom resolver to detect missing references?
|
||||
var resolver = new PathAssemblyResolver(paths);
|
||||
var loadContext = new MetadataLoadContext(resolver);
|
||||
try
|
||||
{
|
||||
var assembly = loadContext.LoadFromAssemblyPath(classLibraryFilename);
|
||||
var rootFolder = new Folder(@"Root");
|
||||
|
||||
|
||||
foreach (var assemblyType in assembly.GetTypes())
|
||||
AddType(assemblyType, rootFolder);
|
||||
|
||||
|
||||
return new AssemblySource
|
||||
{
|
||||
LoadContext = loadContext,
|
||||
RootFolder = rootFolder
|
||||
};
|
||||
}
|
||||
catch
|
||||
{
|
||||
loadContext.Dispose();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void AddType(Type type, Folder rootFolder)
|
||||
{
|
||||
if (!type.IsClass)
|
||||
return;
|
||||
|
||||
var assemblyName = type.Assembly.GetName().Name + ".";
|
||||
var typeNamespace = type.Namespace ?? "";
|
||||
|
||||
if (typeNamespace.StartsWith(assemblyName))
|
||||
typeNamespace = typeNamespace.Substring(assemblyName.Length);
|
||||
|
||||
var folder = CreateFolder(rootFolder, typeNamespace);
|
||||
folder.AddMessage(new Message(type));
|
||||
}
|
||||
|
||||
|
||||
private static Folder CreateFolder(Folder rootFolder, string typeNamespace)
|
||||
{
|
||||
var parts = typeNamespace.Split('.');
|
||||
if (parts.Length == 0)
|
||||
return rootFolder;
|
||||
|
||||
var folder = rootFolder;
|
||||
|
||||
foreach (var part in parts)
|
||||
folder = folder.CreateFolder(part);
|
||||
|
||||
return folder;
|
||||
}
|
||||
|
||||
|
||||
private class Folder : IExampleFolder
|
||||
{
|
||||
private readonly List<Folder> folders = new();
|
||||
private readonly List<IExampleMessage> messages = new();
|
||||
|
||||
|
||||
public string Name { get; }
|
||||
public IReadOnlyList<IExampleFolder> Folders => folders;
|
||||
public IReadOnlyList<IExampleMessage> Messages => messages;
|
||||
|
||||
|
||||
public Folder(string name)
|
||||
{
|
||||
Name = name;
|
||||
}
|
||||
|
||||
|
||||
public Folder CreateFolder(string name)
|
||||
{
|
||||
var folder = folders.FirstOrDefault(f => f.Name == name);
|
||||
if (folder != null)
|
||||
return folder;
|
||||
|
||||
folder = new Folder(name);
|
||||
folders.Add(folder);
|
||||
return folder;
|
||||
}
|
||||
|
||||
|
||||
public void AddMessage(IExampleMessage message)
|
||||
{
|
||||
messages.Add(message);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private class Message : IExampleMessage
|
||||
{
|
||||
private readonly Type type;
|
||||
|
||||
|
||||
public Message(Type type)
|
||||
{
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
|
||||
public string Generate()
|
||||
{
|
||||
/*
|
||||
We can't create an instance of the type to serialize easily, as most will depend on
|
||||
assemblies not included in the NuGet package, so we'll parse the Type ourselves.
|
||||
This is still much easier than using MetadataReader, as we can more easily check against
|
||||
standard types like Nullable.
|
||||
|
||||
The only external dependencies should be the attributes, like [RequiredGuid]. The messaging models
|
||||
themselves should not inherit from classes outside of their assembly, or include properties
|
||||
with types from other assemblies. With that assumption, walking the class structure should be safe.
|
||||
The extraAssemblies passed to TapetiClassLibraryExampleSource can also be used to give it a better chance.
|
||||
*/
|
||||
var serialized = TypeToJObjectConverter.Convert(type);
|
||||
return serialized.ToString(Formatting.Indented);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private class AssemblySource : IDisposable
|
||||
{
|
||||
public MetadataLoadContext LoadContext { get; init; }
|
||||
public IExampleFolder RootFolder { get; init; }
|
||||
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
LoadContext.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -2,58 +2,13 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Runtime.Loader;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace ParseTapetiMessagesPrototype
|
||||
namespace PettingZoo.Tapeti
|
||||
{
|
||||
public static class AssemblyLoaderMessageParser
|
||||
internal class TypeToJObjectConverter
|
||||
{
|
||||
public static void ParseAssembly(string classLibraryFilename)
|
||||
{
|
||||
var loadContext = new AssemblyLoadContext(null, true);
|
||||
try
|
||||
{
|
||||
var assembly = loadContext.LoadFromAssemblyPath(classLibraryFilename);
|
||||
|
||||
foreach (var assemblyType in assembly.GetTypes())
|
||||
HandleType(assemblyType);
|
||||
}
|
||||
finally
|
||||
{
|
||||
loadContext.Unload();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static void HandleType(Type type)
|
||||
{
|
||||
if (!type.IsClass)
|
||||
return;
|
||||
|
||||
// For this prototype, filter out anything not ending in Message
|
||||
// Might want to show a full tree in PettingZoo since this is just a convention
|
||||
if (!type.Name.EndsWith("Message") || type.Name != "RelatieUpdateMessage")
|
||||
return;
|
||||
|
||||
Console.WriteLine($"{type.Namespace}.{type.Name}");
|
||||
|
||||
// We can't create an instance of the type to serialize easily, as most will depend on
|
||||
// assemblies not included in the NuGet package, so we'll parse the Type ourselves.
|
||||
// This is still slightly easier than using MetadataReader, as we can more easily check against
|
||||
// standard types like Nullable.
|
||||
//
|
||||
// The only external dependencies should be the attributes, like [RequiredGuid]. The messaging models
|
||||
// themselves should not inherit from classes outside of their assembly, or include properties
|
||||
// with types from other assemblies. With that assumption, walking the class structure should be safe.
|
||||
var serialized = TypeToJObject(type);
|
||||
|
||||
Console.WriteLine(serialized);
|
||||
Console.WriteLine("");
|
||||
}
|
||||
|
||||
|
||||
private static JObject TypeToJObject(Type type)
|
||||
public static JObject Convert(Type type)
|
||||
{
|
||||
var result = new JObject();
|
||||
|
||||
@ -101,14 +56,14 @@ namespace ParseTapetiMessagesPrototype
|
||||
.FirstOrDefault(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IEnumerable<>));
|
||||
|
||||
if (enumerableInterface != null)
|
||||
return new JArray(TypeToJObject(enumerableInterface.GetGenericArguments()[0]));
|
||||
return new JArray(Convert(enumerableInterface.GetGenericArguments()[0]));
|
||||
|
||||
|
||||
return TypeToJObject(actualType);
|
||||
return Convert(actualType);
|
||||
}
|
||||
|
||||
if (actualType.IsArray)
|
||||
return new JArray(TypeToJObject(actualType.GetElementType()));
|
||||
return new JArray(Convert(actualType.GetElementType()));
|
||||
|
||||
if (actualType.IsEnum)
|
||||
return Enum.GetNames(actualType).FirstOrDefault();
|
||||
@ -129,5 +84,7 @@ namespace ParseTapetiMessagesPrototype
|
||||
? mappedToken
|
||||
: $"(unknown type: {actualType.Name})";
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 16
|
||||
VisualStudioVersion = 16.0.31911.196
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.0.31912.275
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PettingZoo", "PettingZoo\PettingZoo.csproj", "{24819D09-C747-4356-B686-D9DE9CAA6F59}"
|
||||
EndProject
|
||||
@ -14,7 +14,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PettingZoo.Core", "PettingZ
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PettingZoo.RabbitMQ", "PettingZoo.RabbitMQ\PettingZoo.RabbitMQ.csproj", "{220149F3-A8D6-44ED-B3B6-DFE506EB018A}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ParseTapetiMessagesPrototype", "ParseTapetiMessagesPrototype\ParseTapetiMessagesPrototype.csproj", "{B06DDB4F-04D1-4325-9F7B-5FBA0AAE47E7}"
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PettingZoo.Tapeti", "PettingZoo.Tapeti\PettingZoo.Tapeti.csproj", "{1763AB04-59D9-4663-B207-D6302FFAACD5}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
@ -34,10 +34,10 @@ Global
|
||||
{220149F3-A8D6-44ED-B3B6-DFE506EB018A}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{220149F3-A8D6-44ED-B3B6-DFE506EB018A}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{220149F3-A8D6-44ED-B3B6-DFE506EB018A}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{B06DDB4F-04D1-4325-9F7B-5FBA0AAE47E7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{B06DDB4F-04D1-4325-9F7B-5FBA0AAE47E7}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{B06DDB4F-04D1-4325-9F7B-5FBA0AAE47E7}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{B06DDB4F-04D1-4325-9F7B-5FBA0AAE47E7}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{1763AB04-59D9-4663-B207-D6302FFAACD5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{1763AB04-59D9-4663-B207-D6302FFAACD5}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{1763AB04-59D9-4663-B207-D6302FFAACD5}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{1763AB04-59D9-4663-B207-D6302FFAACD5}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<TargetFramework>net5.0-windows</TargetFramework>
|
||||
<TargetFramework>net6.0-windows</TargetFramework>
|
||||
<UseWPF>true</UseWPF>
|
||||
<Authors>Mark van Renswoude</Authors>
|
||||
<Product>Petting Zoo</Product>
|
||||
@ -46,6 +46,11 @@
|
||||
<DesignTime>True</DesignTime>
|
||||
<AutoGen>True</AutoGen>
|
||||
</Compile>
|
||||
<Compile Update="UI\Example\ExamplePickerDialogStrings.Designer.cs">
|
||||
<DesignTime>True</DesignTime>
|
||||
<AutoGen>True</AutoGen>
|
||||
<DependentUpon>ExamplePickerDialogStrings.resx</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Update="UI\Main\MainWindowStrings.Designer.cs">
|
||||
<DependentUpon>MainWindowStrings.resx</DependentUpon>
|
||||
<DesignTime>True</DesignTime>
|
||||
@ -56,6 +61,14 @@
|
||||
<DesignTime>True</DesignTime>
|
||||
<AutoGen>True</AutoGen>
|
||||
</Compile>
|
||||
<Compile Update="UI\Tab\Publisher\TapetiPublisherViewStrings.Designer.cs">
|
||||
<DependentUpon>TapetiPublisherViewStrings.resx</DependentUpon>
|
||||
<DesignTime>True</DesignTime>
|
||||
<AutoGen>True</AutoGen>
|
||||
</Compile>
|
||||
<Compile Update="UI\Tab\Publisher\TapetiPublisherView.xaml.cs">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Update="UI\Tab\Publisher\RawPublisherViewStrings.Designer.cs">
|
||||
<DependentUpon>RawPublisherViewStrings.resx</DependentUpon>
|
||||
<DesignTime>True</DesignTime>
|
||||
@ -78,6 +91,10 @@
|
||||
<LastGenOutput>ConnectionWindowStrings.Designer.cs</LastGenOutput>
|
||||
<Generator>PublicResXFileCodeGenerator</Generator>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Update="UI\Example\ExamplePickerDialogStrings.resx">
|
||||
<Generator>PublicResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>ExamplePickerDialogStrings.Designer.cs</LastGenOutput>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Update="UI\Main\MainWindowStrings.resx">
|
||||
<LastGenOutput>MainWindowStrings.Designer.cs</LastGenOutput>
|
||||
<Generator>PublicResXFileCodeGenerator</Generator>
|
||||
@ -86,6 +103,10 @@
|
||||
<LastGenOutput>SubscribeWindowStrings.Designer.cs</LastGenOutput>
|
||||
<Generator>PublicResXFileCodeGenerator</Generator>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Update="UI\Tab\Publisher\TapetiPublisherViewStrings.resx">
|
||||
<LastGenOutput>TapetiPublisherViewStrings.Designer.cs</LastGenOutput>
|
||||
<Generator>PublicResXFileCodeGenerator</Generator>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Update="UI\Tab\Publisher\RawPublisherViewStrings.resx">
|
||||
<LastGenOutput>RawPublisherViewStrings.Designer.cs</LastGenOutput>
|
||||
<Generator>PublicResXFileCodeGenerator</Generator>
|
||||
@ -113,6 +134,10 @@
|
||||
<Page Update="UI\Tab\Publisher\PublisherView.xaml">
|
||||
<XamlRuntime>$(DefaultXamlRuntime)</XamlRuntime>
|
||||
</Page>
|
||||
<Page Update="UI\Tab\Publisher\TapetiPublisherView.xaml">
|
||||
<XamlRuntime>$(DefaultXamlRuntime)</XamlRuntime>
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Update="UI\Tab\Subscriber\SubscriberView.xaml">
|
||||
<XamlRuntime>$(DefaultXamlRuntime)</XamlRuntime>
|
||||
</Page>
|
||||
|
@ -67,8 +67,9 @@
|
||||
<Style x:Key="RoutingKey">
|
||||
</Style>
|
||||
|
||||
<Style x:Key="TypeSelection" TargetType="{x:Type FrameworkElement}">
|
||||
<Style x:Key="TypeSelection" TargetType="{x:Type ToggleButton}">
|
||||
<Setter Property="Margin" Value="0 0 8 0" />
|
||||
<Setter Property="Padding" Value="8 4 8 4" />
|
||||
<Setter Property="VerticalAlignment" Value="Center" />
|
||||
</Style>
|
||||
|
||||
|
12
PettingZoo/UI/Example/ExamplePickerDialog.xaml
Normal file
12
PettingZoo/UI/Example/ExamplePickerDialog.xaml
Normal file
@ -0,0 +1,12 @@
|
||||
<Window x:Class="PettingZoo.UI.Example.ExamplePickerDialog"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:example="clr-namespace:PettingZoo.UI.Example"
|
||||
mc:Ignorable="d"
|
||||
Title="{x:Static example:ExamplePickerDialogStrings.WindowTitle}" Height="800" Width="600">
|
||||
<Grid>
|
||||
|
||||
</Grid>
|
||||
</Window>
|
15
PettingZoo/UI/Example/ExamplePickerDialog.xaml.cs
Normal file
15
PettingZoo/UI/Example/ExamplePickerDialog.xaml.cs
Normal file
@ -0,0 +1,15 @@
|
||||
using System.Windows;
|
||||
|
||||
namespace PettingZoo.UI.Example
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for ExamplePickerDialog.xaml
|
||||
/// </summary>
|
||||
public partial class ExamplePickerDialog : Window
|
||||
{
|
||||
public ExamplePickerDialog()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
72
PettingZoo/UI/Example/ExamplePickerDialogStrings.Designer.cs
generated
Normal file
72
PettingZoo/UI/Example/ExamplePickerDialogStrings.Designer.cs
generated
Normal file
@ -0,0 +1,72 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <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.Example {
|
||||
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 ExamplePickerDialogStrings {
|
||||
|
||||
private static global::System.Resources.ResourceManager resourceMan;
|
||||
|
||||
private static global::System.Globalization.CultureInfo resourceCulture;
|
||||
|
||||
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
||||
internal ExamplePickerDialogStrings() {
|
||||
}
|
||||
|
||||
/// <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.Example.ExamplePickerDialogStrings", typeof(ExamplePickerDialogStrings).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 Select example.
|
||||
/// </summary>
|
||||
public static string WindowTitle {
|
||||
get {
|
||||
return ResourceManager.GetString("WindowTitle", resourceCulture);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
123
PettingZoo/UI/Example/ExamplePickerDialogStrings.resx
Normal file
123
PettingZoo/UI/Example/ExamplePickerDialogStrings.resx
Normal file
@ -0,0 +1,123 @@
|
||||
<?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="WindowTitle" xml:space="preserve">
|
||||
<value>Select example</value>
|
||||
</data>
|
||||
</root>
|
6
PettingZoo/UI/Example/ExamplePickerDialogViewModel.cs
Normal file
6
PettingZoo/UI/Example/ExamplePickerDialogViewModel.cs
Normal file
@ -0,0 +1,6 @@
|
||||
namespace PettingZoo.UI.Example
|
||||
{
|
||||
public class ExamplePickerDialogViewModel
|
||||
{
|
||||
}
|
||||
}
|
@ -37,8 +37,7 @@ namespace PettingZoo.UI.Main
|
||||
|
||||
private void MainWindow_OnLoaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
// TODO support command-line parameters for easier testing
|
||||
//viewModel.ConnectCommand.Execute(null);
|
||||
viewModel.ConnectCommand.Execute(null);
|
||||
}
|
||||
|
||||
|
||||
|
@ -15,10 +15,9 @@
|
||||
<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 Orientation="Horizontal" Grid.Row="0" HorizontalAlignment="Center">
|
||||
<ToggleButton Content="{x:Static res:PublisherViewStrings.OptionMessageTypeRaw}" Style="{StaticResource TypeSelection}" IsChecked="{Binding MessageTypeRaw}" />
|
||||
<ToggleButton Content="{x:Static res:PublisherViewStrings.OptionMessageTypeTapeti}" Style="{StaticResource TypeSelection}" IsChecked="{Binding MessageTypeTapeti}" />
|
||||
</StackPanel>
|
||||
|
||||
<ScrollViewer Grid.Row="1" VerticalScrollBarVisibility="Auto">
|
||||
|
@ -110,22 +110,21 @@ namespace PettingZoo.UI.Tab.Publisher
|
||||
MessageTypeControl = rawPublisherView;
|
||||
|
||||
messageTypePublishCommand = rawPublisherViewModel.PublishCommand;
|
||||
publishCommand.RaiseCanExecuteChanged();
|
||||
break;
|
||||
|
||||
case MessageType.Tapeti:
|
||||
// TODO
|
||||
var tapetiPublisherViewModel = new RawPublisherViewModel(connection);
|
||||
tapetiPublisherView ??= new RawPublisherView(tapetiPublisherViewModel);
|
||||
var tapetiPublisherViewModel = new TapetiPublisherViewModel(connection);
|
||||
tapetiPublisherView ??= new TapetiPublisherView(tapetiPublisherViewModel);
|
||||
MessageTypeControl = tapetiPublisherView;
|
||||
|
||||
messageTypePublishCommand = tapetiPublisherViewModel.PublishCommand;
|
||||
publishCommand.RaiseCanExecuteChanged();
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new ArgumentException();
|
||||
throw new ArgumentException($@"Unknown message type: {value}", nameof(value));
|
||||
}
|
||||
|
||||
publishCommand.RaiseCanExecuteChanged();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -19,7 +19,7 @@ namespace PettingZoo.UI.Tab.Publisher {
|
||||
// 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", "16.0.0.0")]
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
public class PublisherViewStrings {
|
||||
@ -79,7 +79,7 @@ namespace PettingZoo.UI.Tab.Publisher {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Raw.
|
||||
/// Looks up a localized string similar to Raw message.
|
||||
/// </summary>
|
||||
public static string OptionMessageTypeRaw {
|
||||
get {
|
||||
@ -88,7 +88,7 @@ namespace PettingZoo.UI.Tab.Publisher {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Tapeti.
|
||||
/// Looks up a localized string similar to Tapeti message.
|
||||
/// </summary>
|
||||
public static string OptionMessageTypeTapeti {
|
||||
get {
|
||||
|
@ -124,9 +124,9 @@
|
||||
<value>Message type: </value>
|
||||
</data>
|
||||
<data name="OptionMessageTypeRaw" xml:space="preserve">
|
||||
<value>Raw</value>
|
||||
<value>Raw message</value>
|
||||
</data>
|
||||
<data name="OptionMessageTypeTapeti" xml:space="preserve">
|
||||
<value>Tapeti</value>
|
||||
<value>Tapeti message</value>
|
||||
</data>
|
||||
</root>
|
78
PettingZoo/UI/Tab/Publisher/TapetiPublisherView.xaml
Normal file
78
PettingZoo/UI/Tab/Publisher/TapetiPublisherView.xaml
Normal file
@ -0,0 +1,78 @@
|
||||
<UserControl x:Class="PettingZoo.UI.Tab.Publisher.TapetiPublisherView"
|
||||
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:DesignTimeTapetiPublisherViewModel, 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="16"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto" />
|
||||
</ui:GridLayout.RowDefinitions>
|
||||
|
||||
|
||||
<Label Grid.Row="0" Grid.Column="1">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<RadioButton Content="{x:Static publisher:TapetiPublisherViewStrings.LabelSendToExchange}" IsChecked="{Binding SendToExchange}" Style="{StaticResource TypeSelection}" />
|
||||
<RadioButton Content="{x:Static publisher:TapetiPublisherViewStrings.LabelSendToQueue}" IsChecked="{Binding SendToQueue}" Style="{StaticResource TypeSelection}" />
|
||||
</StackPanel>
|
||||
</Label>
|
||||
|
||||
<Label Grid.Row="1" Grid.Column="0" Content="{x:Static publisher:TapetiPublisherViewStrings.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:TapetiPublisherViewStrings.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:TapetiPublisherViewStrings.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:TapetiPublisherViewStrings.LabelProperties}" Style="{StaticResource SectionLabel}"/>
|
||||
|
||||
<Label Grid.Row="6" Grid.Column="0" Content="{x:Static publisher:TapetiPublisherViewStrings.LabelCorrelationId}" />
|
||||
<TextBox Grid.Row="6" Grid.Column="1" Text="{Binding CorrelationId}" />
|
||||
|
||||
<Label Grid.Row="7" Grid.Column="0" Content="{x:Static publisher:TapetiPublisherViewStrings.LabelReplyTo}" />
|
||||
<TextBox Grid.Row="7" Grid.Column="1" Text="{Binding ReplyTo}" />
|
||||
|
||||
<Label Grid.Row="10" Grid.Column="0" Content="{x:Static publisher:TapetiPublisherViewStrings.LabelAssemblyName}" />
|
||||
<TextBox Grid.Row="10" Grid.Column="1" Text="{Binding AssemblyName, UpdateSourceTrigger=PropertyChanged}" />
|
||||
|
||||
<Label Grid.Row="11" Grid.Column="0" Content="{x:Static publisher:TapetiPublisherViewStrings.LabelClassName}" />
|
||||
<Grid Grid.Row="11" Grid.Column="1">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<TextBox Grid.Column="0" Text="{Binding ClassName}" GotFocus="CaretToEnd" />
|
||||
<!--
|
||||
<Button Grid.Column="1" Content="{x:Static publisher:TapetiPublisherViewStrings.ButtonBrowseClass}" />
|
||||
-->
|
||||
</Grid>
|
||||
|
||||
<Label Grid.Row="12" Grid.Column="0" Content="{x:Static publisher:TapetiPublisherViewStrings.LabelPayload}" />
|
||||
<TextBox Grid.Row="12" Grid.Column="1" Text="{Binding Payload}" AcceptsReturn="True" VerticalScrollBarVisibility="Visible" Height="150" />
|
||||
</ui:GridLayout>
|
||||
</UserControl>
|
26
PettingZoo/UI/Tab/Publisher/TapetiPublisherView.xaml.cs
Normal file
26
PettingZoo/UI/Tab/Publisher/TapetiPublisherView.xaml.cs
Normal file
@ -0,0 +1,26 @@
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace PettingZoo.UI.Tab.Publisher
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for TapetiPublisherView.xaml
|
||||
/// </summary>
|
||||
public partial class TapetiPublisherView
|
||||
{
|
||||
public TapetiPublisherView(TapetiPublisherViewModel viewModel)
|
||||
{
|
||||
InitializeComponent();
|
||||
DataContext = viewModel;
|
||||
}
|
||||
|
||||
|
||||
private void CaretToEnd(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (sender is not TextBox textBox)
|
||||
return;
|
||||
|
||||
textBox.CaretIndex = textBox.Text?.Length ?? 0;
|
||||
}
|
||||
}
|
||||
}
|
170
PettingZoo/UI/Tab/Publisher/TapetiPublisherViewModel.cs
Normal file
170
PettingZoo/UI/Tab/Publisher/TapetiPublisherViewModel.cs
Normal file
@ -0,0 +1,170 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Windows;
|
||||
using System.Windows.Input;
|
||||
using PettingZoo.Core.Connection;
|
||||
using IConnection = PettingZoo.Core.Connection.IConnection;
|
||||
|
||||
namespace PettingZoo.UI.Tab.Publisher
|
||||
{
|
||||
public class TapetiPublisherViewModel : BaseViewModel
|
||||
{
|
||||
private readonly IConnection connection;
|
||||
private readonly DelegateCommand publishCommand;
|
||||
|
||||
private bool sendToExchange = true;
|
||||
private string exchange = "";
|
||||
private string routingKey = "";
|
||||
private string queue = "";
|
||||
|
||||
private MessageDeliveryMode deliveryMode;
|
||||
|
||||
private string correlationId = "";
|
||||
private string replyTo = "";
|
||||
private string payload = "";
|
||||
private string className = "";
|
||||
private string assemblyName = "";
|
||||
|
||||
|
||||
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 CorrelationId
|
||||
{
|
||||
get => correlationId;
|
||||
set => SetField(ref correlationId, value);
|
||||
}
|
||||
|
||||
|
||||
public string ReplyTo
|
||||
{
|
||||
get => replyTo;
|
||||
set => SetField(ref replyTo, value);
|
||||
}
|
||||
|
||||
|
||||
public string ClassName
|
||||
{
|
||||
get => string.IsNullOrEmpty(className) ? AssemblyName + "." : className;
|
||||
set => SetField(ref className, value);
|
||||
}
|
||||
|
||||
|
||||
public string AssemblyName
|
||||
{
|
||||
get => assemblyName;
|
||||
set => SetField(ref assemblyName, value, otherPropertiesChanged:
|
||||
string.IsNullOrEmpty(value) || string.IsNullOrEmpty(className)
|
||||
? new [] { nameof(ClassName) }
|
||||
: null
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
public string Payload
|
||||
{
|
||||
get => payload;
|
||||
set => SetField(ref payload, value);
|
||||
}
|
||||
|
||||
|
||||
public ICommand PublishCommand => publishCommand;
|
||||
|
||||
|
||||
public TapetiPublisherViewModel(IConnection connection)
|
||||
{
|
||||
this.connection = connection;
|
||||
|
||||
publishCommand = new DelegateCommand(PublishExecute, PublishCanExecute);
|
||||
}
|
||||
|
||||
|
||||
private void PublishExecute()
|
||||
{
|
||||
static string? NullIfEmpty(string? value)
|
||||
{
|
||||
return string.IsNullOrEmpty(value) ? null : value;
|
||||
}
|
||||
|
||||
// TODO support for Reply To to dynamic queue which waits for a message (or opens a new subscriber tab?)
|
||||
// TODO background worker / async
|
||||
|
||||
connection.Publish(new PublishMessageInfo(
|
||||
SendToExchange ? Exchange : "",
|
||||
SendToExchange ? RoutingKey : Queue,
|
||||
Encoding.UTF8.GetBytes(Payload),
|
||||
new MessageProperties(new Dictionary<string, string>
|
||||
{
|
||||
{ @"classType", $"{ClassName}:{AssemblyName}" }
|
||||
})
|
||||
{
|
||||
ContentType = @"application/json",
|
||||
CorrelationId = NullIfEmpty(CorrelationId),
|
||||
DeliveryMode = deliveryMode,
|
||||
ReplyTo = NullIfEmpty(ReplyTo)
|
||||
}));
|
||||
}
|
||||
|
||||
|
||||
private bool PublishCanExecute()
|
||||
{
|
||||
// TODO validate input
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public class DesignTimeTapetiPublisherViewModel : TapetiPublisherViewModel
|
||||
{
|
||||
public DesignTimeTapetiPublisherViewModel() : base(null!)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
public override Visibility ExchangeVisibility => Visibility.Visible;
|
||||
public override Visibility QueueVisibility => Visibility.Visible;
|
||||
}
|
||||
}
|
198
PettingZoo/UI/Tab/Publisher/TapetiPublisherViewStrings.Designer.cs
generated
Normal file
198
PettingZoo/UI/Tab/Publisher/TapetiPublisherViewStrings.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.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 TapetiPublisherViewStrings {
|
||||
|
||||
private static global::System.Resources.ResourceManager resourceMan;
|
||||
|
||||
private static global::System.Globalization.CultureInfo resourceCulture;
|
||||
|
||||
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
||||
internal TapetiPublisherViewStrings() {
|
||||
}
|
||||
|
||||
/// <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.TapetiPublisherViewStrings", typeof(TapetiPublisherViewStrings).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 ....
|
||||
/// </summary>
|
||||
public static string ButtonBrowseClass {
|
||||
get {
|
||||
return ResourceManager.GetString("ButtonBrowseClass", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <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 Assembly name.
|
||||
/// </summary>
|
||||
public static string LabelAssemblyName {
|
||||
get {
|
||||
return ResourceManager.GetString("LabelAssemblyName", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Class name (full).
|
||||
/// </summary>
|
||||
public static string LabelClassName {
|
||||
get {
|
||||
return ResourceManager.GetString("LabelClassName", 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 Payload.
|
||||
/// </summary>
|
||||
public static string LabelPayload {
|
||||
get {
|
||||
return ResourceManager.GetString("LabelPayload", 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
165
PettingZoo/UI/Tab/Publisher/TapetiPublisherViewStrings.resx
Normal file
165
PettingZoo/UI/Tab/Publisher/TapetiPublisherViewStrings.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="ButtonBrowseClass" xml:space="preserve">
|
||||
<value>...</value>
|
||||
</data>
|
||||
<data name="DeliveryModeNonPersistent" xml:space="preserve">
|
||||
<value>Transient (non-persistent)</value>
|
||||
</data>
|
||||
<data name="DeliveryModePersistent" xml:space="preserve">
|
||||
<value>Persistent</value>
|
||||
</data>
|
||||
<data name="LabelAssemblyName" xml:space="preserve">
|
||||
<value>Assembly name</value>
|
||||
</data>
|
||||
<data name="LabelClassName" xml:space="preserve">
|
||||
<value>Class name (full)</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="LabelPayload" xml:space="preserve">
|
||||
<value>Payload</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>
|
||||
</root>
|
@ -8,6 +8,8 @@ using PettingZoo.Core.Connection;
|
||||
using PettingZoo.Core.Rendering;
|
||||
|
||||
// TODO update title with unread message count if tab is not active
|
||||
// TODO export option (to Tapeti.Cmd compatible format / command-line of course)
|
||||
// TODO send message to (new) publisher tab
|
||||
|
||||
namespace PettingZoo.UI.Tab.Subscriber
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user