Implemented JSON syntax checking
Implemented (re)storing of main window position
This commit is contained in:
parent
4b730b2a1a
commit
28d3548088
30
PettingZoo.Core/Settings/IUISettingsRepository.cs
Normal file
30
PettingZoo.Core/Settings/IUISettingsRepository.cs
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace PettingZoo.Core.Settings
|
||||||
|
{
|
||||||
|
public interface IUISettingsRepository
|
||||||
|
{
|
||||||
|
Task<MainWindowPositionSettings?> GetMainWindowPosition();
|
||||||
|
Task StoreMainWindowPosition(MainWindowPositionSettings settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public class MainWindowPositionSettings
|
||||||
|
{
|
||||||
|
public int Top { get; }
|
||||||
|
public int Left { get; }
|
||||||
|
public int Width { get; }
|
||||||
|
public int Height { get; }
|
||||||
|
public bool Maximized { get; }
|
||||||
|
|
||||||
|
|
||||||
|
public MainWindowPositionSettings(int top, int left, int width, int height, bool maximized)
|
||||||
|
{
|
||||||
|
Top = top;
|
||||||
|
Left = left;
|
||||||
|
Width = width;
|
||||||
|
Height = height;
|
||||||
|
Maximized = maximized;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -7,6 +7,11 @@ namespace PettingZoo.Settings.LiteDB
|
|||||||
{
|
{
|
||||||
private readonly string databaseFilename;
|
private readonly string databaseFilename;
|
||||||
|
|
||||||
|
protected static readonly BsonMapper Mapper = new()
|
||||||
|
{
|
||||||
|
EmptyStringToNull = false
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
public BaseLiteDBRepository(string databaseName)
|
public BaseLiteDBRepository(string databaseName)
|
||||||
{
|
{
|
||||||
@ -24,10 +29,7 @@ namespace PettingZoo.Settings.LiteDB
|
|||||||
|
|
||||||
protected ILiteDatabaseAsync GetDatabase()
|
protected ILiteDatabaseAsync GetDatabase()
|
||||||
{
|
{
|
||||||
return new LiteDatabaseAsync(databaseFilename, new BsonMapper
|
return new LiteDatabaseAsync(databaseFilename, Mapper);
|
||||||
{
|
|
||||||
EmptyStringToNull = false
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
84
PettingZoo.Settings.LiteDB/LiteDBUISettingsRepository.cs
Normal file
84
PettingZoo.Settings.LiteDB/LiteDBUISettingsRepository.cs
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
using PettingZoo.Core.Settings;
|
||||||
|
|
||||||
|
namespace PettingZoo.Settings.LiteDB
|
||||||
|
{
|
||||||
|
public class LiteDBUISettingsRepository : BaseLiteDBRepository, IUISettingsRepository
|
||||||
|
{
|
||||||
|
private const string CollectionSettings = "settings";
|
||||||
|
|
||||||
|
|
||||||
|
public LiteDBUISettingsRepository() : base(@"uiSettings")
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public async Task<MainWindowPositionSettings?> GetMainWindowPosition()
|
||||||
|
{
|
||||||
|
using var database = GetDatabase();
|
||||||
|
var collection = database.GetCollection(CollectionSettings);
|
||||||
|
|
||||||
|
var settings = await collection.FindByIdAsync(MainWindowPositionSettingsRecord.SettingsKey);
|
||||||
|
if (settings == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
var position = Mapper.ToObject<MainWindowPositionSettingsRecord>(settings);
|
||||||
|
return new MainWindowPositionSettings(
|
||||||
|
position.Top,
|
||||||
|
position.Left,
|
||||||
|
position.Width,
|
||||||
|
position.Height,
|
||||||
|
position.Maximized);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public async Task StoreMainWindowPosition(MainWindowPositionSettings settings)
|
||||||
|
{
|
||||||
|
using var database = GetDatabase();
|
||||||
|
var collection = database.GetCollection(CollectionSettings);
|
||||||
|
|
||||||
|
await collection.UpsertAsync(
|
||||||
|
Mapper.ToDocument(new MainWindowPositionSettingsRecord
|
||||||
|
{
|
||||||
|
Top = settings.Top,
|
||||||
|
Left = settings.Left,
|
||||||
|
Width = settings.Width,
|
||||||
|
Height = settings.Height,
|
||||||
|
Maximized = settings.Maximized
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// ReSharper disable MemberCanBePrivate.Local - for LiteDB
|
||||||
|
// ReSharper disable PropertyCanBeMadeInitOnly.Local
|
||||||
|
private class BaseSettingsRecord
|
||||||
|
{
|
||||||
|
// ReSharper disable once UnusedAutoPropertyAccessor.Local
|
||||||
|
public Guid Id { get; }
|
||||||
|
|
||||||
|
protected BaseSettingsRecord(Guid id)
|
||||||
|
{
|
||||||
|
Id = id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private class MainWindowPositionSettingsRecord : BaseSettingsRecord
|
||||||
|
{
|
||||||
|
public static readonly Guid SettingsKey = new("fc71cf99-0744-4f5d-ada8-6a78d1df7b62");
|
||||||
|
|
||||||
|
|
||||||
|
public int Top { get; set; }
|
||||||
|
public int Left { get; set; }
|
||||||
|
public int Width { get; set; }
|
||||||
|
public int Height { get; set; }
|
||||||
|
public bool Maximized { get; set; }
|
||||||
|
|
||||||
|
public MainWindowPositionSettingsRecord() : base(SettingsKey)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ReSharper restore PropertyCanBeMadeInitOnly.Local
|
||||||
|
// ReSharper restore MemberCanBePrivate.Local
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,7 @@
|
|||||||
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
||||||
<s:Boolean x:Key="/Default/CodeInspection/CodeAnnotations/NamespacesWithAnnotations/=PettingZoo_002EAnnotations/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/CodeInspection/CodeAnnotations/NamespacesWithAnnotations/=PettingZoo_002EAnnotations/@EntryIndexedValue">True</s:Boolean>
|
||||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=DB/@EntryIndexedValue">DB</s:String>
|
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=DB/@EntryIndexedValue">DB</s:String>
|
||||||
|
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=DBUI/@EntryIndexedValue">DBUI</s:String>
|
||||||
|
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=UI/@EntryIndexedValue">UI</s:String>
|
||||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=MQ/@EntryIndexedValue">MQ</s:String>
|
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=MQ/@EntryIndexedValue">MQ</s:String>
|
||||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=WPF/@EntryIndexedValue">WPF</s:String></wpf:ResourceDictionary>
|
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=WPF/@EntryIndexedValue">WPF</s:String></wpf:ResourceDictionary>
|
@ -1,10 +1,83 @@
|
|||||||
using System.Windows;
|
using System;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Windows;
|
||||||
using System.Windows.Threading;
|
using System.Windows.Threading;
|
||||||
|
using PettingZoo.Core.Settings;
|
||||||
|
using PettingZoo.UI.Main;
|
||||||
|
using SimpleInjector;
|
||||||
|
using Point = System.Windows.Point;
|
||||||
|
|
||||||
namespace PettingZoo
|
namespace PettingZoo
|
||||||
{
|
{
|
||||||
public partial class App
|
public partial class App
|
||||||
{
|
{
|
||||||
|
private readonly Container container;
|
||||||
|
|
||||||
|
|
||||||
|
public App()
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("Default main should not be used");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public App(Container container)
|
||||||
|
{
|
||||||
|
this.container = container;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
protected override async void OnStartup(StartupEventArgs e)
|
||||||
|
{
|
||||||
|
var uitSettingsRepository = container.GetInstance<IUISettingsRepository>();
|
||||||
|
var position = await uitSettingsRepository.GetMainWindowPosition();
|
||||||
|
|
||||||
|
var mainWindow = container.GetInstance<MainWindow>();
|
||||||
|
|
||||||
|
if (position != null)
|
||||||
|
{
|
||||||
|
var positionBounds = new Rect(
|
||||||
|
new Point(position.Left, position.Top),
|
||||||
|
new Point(position.Left + position.Width, position.Top + position.Height));
|
||||||
|
|
||||||
|
if (InScreenBounds(positionBounds))
|
||||||
|
{
|
||||||
|
mainWindow.WindowStartupLocation = WindowStartupLocation.Manual;
|
||||||
|
mainWindow.Top = positionBounds.Top;
|
||||||
|
mainWindow.Left = positionBounds.Left;
|
||||||
|
mainWindow.Width = positionBounds.Width;
|
||||||
|
mainWindow.Height = positionBounds.Height;
|
||||||
|
}
|
||||||
|
|
||||||
|
mainWindow.WindowState = position.Maximized ? WindowState.Maximized : WindowState.Normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
mainWindow.Closing += (_, _) =>
|
||||||
|
{
|
||||||
|
var newPosition = new MainWindowPositionSettings(
|
||||||
|
(int)mainWindow.RestoreBounds.Top,
|
||||||
|
(int)mainWindow.RestoreBounds.Left,
|
||||||
|
(int)mainWindow.RestoreBounds.Width,
|
||||||
|
(int)mainWindow.RestoreBounds.Height,
|
||||||
|
mainWindow.WasMaximized);
|
||||||
|
|
||||||
|
Task.Run(() => uitSettingsRepository.StoreMainWindowPosition(newPosition));
|
||||||
|
};
|
||||||
|
|
||||||
|
mainWindow.Show();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static bool InScreenBounds(Rect bounds)
|
||||||
|
{
|
||||||
|
var boundsRectangle = new Rectangle((int)bounds.Left, (int)bounds.Top, (int)bounds.Width, (int)bounds.Height);
|
||||||
|
|
||||||
|
// There doesn't appear to be any way to get this information other than from System.Windows.From/PInvoke at the time of writing
|
||||||
|
return System.Windows.Forms.Screen.AllScreens.Any(screen => screen.Bounds.IntersectsWith(boundsRectangle));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private void App_OnDispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
|
private void App_OnDispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
|
||||||
{
|
{
|
||||||
_ = MessageBox.Show($"Unhandled exception: {e.Exception.Message}", "Petting Zoo - Exception", MessageBoxButton.OK, MessageBoxImage.Error);
|
_ = MessageBox.Show($"Unhandled exception: {e.Exception.Message}", "Petting Zoo - Exception", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||||
|
69
PettingZoo/Images/Error.svg
Normal file
69
PettingZoo/Images/Error.svg
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 18.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
version="1.1"
|
||||||
|
id="Capa_1"
|
||||||
|
x="0px"
|
||||||
|
y="0px"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
xml:space="preserve"
|
||||||
|
sodipodi:docname="Error.svg"
|
||||||
|
width="24"
|
||||||
|
height="24"
|
||||||
|
inkscape:version="1.1.1 (3bf5ae0d25, 2021-09-20)"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"><defs
|
||||||
|
id="defs130">
|
||||||
|
|
||||||
|
|
||||||
|
</defs><sodipodi:namedview
|
||||||
|
id="namedview128"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:pagecheckerboard="0"
|
||||||
|
showgrid="false"
|
||||||
|
inkscape:zoom="14.344828"
|
||||||
|
inkscape:cx="-14.395433"
|
||||||
|
inkscape:cy="-2.9627404"
|
||||||
|
inkscape:window-width="1920"
|
||||||
|
inkscape:window-height="1017"
|
||||||
|
inkscape:window-x="1912"
|
||||||
|
inkscape:window-y="-8"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
inkscape:current-layer="Capa_1" />
|
||||||
|
<g
|
||||||
|
id="g95"
|
||||||
|
transform="translate(-34,-32)">
|
||||||
|
|
||||||
|
<circle
|
||||||
|
style="fill:#ed7161"
|
||||||
|
cx="46"
|
||||||
|
cy="44"
|
||||||
|
r="12"
|
||||||
|
id="circle89" /><path
|
||||||
|
style="fill:#ffffff"
|
||||||
|
d="m 47.414,44 3.536,-3.536 c 0.391,-0.391 0.391,-1.023 0,-1.414 -0.391,-0.391 -1.023,-0.391 -1.414,0 l -3.536,3.536 -3.536,-3.536 c -0.391,-0.391 -1.023,-0.391 -1.414,0 -0.391,0.391 -0.391,1.023 0,1.414 l 3.536,3.536 -3.536,3.536 c -0.391,0.391 -0.391,1.023 0,1.414 0.195,0.195 0.451,0.293 0.707,0.293 0.256,0 0.512,-0.098 0.707,-0.293 l 3.536,-3.536 3.536,3.536 c 0.195,0.195 0.451,0.293 0.707,0.293 0.256,0 0.512,-0.098 0.707,-0.293 0.391,-0.391 0.391,-1.023 0,-1.414 z"
|
||||||
|
id="path91" />
|
||||||
|
</g>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.8 KiB |
54
PettingZoo/Images/Ok.svg
Normal file
54
PettingZoo/Images/Ok.svg
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 18.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
version="1.1"
|
||||||
|
id="Capa_1"
|
||||||
|
x="0px"
|
||||||
|
y="0px"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
xml:space="preserve"
|
||||||
|
sodipodi:docname="Ok.svg"
|
||||||
|
width="24"
|
||||||
|
height="24"
|
||||||
|
inkscape:version="1.1.1 (3bf5ae0d25, 2021-09-20)"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"><defs
|
||||||
|
id="defs13" /><sodipodi:namedview
|
||||||
|
id="namedview11"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:pagecheckerboard="0"
|
||||||
|
showgrid="false"
|
||||||
|
inkscape:zoom="7.1724138"
|
||||||
|
inkscape:cx="-11.362981"
|
||||||
|
inkscape:cy="7.1802885"
|
||||||
|
inkscape:window-width="1920"
|
||||||
|
inkscape:window-height="1017"
|
||||||
|
inkscape:window-x="1912"
|
||||||
|
inkscape:window-y="-8"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
inkscape:current-layer="Capa_1" />
|
||||||
|
<g
|
||||||
|
id="g8"
|
||||||
|
transform="translate(-34,-32)">
|
||||||
|
<g
|
||||||
|
id="g6">
|
||||||
|
<circle
|
||||||
|
style="fill:#26b999"
|
||||||
|
cx="46"
|
||||||
|
cy="44"
|
||||||
|
r="12"
|
||||||
|
id="circle2" />
|
||||||
|
<path
|
||||||
|
style="fill:#ffffff"
|
||||||
|
d="m 52.571,38.179 c -0.455,-0.316 -1.077,-0.204 -1.392,0.25 l -5.596,8.04 -3.949,-3.242 c -0.426,-0.351 -1.057,-0.288 -1.407,0.139 -0.351,0.427 -0.289,1.057 0.139,1.407 l 4.786,3.929 c 0.18,0.147 0.404,0.227 0.634,0.227 0.045,0 0.091,-0.003 0.137,-0.009 0.276,-0.039 0.524,-0.19 0.684,-0.419 l 6.214,-8.929 c 0.315,-0.454 0.203,-1.077 -0.25,-1.393 z"
|
||||||
|
id="path4" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.6 KiB |
@ -5,6 +5,7 @@
|
|||||||
<TargetFramework>net6.0-windows</TargetFramework>
|
<TargetFramework>net6.0-windows</TargetFramework>
|
||||||
<Version>0.1</Version>
|
<Version>0.1</Version>
|
||||||
<UseWPF>true</UseWPF>
|
<UseWPF>true</UseWPF>
|
||||||
|
<UseWindowsForms>true</UseWindowsForms>
|
||||||
<Authors>Mark van Renswoude</Authors>
|
<Authors>Mark van Renswoude</Authors>
|
||||||
<Product>Petting Zoo</Product>
|
<Product>Petting Zoo</Product>
|
||||||
<Description>Petting Zoo - a live RabbitMQ message viewer</Description>
|
<Description>Petting Zoo - a live RabbitMQ message viewer</Description>
|
||||||
@ -19,6 +20,8 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Remove="Images\Dock.svg" />
|
<None Remove="Images\Dock.svg" />
|
||||||
|
<None Remove="Images\Error.svg" />
|
||||||
|
<None Remove="Images\Ok.svg" />
|
||||||
<None Remove="Images\PublishSend.svg" />
|
<None Remove="Images\PublishSend.svg" />
|
||||||
<None Remove="Images\Undock.svg" />
|
<None Remove="Images\Undock.svg" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
@ -28,6 +31,8 @@
|
|||||||
<Resource Include="Images\Connect.svg" />
|
<Resource Include="Images\Connect.svg" />
|
||||||
<Resource Include="Images\Disconnect.svg" />
|
<Resource Include="Images\Disconnect.svg" />
|
||||||
<Resource Include="Images\Dock.svg" />
|
<Resource Include="Images\Dock.svg" />
|
||||||
|
<Resource Include="Images\Error.svg" />
|
||||||
|
<Resource Include="Images\Ok.svg" />
|
||||||
<Resource Include="Images\Publish.svg" />
|
<Resource Include="Images\Publish.svg" />
|
||||||
<Resource Include="Images\PublishSend.svg" />
|
<Resource Include="Images\PublishSend.svg" />
|
||||||
<Resource Include="Images\Subscribe.svg" />
|
<Resource Include="Images\Subscribe.svg" />
|
||||||
@ -35,8 +40,9 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
||||||
<PackageReference Include="SharpVectors" Version="1.7.6" />
|
<PackageReference Include="SharpVectors" Version="1.7.7" />
|
||||||
<PackageReference Include="SimpleInjector" Version="5.3.2" />
|
<PackageReference Include="SimpleInjector" Version="5.3.2" />
|
||||||
|
<PackageReference Include="System.Reactive" Version="5.0.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
@ -75,6 +81,11 @@
|
|||||||
<DesignTime>True</DesignTime>
|
<DesignTime>True</DesignTime>
|
||||||
<AutoGen>True</AutoGen>
|
<AutoGen>True</AutoGen>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
<Compile Update="UI\Tab\Publisher\PayloadEditorStrings.Designer.cs">
|
||||||
|
<DesignTime>True</DesignTime>
|
||||||
|
<AutoGen>True</AutoGen>
|
||||||
|
<DependentUpon>PayloadEditorStrings.resx</DependentUpon>
|
||||||
|
</Compile>
|
||||||
<Compile Update="UI\Tab\Publisher\TapetiPublisherViewStrings.Designer.cs">
|
<Compile Update="UI\Tab\Publisher\TapetiPublisherViewStrings.Designer.cs">
|
||||||
<DependentUpon>TapetiPublisherViewStrings.resx</DependentUpon>
|
<DependentUpon>TapetiPublisherViewStrings.resx</DependentUpon>
|
||||||
<DesignTime>True</DesignTime>
|
<DesignTime>True</DesignTime>
|
||||||
@ -126,6 +137,10 @@
|
|||||||
<LastGenOutput>SubscribeWindowStrings.Designer.cs</LastGenOutput>
|
<LastGenOutput>SubscribeWindowStrings.Designer.cs</LastGenOutput>
|
||||||
<Generator>PublicResXFileCodeGenerator</Generator>
|
<Generator>PublicResXFileCodeGenerator</Generator>
|
||||||
</EmbeddedResource>
|
</EmbeddedResource>
|
||||||
|
<EmbeddedResource Update="UI\Tab\Publisher\PayloadEditorStrings.resx">
|
||||||
|
<Generator>ResXFileCodeGenerator</Generator>
|
||||||
|
<LastGenOutput>PayloadEditorStrings.Designer.cs</LastGenOutput>
|
||||||
|
</EmbeddedResource>
|
||||||
<EmbeddedResource Update="UI\Tab\Publisher\TapetiPublisherViewStrings.resx">
|
<EmbeddedResource Update="UI\Tab\Publisher\TapetiPublisherViewStrings.resx">
|
||||||
<LastGenOutput>TapetiPublisherViewStrings.Designer.cs</LastGenOutput>
|
<LastGenOutput>TapetiPublisherViewStrings.Designer.cs</LastGenOutput>
|
||||||
<Generator>PublicResXFileCodeGenerator</Generator>
|
<Generator>PublicResXFileCodeGenerator</Generator>
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Markup;
|
using System.Windows.Markup;
|
||||||
using PettingZoo.Core.Connection;
|
using PettingZoo.Core.Connection;
|
||||||
@ -38,6 +39,7 @@ namespace PettingZoo
|
|||||||
container.Register<IConnectionDialog, WindowConnectionDialog>();
|
container.Register<IConnectionDialog, WindowConnectionDialog>();
|
||||||
container.Register<ISubscribeDialog, WindowSubscribeDialog>();
|
container.Register<ISubscribeDialog, WindowSubscribeDialog>();
|
||||||
container.Register<IConnectionSettingsRepository, LiteDBConnectionSettingsRepository>();
|
container.Register<IConnectionSettingsRepository, LiteDBConnectionSettingsRepository>();
|
||||||
|
container.Register<IUISettingsRepository, LiteDBUISettingsRepository>();
|
||||||
|
|
||||||
container.Register<MainWindow>();
|
container.Register<MainWindow>();
|
||||||
|
|
||||||
@ -49,7 +51,7 @@ namespace PettingZoo
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var app = new App();
|
var app = new App(container);
|
||||||
app.InitializeComponent();
|
app.InitializeComponent();
|
||||||
|
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
@ -65,8 +67,7 @@ namespace PettingZoo
|
|||||||
// All this is the reason we only perform verification in debug builds
|
// All this is the reason we only perform verification in debug builds
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
var mainWindow = container.GetInstance<MainWindow>();
|
app.Run();
|
||||||
_ = app.Run(mainWindow);
|
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
Must-have
|
Must-have
|
||||||
---------
|
---------
|
||||||
- Option to not save password in profiles
|
|
||||||
|
|
||||||
|
|
||||||
Should-have
|
Should-have
|
||||||
@ -11,5 +10,4 @@ Should-have
|
|||||||
|
|
||||||
Nice-to-have
|
Nice-to-have
|
||||||
------------
|
------------
|
||||||
- JSON validation
|
|
||||||
- JSON syntax highlighting
|
- JSON syntax highlighting
|
29
PettingZoo/UI/DependencyObjectExtensions.cs
Normal file
29
PettingZoo/UI/DependencyObjectExtensions.cs
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
using System;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Reactive.Disposables;
|
||||||
|
using System.Reactive.Linq;
|
||||||
|
using System.Windows;
|
||||||
|
|
||||||
|
namespace PettingZoo.UI
|
||||||
|
{
|
||||||
|
public static class DependencyObjectExtensions
|
||||||
|
{
|
||||||
|
public static IObservable<T> OnPropertyChanges<T>(this DependencyObject source, DependencyProperty property)
|
||||||
|
{
|
||||||
|
return Observable.Create<T>(o =>
|
||||||
|
{
|
||||||
|
var dpd = DependencyPropertyDescriptor.FromProperty(property, property.OwnerType);
|
||||||
|
if (dpd == null)
|
||||||
|
o.OnError(new InvalidOperationException("Can not register change handler for this dependency property."));
|
||||||
|
|
||||||
|
void Handler(object? sender, EventArgs e)
|
||||||
|
{
|
||||||
|
o.OnNext((T)source.GetValue(property));
|
||||||
|
}
|
||||||
|
|
||||||
|
dpd?.AddValueChanged(source, Handler);
|
||||||
|
return Disposable.Create(() => dpd?.RemoveValueChanged(source, Handler));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
19
PettingZoo/UI/EnumBooleanConverter.cs
Normal file
19
PettingZoo/UI/EnumBooleanConverter.cs
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
using System;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Windows.Data;
|
||||||
|
|
||||||
|
namespace PettingZoo.UI
|
||||||
|
{
|
||||||
|
public class EnumBooleanConverter : IValueConverter
|
||||||
|
{
|
||||||
|
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||||
|
{
|
||||||
|
return value.Equals(parameter);
|
||||||
|
}
|
||||||
|
|
||||||
|
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||||
|
{
|
||||||
|
return ((bool)value) ? parameter : Binding.DoNothing;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -18,6 +18,8 @@ namespace PettingZoo.UI.Main
|
|||||||
{
|
{
|
||||||
private readonly MainWindowViewModel viewModel;
|
private readonly MainWindowViewModel viewModel;
|
||||||
|
|
||||||
|
public bool WasMaximized;
|
||||||
|
|
||||||
|
|
||||||
public MainWindow(IConnectionFactory connectionFactory, IConnectionDialog connectionDialog, ISubscribeDialog subscribeDialog)
|
public MainWindow(IConnectionFactory connectionFactory, IConnectionDialog connectionDialog, ISubscribeDialog subscribeDialog)
|
||||||
{
|
{
|
||||||
@ -28,6 +30,20 @@ namespace PettingZoo.UI.Main
|
|||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
Dispatcher.ShutdownStarted += OnDispatcherShutDownStarted;
|
Dispatcher.ShutdownStarted += OnDispatcherShutDownStarted;
|
||||||
|
|
||||||
|
|
||||||
|
// If the WindowState is Minimized, we can't tell if it was maximized before. To properly store
|
||||||
|
// the last window position, keep track of it.
|
||||||
|
this.OnPropertyChanges<WindowState>(WindowStateProperty)
|
||||||
|
.Subscribe(newState =>
|
||||||
|
{
|
||||||
|
WasMaximized = newState switch
|
||||||
|
{
|
||||||
|
WindowState.Maximized => true,
|
||||||
|
WindowState.Normal => false,
|
||||||
|
_ => WasMaximized
|
||||||
|
};
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
31
PettingZoo/UI/Tab/Publisher/PayloadEditorControl.xaml
Normal file
31
PettingZoo/UI/Tab/Publisher/PayloadEditorControl.xaml
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
<UserControl x:Class="PettingZoo.UI.Tab.Publisher.PayloadEditorControl"
|
||||||
|
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"
|
||||||
|
xmlns:svgc="http://sharpvectors.codeplex.com/svgc/"
|
||||||
|
mc:Ignorable="d"
|
||||||
|
d:DesignHeight="450" d:DesignWidth="800"
|
||||||
|
Background="White">
|
||||||
|
<UserControl.Resources>
|
||||||
|
<ui:EnumBooleanConverter x:Key="EnumBooleanConverter" />
|
||||||
|
</UserControl.Resources>
|
||||||
|
<DockPanel x:Name="DataContextContainer" d:DataContext="{d:DesignInstance publisher:DesignTimePayloadEditorViewModel, IsDesignTimeCreatable=True}">
|
||||||
|
<StackPanel Orientation="Horizontal" DockPanel.Dock="Top" Visibility="{Binding ContentTypeVisibility}" Margin="0,0,0,8">
|
||||||
|
<RadioButton Content="JSON" Style="{StaticResource TypeSelection}" IsChecked="{Binding ContentTypeSelection, Converter={StaticResource EnumBooleanConverter}, ConverterParameter={x:Static publisher:PayloadEditorContentType.Json}}" />
|
||||||
|
<RadioButton Content="Plain text" Style="{StaticResource TypeSelection}" IsChecked="{Binding ContentTypeSelection, Converter={StaticResource EnumBooleanConverter}, ConverterParameter={x:Static publisher:PayloadEditorContentType.Plain}}" />
|
||||||
|
<RadioButton Content="Other" Style="{StaticResource TypeSelection}" IsChecked="{Binding ContentTypeSelection, Converter={StaticResource EnumBooleanConverter}, ConverterParameter={x:Static publisher:PayloadEditorContentType.Other}}" />
|
||||||
|
<TextBox Width="200" Text="{Binding ContentType, UpdateSourceTrigger=PropertyChanged}" />
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<StackPanel Orientation="Horizontal" DockPanel.Dock="Bottom" Visibility="{Binding JsonValidationVisibility}" Margin="0,8,0,0">
|
||||||
|
<Image Source="{svgc:SvgImage Source=/Images/Ok.svg, AppName=PettingZoo}" Width="16" Height="16" Margin="4" Visibility="{Binding JsonValidationOk}" />
|
||||||
|
<Image Source="{svgc:SvgImage Source=/Images/Error.svg, AppName=PettingZoo}" Width="16" Height="16" Margin="4" Visibility="{Binding JsonValidationError}" />
|
||||||
|
<TextBlock Text="{Binding JsonValidationMessage}" Margin="4" />
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<TextBox Text="{Binding Payload, UpdateSourceTrigger=PropertyChanged}" Style="{StaticResource Payload}" />
|
||||||
|
</DockPanel>
|
||||||
|
</UserControl>
|
141
PettingZoo/UI/Tab/Publisher/PayloadEditorControl.xaml.cs
Normal file
141
PettingZoo/UI/Tab/Publisher/PayloadEditorControl.xaml.cs
Normal file
@ -0,0 +1,141 @@
|
|||||||
|
using System;
|
||||||
|
using System.Reactive.Linq;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Data;
|
||||||
|
|
||||||
|
namespace PettingZoo.UI.Tab.Publisher
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Interaction logic for PayloadEditorControl.xaml
|
||||||
|
/// </summary>
|
||||||
|
public partial class PayloadEditorControl
|
||||||
|
{
|
||||||
|
private readonly PayloadEditorViewModel viewModel = new();
|
||||||
|
|
||||||
|
|
||||||
|
public static readonly DependencyProperty ContentTypeProperty
|
||||||
|
= DependencyProperty.Register(
|
||||||
|
"ContentType",
|
||||||
|
typeof(string),
|
||||||
|
typeof(PayloadEditorControl),
|
||||||
|
new FrameworkPropertyMetadata("")
|
||||||
|
{
|
||||||
|
BindsTwoWayByDefault = true,
|
||||||
|
DefaultUpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
public string ContentType
|
||||||
|
{
|
||||||
|
get => viewModel.ContentType;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (value == viewModel.ContentType)
|
||||||
|
return;
|
||||||
|
|
||||||
|
SetValue(ContentTypeProperty, value);
|
||||||
|
viewModel.ContentType = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static readonly DependencyProperty FixedJsonProperty
|
||||||
|
= DependencyProperty.Register(
|
||||||
|
"FixedJson",
|
||||||
|
typeof(bool),
|
||||||
|
typeof(PayloadEditorControl),
|
||||||
|
new PropertyMetadata(false)
|
||||||
|
);
|
||||||
|
|
||||||
|
public bool FixedJson
|
||||||
|
{
|
||||||
|
get => viewModel.FixedJson;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (value == viewModel.FixedJson)
|
||||||
|
return;
|
||||||
|
|
||||||
|
SetValue(FixedJsonProperty, value);
|
||||||
|
viewModel.FixedJson = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static readonly DependencyProperty PayloadProperty
|
||||||
|
= DependencyProperty.Register(
|
||||||
|
"Payload",
|
||||||
|
typeof(string),
|
||||||
|
typeof(PayloadEditorControl),
|
||||||
|
new FrameworkPropertyMetadata("")
|
||||||
|
{
|
||||||
|
BindsTwoWayByDefault = true,
|
||||||
|
DefaultUpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
public string Payload
|
||||||
|
{
|
||||||
|
get => viewModel.Payload;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (value == viewModel.Payload)
|
||||||
|
return;
|
||||||
|
|
||||||
|
SetValue(PayloadProperty, value);
|
||||||
|
viewModel.Payload = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public PayloadEditorControl()
|
||||||
|
{
|
||||||
|
// Keep the exposed properties in sync with the ViewModel
|
||||||
|
this.OnPropertyChanges<string>(ContentTypeProperty)
|
||||||
|
.ObserveOn(SynchronizationContext.Current!)
|
||||||
|
.Subscribe(value =>
|
||||||
|
{
|
||||||
|
viewModel.ContentType = value;
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
this.OnPropertyChanges<bool>(FixedJsonProperty)
|
||||||
|
.ObserveOn(SynchronizationContext.Current!)
|
||||||
|
.Subscribe(value =>
|
||||||
|
{
|
||||||
|
viewModel.FixedJson = value;
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
this.OnPropertyChanges<string>(PayloadProperty)
|
||||||
|
.ObserveOn(SynchronizationContext.Current!)
|
||||||
|
.Subscribe(value =>
|
||||||
|
{
|
||||||
|
viewModel.Payload = value;
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
viewModel.PropertyChanged += (_, args) =>
|
||||||
|
{
|
||||||
|
switch (args.PropertyName)
|
||||||
|
{
|
||||||
|
case nameof(viewModel.ContentType):
|
||||||
|
SetValue(ContentTypeProperty, viewModel.ContentType);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case nameof(viewModel.FixedJson):
|
||||||
|
SetValue(FixedJsonProperty, viewModel.FixedJson);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case nameof(viewModel.Payload):
|
||||||
|
SetValue(PayloadProperty, viewModel.Payload);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
InitializeComponent();
|
||||||
|
|
||||||
|
// Setting the DataContext for the UserControl is a major PITA when binding the control's properties,
|
||||||
|
// so I've moved the ViewModel one level down to get the best of both worlds...
|
||||||
|
DataContextContainer.DataContext = viewModel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
108
PettingZoo/UI/Tab/Publisher/PayloadEditorStrings.Designer.cs
generated
Normal file
108
PettingZoo/UI/Tab/Publisher/PayloadEditorStrings.Designer.cs
generated
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// <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()]
|
||||||
|
internal class PayloadEditorStrings {
|
||||||
|
|
||||||
|
private static global::System.Resources.ResourceManager resourceMan;
|
||||||
|
|
||||||
|
private static global::System.Globalization.CultureInfo resourceCulture;
|
||||||
|
|
||||||
|
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
||||||
|
internal PayloadEditorStrings() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the cached ResourceManager instance used by this class.
|
||||||
|
/// </summary>
|
||||||
|
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||||
|
internal static global::System.Resources.ResourceManager ResourceManager {
|
||||||
|
get {
|
||||||
|
if (object.ReferenceEquals(resourceMan, null)) {
|
||||||
|
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("PettingZoo.UI.Tab.Publisher.PayloadEditorStrings", typeof(PayloadEditorStrings).Assembly);
|
||||||
|
resourceMan = temp;
|
||||||
|
}
|
||||||
|
return resourceMan;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Overrides the current thread's CurrentUICulture property for all
|
||||||
|
/// resource lookups using this strongly typed resource class.
|
||||||
|
/// </summary>
|
||||||
|
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||||
|
internal static global::System.Globalization.CultureInfo Culture {
|
||||||
|
get {
|
||||||
|
return resourceCulture;
|
||||||
|
}
|
||||||
|
set {
|
||||||
|
resourceCulture = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to JSON.
|
||||||
|
/// </summary>
|
||||||
|
internal static string ContentTypeJson {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("ContentTypeJson", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Other.
|
||||||
|
/// </summary>
|
||||||
|
internal static string ContentTypeOther {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("ContentTypeOther", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Plain text.
|
||||||
|
/// </summary>
|
||||||
|
internal static string ContentTypePlain {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("ContentTypePlain", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Invalid JSON: {0}.
|
||||||
|
/// </summary>
|
||||||
|
internal static string JsonValidationError {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("JsonValidationError", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Valid JSON.
|
||||||
|
/// </summary>
|
||||||
|
internal static string JsonValidationOk {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("JsonValidationOk", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
135
PettingZoo/UI/Tab/Publisher/PayloadEditorStrings.resx
Normal file
135
PettingZoo/UI/Tab/Publisher/PayloadEditorStrings.resx
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
<?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="ContentTypeJson" xml:space="preserve">
|
||||||
|
<value>JSON</value>
|
||||||
|
</data>
|
||||||
|
<data name="ContentTypeOther" xml:space="preserve">
|
||||||
|
<value>Other</value>
|
||||||
|
</data>
|
||||||
|
<data name="ContentTypePlain" xml:space="preserve">
|
||||||
|
<value>Plain text</value>
|
||||||
|
</data>
|
||||||
|
<data name="JsonValidationError" xml:space="preserve">
|
||||||
|
<value>Invalid JSON: {0}</value>
|
||||||
|
</data>
|
||||||
|
<data name="JsonValidationOk" xml:space="preserve">
|
||||||
|
<value>Valid JSON</value>
|
||||||
|
</data>
|
||||||
|
</root>
|
154
PettingZoo/UI/Tab/Publisher/PayloadEditorViewModel.cs
Normal file
154
PettingZoo/UI/Tab/Publisher/PayloadEditorViewModel.cs
Normal file
@ -0,0 +1,154 @@
|
|||||||
|
using System;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Reactive.Linq;
|
||||||
|
using System.Reactive.Subjects;
|
||||||
|
using System.Windows;
|
||||||
|
using Newtonsoft.Json.Linq;
|
||||||
|
|
||||||
|
namespace PettingZoo.UI.Tab.Publisher
|
||||||
|
{
|
||||||
|
public enum PayloadEditorContentType
|
||||||
|
{
|
||||||
|
Json,
|
||||||
|
Plain,
|
||||||
|
Other
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
public class PayloadEditorViewModel : BaseViewModel
|
||||||
|
{
|
||||||
|
private const string ContentTypeJson = "application/json";
|
||||||
|
private const string ContentTypePlain = "text/plain";
|
||||||
|
|
||||||
|
private string contentType = ContentTypeJson;
|
||||||
|
private PayloadEditorContentType contentTypeSelection = PayloadEditorContentType.Json;
|
||||||
|
private bool fixedJson;
|
||||||
|
|
||||||
|
private bool jsonValid = true;
|
||||||
|
private string jsonValidationMessage;
|
||||||
|
|
||||||
|
private string payload = "";
|
||||||
|
|
||||||
|
|
||||||
|
public string ContentType
|
||||||
|
{
|
||||||
|
get => ContentTypeSelection switch
|
||||||
|
{
|
||||||
|
PayloadEditorContentType.Json => ContentTypeJson,
|
||||||
|
PayloadEditorContentType.Plain => ContentTypePlain,
|
||||||
|
_ => contentType
|
||||||
|
};
|
||||||
|
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (!SetField(ref contentType, value))
|
||||||
|
return;
|
||||||
|
|
||||||
|
ContentTypeSelection = value switch
|
||||||
|
{
|
||||||
|
ContentTypeJson => PayloadEditorContentType.Json,
|
||||||
|
ContentTypePlain => PayloadEditorContentType.Plain,
|
||||||
|
_ => PayloadEditorContentType.Other
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public PayloadEditorContentType ContentTypeSelection
|
||||||
|
{
|
||||||
|
get => contentTypeSelection;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (!SetField(ref contentTypeSelection, value, otherPropertiesChanged: new [] { nameof(JsonValidationVisibility) }))
|
||||||
|
return;
|
||||||
|
|
||||||
|
ContentType = ContentTypeSelection switch
|
||||||
|
{
|
||||||
|
PayloadEditorContentType.Json => ContentTypeJson,
|
||||||
|
PayloadEditorContentType.Plain => ContentTypePlain,
|
||||||
|
_ => ContentType
|
||||||
|
};
|
||||||
|
|
||||||
|
ValidatePayload();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public bool FixedJson
|
||||||
|
{
|
||||||
|
get => fixedJson;
|
||||||
|
set => SetField(ref fixedJson, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Visibility JsonValidationVisibility => ContentTypeSelection == PayloadEditorContentType.Json ? Visibility.Visible : Visibility.Collapsed;
|
||||||
|
public Visibility JsonValidationOk => JsonValid ? Visibility.Visible : Visibility.Collapsed;
|
||||||
|
public Visibility JsonValidationError => !JsonValid ? Visibility.Visible : Visibility.Collapsed;
|
||||||
|
|
||||||
|
|
||||||
|
public string JsonValidationMessage
|
||||||
|
{
|
||||||
|
get => jsonValidationMessage;
|
||||||
|
private set => SetField(ref jsonValidationMessage, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public bool JsonValid
|
||||||
|
{
|
||||||
|
get => jsonValid;
|
||||||
|
private set => SetField(ref jsonValid, value, otherPropertiesChanged: new[] { nameof(JsonValidationOk), nameof(JsonValidationError) });
|
||||||
|
}
|
||||||
|
|
||||||
|
public Visibility ContentTypeVisibility => FixedJson ? Visibility.Collapsed : Visibility.Visible;
|
||||||
|
|
||||||
|
|
||||||
|
public string Payload
|
||||||
|
{
|
||||||
|
get => payload;
|
||||||
|
set => SetField(ref payload, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public PayloadEditorViewModel()
|
||||||
|
{
|
||||||
|
jsonValidationMessage = PayloadEditorStrings.JsonValidationOk;
|
||||||
|
|
||||||
|
Observable.FromEventPattern<PropertyChangedEventHandler, PropertyChangedEventArgs>(
|
||||||
|
h => PropertyChanged += h,
|
||||||
|
h => PropertyChanged -= h)
|
||||||
|
.Where(e => e.EventArgs.PropertyName == nameof(Payload))
|
||||||
|
.Throttle(TimeSpan.FromMilliseconds(500))
|
||||||
|
.Subscribe(_ => ValidatePayload());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void ValidatePayload()
|
||||||
|
{
|
||||||
|
if (ContentTypeSelection != PayloadEditorContentType.Json)
|
||||||
|
{
|
||||||
|
JsonValid = true;
|
||||||
|
JsonValidationMessage = PayloadEditorStrings.JsonValidationOk;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrEmpty(Payload))
|
||||||
|
JToken.Parse(Payload);
|
||||||
|
|
||||||
|
JsonValid = true;
|
||||||
|
JsonValidationMessage = PayloadEditorStrings.JsonValidationOk;
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
JsonValid = false;
|
||||||
|
JsonValidationMessage = string.Format(PayloadEditorStrings.JsonValidationError, e.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public class DesignTimePayloadEditorViewModel : PayloadEditorViewModel
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
@ -29,7 +29,6 @@
|
|||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
<RowDefinition Height="Auto" />
|
|
||||||
<RowDefinition Height="16"/>
|
<RowDefinition Height="16"/>
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
@ -95,38 +94,35 @@
|
|||||||
|
|
||||||
<Label Grid.Row="2" Grid.Column="0" Content="{x:Static publisher:RawPublisherViewStrings.LabelProperties}" Style="{StaticResource SectionLabel}"/>
|
<Label Grid.Row="2" Grid.Column="0" Content="{x:Static publisher:RawPublisherViewStrings.LabelProperties}" Style="{StaticResource SectionLabel}"/>
|
||||||
|
|
||||||
<Label Grid.Row="3" Grid.Column="0" Content="{x:Static publisher:RawPublisherViewStrings.LabelContentType}" />
|
<Label Grid.Row="3" Grid.Column="0" Content="{x:Static publisher:RawPublisherViewStrings.LabelCorrelationId}" />
|
||||||
<TextBox Grid.Row="3" Grid.Column="1" Text="{Binding ContentType, UpdateSourceTrigger=PropertyChanged}" />
|
<TextBox Grid.Row="3" Grid.Column="1" Text="{Binding CorrelationId, UpdateSourceTrigger=PropertyChanged}" />
|
||||||
|
|
||||||
<Label Grid.Row="4" Grid.Column="0" Content="{x:Static publisher:RawPublisherViewStrings.LabelCorrelationId}" />
|
<Label Grid.Row="4" Grid.Column="0" Content="{x:Static publisher:RawPublisherViewStrings.LabelAppId}" Visibility="{Binding PropertiesExpandedVisibility}" />
|
||||||
<TextBox Grid.Row="4" Grid.Column="1" Text="{Binding CorrelationId, UpdateSourceTrigger=PropertyChanged}" />
|
<TextBox Grid.Row="4" Grid.Column="1" Text="{Binding AppId, UpdateSourceTrigger=PropertyChanged}" Visibility="{Binding PropertiesExpandedVisibility}" />
|
||||||
|
|
||||||
<Label Grid.Row="5" Grid.Column="0" Content="{x:Static publisher:RawPublisherViewStrings.LabelAppId}" Visibility="{Binding PropertiesExpandedVisibility}" />
|
<Label Grid.Row="5" Grid.Column="0" Content="{x:Static publisher:RawPublisherViewStrings.LabelContentEncoding}" Visibility="{Binding PropertiesExpandedVisibility}" />
|
||||||
<TextBox Grid.Row="5" Grid.Column="1" Text="{Binding AppId, UpdateSourceTrigger=PropertyChanged}" Visibility="{Binding PropertiesExpandedVisibility}" />
|
<TextBox Grid.Row="5" Grid.Column="1" Text="{Binding ContentEncoding, UpdateSourceTrigger=PropertyChanged}" Visibility="{Binding PropertiesExpandedVisibility}" />
|
||||||
|
|
||||||
<Label Grid.Row="6" Grid.Column="0" Content="{x:Static publisher:RawPublisherViewStrings.LabelContentEncoding}" Visibility="{Binding PropertiesExpandedVisibility}" />
|
<Label Grid.Row="6" Grid.Column="0" Content="{x:Static publisher:RawPublisherViewStrings.LabelExpiration}" Visibility="{Binding PropertiesExpandedVisibility}" />
|
||||||
<TextBox Grid.Row="6" Grid.Column="1" Text="{Binding ContentEncoding, UpdateSourceTrigger=PropertyChanged}" Visibility="{Binding PropertiesExpandedVisibility}" />
|
<TextBox Grid.Row="6" Grid.Column="1" Text="{Binding Expiration, UpdateSourceTrigger=PropertyChanged}" Visibility="{Binding PropertiesExpandedVisibility}" />
|
||||||
|
|
||||||
<Label Grid.Row="7" Grid.Column="0" Content="{x:Static publisher:RawPublisherViewStrings.LabelExpiration}" Visibility="{Binding PropertiesExpandedVisibility}" />
|
<Label Grid.Row="7" Grid.Column="0" Content="{x:Static publisher:RawPublisherViewStrings.LabelMessageId}" Visibility="{Binding PropertiesExpandedVisibility}" />
|
||||||
<TextBox Grid.Row="7" Grid.Column="1" Text="{Binding Expiration, UpdateSourceTrigger=PropertyChanged}" Visibility="{Binding PropertiesExpandedVisibility}" />
|
<TextBox Grid.Row="7" Grid.Column="1" Text="{Binding MessageId, UpdateSourceTrigger=PropertyChanged}" Visibility="{Binding PropertiesExpandedVisibility}" />
|
||||||
|
|
||||||
<Label Grid.Row="8" Grid.Column="0" Content="{x:Static publisher:RawPublisherViewStrings.LabelMessageId}" Visibility="{Binding PropertiesExpandedVisibility}" />
|
<Label Grid.Row="8" Grid.Column="0" Content="{x:Static publisher:RawPublisherViewStrings.LabelPriority}" Visibility="{Binding PropertiesExpandedVisibility}" />
|
||||||
<TextBox Grid.Row="8" Grid.Column="1" Text="{Binding MessageId, UpdateSourceTrigger=PropertyChanged}" Visibility="{Binding PropertiesExpandedVisibility}" />
|
<TextBox Grid.Row="8" Grid.Column="1" Text="{Binding Priority, UpdateSourceTrigger=PropertyChanged}" Visibility="{Binding PropertiesExpandedVisibility}" />
|
||||||
|
|
||||||
<Label Grid.Row="9" Grid.Column="0" Content="{x:Static publisher:RawPublisherViewStrings.LabelPriority}" Visibility="{Binding PropertiesExpandedVisibility}" />
|
<Label Grid.Row="9" Grid.Column="0" Content="{x:Static publisher:RawPublisherViewStrings.LabelTimestamp}" Visibility="{Binding PropertiesExpandedVisibility}" />
|
||||||
<TextBox Grid.Row="9" Grid.Column="1" Text="{Binding Priority, UpdateSourceTrigger=PropertyChanged}" Visibility="{Binding PropertiesExpandedVisibility}" />
|
<TextBox Grid.Row="9" Grid.Column="1" Text="{Binding Timestamp, UpdateSourceTrigger=PropertyChanged}" Visibility="{Binding PropertiesExpandedVisibility}" />
|
||||||
|
|
||||||
<Label Grid.Row="10" Grid.Column="0" Content="{x:Static publisher:RawPublisherViewStrings.LabelTimestamp}" Visibility="{Binding PropertiesExpandedVisibility}" />
|
<Label Grid.Row="10" Grid.Column="0" Content="{x:Static publisher:RawPublisherViewStrings.LabelType}" Visibility="{Binding PropertiesExpandedVisibility}" />
|
||||||
<TextBox Grid.Row="10" Grid.Column="1" Text="{Binding Timestamp, UpdateSourceTrigger=PropertyChanged}" Visibility="{Binding PropertiesExpandedVisibility}" />
|
<TextBox Grid.Row="10" Grid.Column="1" Text="{Binding TypeProperty, UpdateSourceTrigger=PropertyChanged}" Visibility="{Binding PropertiesExpandedVisibility}" />
|
||||||
|
|
||||||
<Label Grid.Row="11" Grid.Column="0" Content="{x:Static publisher:RawPublisherViewStrings.LabelType}" Visibility="{Binding PropertiesExpandedVisibility}" />
|
<Label Grid.Row="11" Grid.Column="0" Content="{x:Static publisher:RawPublisherViewStrings.LabelUserId}" Visibility="{Binding PropertiesExpandedVisibility}" />
|
||||||
<TextBox Grid.Row="11" Grid.Column="1" Text="{Binding TypeProperty, UpdateSourceTrigger=PropertyChanged}" Visibility="{Binding PropertiesExpandedVisibility}" />
|
<TextBox Grid.Row="11" Grid.Column="1" Text="{Binding UserId, UpdateSourceTrigger=PropertyChanged}" Visibility="{Binding PropertiesExpandedVisibility}" />
|
||||||
|
|
||||||
<Label Grid.Row="12" Grid.Column="0" Content="{x:Static publisher:RawPublisherViewStrings.LabelUserId}" Visibility="{Binding PropertiesExpandedVisibility}" />
|
|
||||||
<TextBox Grid.Row="12" Grid.Column="1" Text="{Binding UserId, UpdateSourceTrigger=PropertyChanged}" Visibility="{Binding PropertiesExpandedVisibility}" />
|
|
||||||
|
|
||||||
|
|
||||||
<Button Grid.Row="13" Grid.Column="1" Content="{Binding PropertiesExpandedCollapsedText}" Command="{Binding PropertiesExpandCollapseCommand}" Cursor="Hand">
|
<Button Grid.Row="12" Grid.Column="1" Content="{Binding PropertiesExpandedCollapsedText}" Command="{Binding PropertiesExpandCollapseCommand}" Cursor="Hand">
|
||||||
<Button.Template>
|
<Button.Template>
|
||||||
<ControlTemplate TargetType="{x:Type Button}">
|
<ControlTemplate TargetType="{x:Type Button}">
|
||||||
<ContentPresenter />
|
<ContentPresenter />
|
||||||
@ -134,7 +130,7 @@
|
|||||||
</Button.Template>
|
</Button.Template>
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
<Label Grid.Row="15" Grid.Column="0" Content="{x:Static publisher:RawPublisherViewStrings.LabelPayload}" />
|
<Label Grid.Row="14" Grid.Column="0" Content="{x:Static publisher:RawPublisherViewStrings.LabelPayload}" />
|
||||||
<TextBox Grid.Row="15" Grid.Column="1" Text="{Binding Payload, UpdateSourceTrigger=PropertyChanged}" Style="{StaticResource Payload}" Height="150" />
|
<publisher:PayloadEditorControl Grid.Row="14" Grid.Column="1" Payload="{Binding Payload}" ContentType="{Binding ContentType}" Height="350"/>
|
||||||
</ui:GridLayout>
|
</ui:GridLayout>
|
||||||
</UserControl>
|
</UserControl>
|
||||||
|
@ -48,6 +48,6 @@
|
|||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
<Label Grid.Row="6" Grid.Column="0" Content="{x:Static publisher:TapetiPublisherViewStrings.LabelPayload}" />
|
<Label Grid.Row="6" Grid.Column="0" Content="{x:Static publisher:TapetiPublisherViewStrings.LabelPayload}" />
|
||||||
<TextBox Grid.Row="6" Grid.Column="1" Text="{Binding Payload, UpdateSourceTrigger=PropertyChanged}" Style="{StaticResource Payload}" Height="150" />
|
<publisher:PayloadEditorControl Grid.Row="6" Grid.Column="1" Payload="{Binding Payload}" FixedJson="True" Height="350"/>
|
||||||
</ui:GridLayout>
|
</ui:GridLayout>
|
||||||
</UserControl>
|
</UserControl>
|
||||||
|
Loading…
Reference in New Issue
Block a user