From 057cac4e22e20f12279d2152aa2a530df5b6829e Mon Sep 17 00:00:00 2001 From: Mark van Renswoude Date: Wed, 15 Dec 2021 10:50:45 +0100 Subject: [PATCH] Upgraded to .NET 6 Implemented Tapeti compatible publishing WIP: example generator from Tapeti message classes (UI still hidden) --- .../MetadataReaderMessageParser.cs | 164 --------------- .../ParseTapetiMessagesPrototype.csproj | 12 -- ParseTapetiMessagesPrototype/Program.cs | 21 -- .../Generator/IExampleGenerator.cs | 25 +++ PettingZoo.Core/PettingZoo.Core.csproj | 2 +- .../PettingZoo.RabbitMQ.csproj | 2 +- PettingZoo.Tapeti/PettingZoo.Tapeti.csproj | 15 ++ .../TapetiClassLibraryExampleSource.cs | 187 +++++++++++++++++ .../TypeToJObjectConverter.cs | 83 ++------ PettingZoo.sln | 14 +- PettingZoo/PettingZoo.csproj | 27 ++- PettingZoo/Style.xaml | 3 +- .../UI/Example/ExamplePickerDialog.xaml | 12 ++ .../UI/Example/ExamplePickerDialog.xaml.cs | 15 ++ .../ExamplePickerDialogStrings.Designer.cs | 72 +++++++ .../Example/ExamplePickerDialogStrings.resx | 123 +++++++++++ .../Example/ExamplePickerDialogViewModel.cs | 6 + PettingZoo/UI/Main/MainWindow.xaml.cs | 3 +- .../UI/Tab/Publisher/PublisherView.xaml | 7 +- .../UI/Tab/Publisher/PublisherViewModel.cs | 11 +- .../PublisherViewStrings.Designer.cs | 6 +- .../Tab/Publisher/PublisherViewStrings.resx | 4 +- .../UI/Tab/Publisher/TapetiPublisherView.xaml | 78 +++++++ .../Tab/Publisher/TapetiPublisherView.xaml.cs | 26 +++ .../Tab/Publisher/TapetiPublisherViewModel.cs | 170 +++++++++++++++ .../TapetiPublisherViewStrings.Designer.cs | 198 ++++++++++++++++++ .../Publisher/TapetiPublisherViewStrings.resx | 165 +++++++++++++++ .../UI/Tab/Subscriber/SubscriberViewModel.cs | 2 + 28 files changed, 1165 insertions(+), 288 deletions(-) delete mode 100644 ParseTapetiMessagesPrototype/MetadataReaderMessageParser.cs delete mode 100644 ParseTapetiMessagesPrototype/ParseTapetiMessagesPrototype.csproj delete mode 100644 ParseTapetiMessagesPrototype/Program.cs create mode 100644 PettingZoo.Core/Generator/IExampleGenerator.cs create mode 100644 PettingZoo.Tapeti/PettingZoo.Tapeti.csproj create mode 100644 PettingZoo.Tapeti/TapetiClassLibraryExampleSource.cs rename ParseTapetiMessagesPrototype/AssemblyLoaderMessageParser.cs => PettingZoo.Tapeti/TypeToJObjectConverter.cs (50%) create mode 100644 PettingZoo/UI/Example/ExamplePickerDialog.xaml create mode 100644 PettingZoo/UI/Example/ExamplePickerDialog.xaml.cs create mode 100644 PettingZoo/UI/Example/ExamplePickerDialogStrings.Designer.cs create mode 100644 PettingZoo/UI/Example/ExamplePickerDialogStrings.resx create mode 100644 PettingZoo/UI/Example/ExamplePickerDialogViewModel.cs create mode 100644 PettingZoo/UI/Tab/Publisher/TapetiPublisherView.xaml create mode 100644 PettingZoo/UI/Tab/Publisher/TapetiPublisherView.xaml.cs create mode 100644 PettingZoo/UI/Tab/Publisher/TapetiPublisherViewModel.cs create mode 100644 PettingZoo/UI/Tab/Publisher/TapetiPublisherViewStrings.Designer.cs create mode 100644 PettingZoo/UI/Tab/Publisher/TapetiPublisherViewStrings.resx diff --git a/ParseTapetiMessagesPrototype/MetadataReaderMessageParser.cs b/ParseTapetiMessagesPrototype/MetadataReaderMessageParser.cs deleted file mode 100644 index f3081cb..0000000 --- a/ParseTapetiMessagesPrototype/MetadataReaderMessageParser.cs +++ /dev/null @@ -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 - { - 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 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 signature) => "methodptr(something)"; - } - } -} diff --git a/ParseTapetiMessagesPrototype/ParseTapetiMessagesPrototype.csproj b/ParseTapetiMessagesPrototype/ParseTapetiMessagesPrototype.csproj deleted file mode 100644 index b84e63f..0000000 --- a/ParseTapetiMessagesPrototype/ParseTapetiMessagesPrototype.csproj +++ /dev/null @@ -1,12 +0,0 @@ - - - - Exe - net5.0 - - - - - - - diff --git a/ParseTapetiMessagesPrototype/Program.cs b/ParseTapetiMessagesPrototype/Program.cs deleted file mode 100644 index 9b753ce..0000000 --- a/ParseTapetiMessagesPrototype/Program.cs +++ /dev/null @@ -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); - } - } -} diff --git a/PettingZoo.Core/Generator/IExampleGenerator.cs b/PettingZoo.Core/Generator/IExampleGenerator.cs new file mode 100644 index 0000000..ae49c7a --- /dev/null +++ b/PettingZoo.Core/Generator/IExampleGenerator.cs @@ -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 Folders { get; } + public IReadOnlyList Messages { get; } + } + + + public interface IExampleMessage + { + string Generate(); + } +} diff --git a/PettingZoo.Core/PettingZoo.Core.csproj b/PettingZoo.Core/PettingZoo.Core.csproj index b380728..483d761 100644 --- a/PettingZoo.Core/PettingZoo.Core.csproj +++ b/PettingZoo.Core/PettingZoo.Core.csproj @@ -1,7 +1,7 @@ - net5.0 + net6.0 enable diff --git a/PettingZoo.RabbitMQ/PettingZoo.RabbitMQ.csproj b/PettingZoo.RabbitMQ/PettingZoo.RabbitMQ.csproj index 38e4451..79d0e3f 100644 --- a/PettingZoo.RabbitMQ/PettingZoo.RabbitMQ.csproj +++ b/PettingZoo.RabbitMQ/PettingZoo.RabbitMQ.csproj @@ -1,7 +1,7 @@ - net5.0 + net6.0 enable diff --git a/PettingZoo.Tapeti/PettingZoo.Tapeti.csproj b/PettingZoo.Tapeti/PettingZoo.Tapeti.csproj new file mode 100644 index 0000000..77a196f --- /dev/null +++ b/PettingZoo.Tapeti/PettingZoo.Tapeti.csproj @@ -0,0 +1,15 @@ + + + + net6.0 + + + + + + + + + + + diff --git a/PettingZoo.Tapeti/TapetiClassLibraryExampleSource.cs b/PettingZoo.Tapeti/TapetiClassLibraryExampleSource.cs new file mode 100644 index 0000000..ec91428 --- /dev/null +++ b/PettingZoo.Tapeti/TapetiClassLibraryExampleSource.cs @@ -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 extraAssemblies; + private Lazy assemblySource; + + + public TapetiClassLibraryExampleSource(string classLibraryFilename, IEnumerable extraAssemblies) + { + this.classLibraryFilename = classLibraryFilename; + this.extraAssemblies = extraAssemblies; + + assemblySource = new Lazy(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 folders = new(); + private readonly List messages = new(); + + + public string Name { get; } + public IReadOnlyList Folders => folders; + public IReadOnlyList 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(); + } + } + } +} diff --git a/ParseTapetiMessagesPrototype/AssemblyLoaderMessageParser.cs b/PettingZoo.Tapeti/TypeToJObjectConverter.cs similarity index 50% rename from ParseTapetiMessagesPrototype/AssemblyLoaderMessageParser.cs rename to PettingZoo.Tapeti/TypeToJObjectConverter.cs index 1bfbc66..d807501 100644 --- a/ParseTapetiMessagesPrototype/AssemblyLoaderMessageParser.cs +++ b/PettingZoo.Tapeti/TypeToJObjectConverter.cs @@ -2,66 +2,21 @@ 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(); - + foreach (var propertyInfo in type.GetProperties(BindingFlags.Public | BindingFlags.Instance)) { // Note: unfortunately we can not call GetCustomAttributes here, as that would // trigger assemblies not included in the package to be loaded - + var value = PropertyToJToken(propertyInfo.PropertyType); result.Add(propertyInfo.Name, value); } @@ -82,38 +37,38 @@ namespace ParseTapetiMessagesPrototype { typeof(float), 0.0 }, { typeof(bool), false } }; - - + + private static JToken PropertyToJToken(Type propertyType) { var actualType = Nullable.GetUnderlyingType(propertyType) ?? propertyType; - + // String is also a class if (actualType == typeof(string)) return ""; - - + + if (actualType.IsClass) { // IEnumerable var enumerableInterface = actualType.GetInterfaces() .FirstOrDefault(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IEnumerable<>)); - + if (enumerableInterface != null) - return new JArray(TypeToJObject(enumerableInterface.GetGenericArguments()[0])); - - - return TypeToJObject(actualType); + return new JArray(Convert(enumerableInterface.GetGenericArguments()[0])); + + + 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(); - + // Special cases for runtime generated values if (actualType == typeof(DateTime)) { @@ -129,5 +84,7 @@ namespace ParseTapetiMessagesPrototype ? mappedToken : $"(unknown type: {actualType.Name})"; } + + } } diff --git a/PettingZoo.sln b/PettingZoo.sln index f4d15a5..a8028f7 100644 --- a/PettingZoo.sln +++ b/PettingZoo.sln @@ -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 diff --git a/PettingZoo/PettingZoo.csproj b/PettingZoo/PettingZoo.csproj index cd97af0..fa44a96 100644 --- a/PettingZoo/PettingZoo.csproj +++ b/PettingZoo/PettingZoo.csproj @@ -2,7 +2,7 @@ WinExe - net5.0-windows + net6.0-windows true Mark van Renswoude Petting Zoo @@ -46,6 +46,11 @@ True True + + True + True + ExamplePickerDialogStrings.resx + MainWindowStrings.resx True @@ -56,6 +61,14 @@ True True + + TapetiPublisherViewStrings.resx + True + True + + + Code + RawPublisherViewStrings.resx True @@ -78,6 +91,10 @@ ConnectionWindowStrings.Designer.cs PublicResXFileCodeGenerator + + PublicResXFileCodeGenerator + ExamplePickerDialogStrings.Designer.cs + MainWindowStrings.Designer.cs PublicResXFileCodeGenerator @@ -86,6 +103,10 @@ SubscribeWindowStrings.Designer.cs PublicResXFileCodeGenerator + + TapetiPublisherViewStrings.Designer.cs + PublicResXFileCodeGenerator + RawPublisherViewStrings.Designer.cs PublicResXFileCodeGenerator @@ -113,6 +134,10 @@ $(DefaultXamlRuntime) + + $(DefaultXamlRuntime) + Designer + $(DefaultXamlRuntime) diff --git a/PettingZoo/Style.xaml b/PettingZoo/Style.xaml index 5f5e226..da8e0fe 100644 --- a/PettingZoo/Style.xaml +++ b/PettingZoo/Style.xaml @@ -67,8 +67,9 @@ - diff --git a/PettingZoo/UI/Example/ExamplePickerDialog.xaml b/PettingZoo/UI/Example/ExamplePickerDialog.xaml new file mode 100644 index 0000000..3b3684a --- /dev/null +++ b/PettingZoo/UI/Example/ExamplePickerDialog.xaml @@ -0,0 +1,12 @@ + + + + + diff --git a/PettingZoo/UI/Example/ExamplePickerDialog.xaml.cs b/PettingZoo/UI/Example/ExamplePickerDialog.xaml.cs new file mode 100644 index 0000000..0ec7066 --- /dev/null +++ b/PettingZoo/UI/Example/ExamplePickerDialog.xaml.cs @@ -0,0 +1,15 @@ +using System.Windows; + +namespace PettingZoo.UI.Example +{ + /// + /// Interaction logic for ExamplePickerDialog.xaml + /// + public partial class ExamplePickerDialog : Window + { + public ExamplePickerDialog() + { + InitializeComponent(); + } + } +} diff --git a/PettingZoo/UI/Example/ExamplePickerDialogStrings.Designer.cs b/PettingZoo/UI/Example/ExamplePickerDialogStrings.Designer.cs new file mode 100644 index 0000000..5f39c62 --- /dev/null +++ b/PettingZoo/UI/Example/ExamplePickerDialogStrings.Designer.cs @@ -0,0 +1,72 @@ +//------------------------------------------------------------------------------ +// +// 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. +// +//------------------------------------------------------------------------------ + +namespace PettingZoo.UI.Example { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // 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() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [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; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + public static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized string similar to Select example. + /// + public static string WindowTitle { + get { + return ResourceManager.GetString("WindowTitle", resourceCulture); + } + } + } +} diff --git a/PettingZoo/UI/Example/ExamplePickerDialogStrings.resx b/PettingZoo/UI/Example/ExamplePickerDialogStrings.resx new file mode 100644 index 0000000..a0b7311 --- /dev/null +++ b/PettingZoo/UI/Example/ExamplePickerDialogStrings.resx @@ -0,0 +1,123 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Select example + + \ No newline at end of file diff --git a/PettingZoo/UI/Example/ExamplePickerDialogViewModel.cs b/PettingZoo/UI/Example/ExamplePickerDialogViewModel.cs new file mode 100644 index 0000000..35dd85f --- /dev/null +++ b/PettingZoo/UI/Example/ExamplePickerDialogViewModel.cs @@ -0,0 +1,6 @@ +namespace PettingZoo.UI.Example +{ + public class ExamplePickerDialogViewModel + { + } +} diff --git a/PettingZoo/UI/Main/MainWindow.xaml.cs b/PettingZoo/UI/Main/MainWindow.xaml.cs index 2f033ff..c41d85e 100644 --- a/PettingZoo/UI/Main/MainWindow.xaml.cs +++ b/PettingZoo/UI/Main/MainWindow.xaml.cs @@ -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); } diff --git a/PettingZoo/UI/Tab/Publisher/PublisherView.xaml b/PettingZoo/UI/Tab/Publisher/PublisherView.xaml index accf7fb..d26cc84 100644 --- a/PettingZoo/UI/Tab/Publisher/PublisherView.xaml +++ b/PettingZoo/UI/Tab/Publisher/PublisherView.xaml @@ -15,10 +15,9 @@ - -