├── src ├── VisualJsonEditor │ ├── Localization │ │ ├── Strings.fr.Designer.cs │ │ ├── Strings.pl.Designer.cs │ │ ├── Strings.pl.resx │ │ ├── Strings.fr.resx │ │ └── Strings.resx │ ├── FileIcon.ico │ ├── SplashScreen.png │ ├── ApplicationIcon.ico │ ├── Images │ │ ├── ButtonAboutLarge.png │ │ ├── ButtonAboutSmall.png │ │ ├── ButtonCloseLarge.png │ │ ├── ButtonCloseSmall.png │ │ ├── ButtonExitSmall.png │ │ ├── ButtonOpenLarge.png │ │ ├── ButtonOpenSmall.png │ │ ├── ButtonRedoSmall.png │ │ ├── ButtonSaveLarge.png │ │ ├── ButtonSaveSmall.png │ │ ├── ButtonUndoSmall.png │ │ ├── ButtonCreateLarge.png │ │ ├── ButtonCreateLarge2.png │ │ ├── ButtonCreateSmall.png │ │ ├── ButtonCreateSmall2.png │ │ ├── ButtonValidateLarge.png │ │ ├── ButtonValidateSmall.png │ │ ├── ButtonConfigurationLarge.png │ │ └── ButtonConfigurationSmall.png │ ├── Properties │ │ ├── Settings.settings │ │ ├── AssemblyInfo.cs │ │ ├── Settings.Designer.cs │ │ ├── Resources.Designer.cs │ │ └── Resources.resx │ ├── App.xaml │ ├── Samples │ │ ├── Sample.json │ │ └── Sample.schema.json │ ├── packages.config │ ├── Converters │ │ ├── DateTimeConverter.cs │ │ ├── DecimalUpDownRangeConverter.cs │ │ ├── IntegerConverter.cs │ │ ├── DateConverter.cs │ │ ├── TimeConverter.cs │ │ ├── IndexConverter.cs │ │ ├── IntegerUpDownRangeConverter.cs │ │ └── NumberConverter.cs │ ├── Messages │ │ ├── OpenJsonDocumentMessage.cs │ │ └── SaveJsonDocumentMessage.cs │ ├── Views │ │ ├── AboutWindow.xaml.cs │ │ ├── AboutWindow.xaml │ │ ├── MainWindow.xaml.cs │ │ └── MainWindow.xaml │ ├── App.config │ ├── Models │ │ ├── JsonTokenModel.cs │ │ ├── JsonValueModel.cs │ │ ├── JsonPropertyModel.cs │ │ ├── JsonDocumentModel.cs │ │ └── JsonObjectModel.cs │ ├── ApplicationConfiguration.cs │ ├── Controls │ │ ├── ExpandingGroupBox.cs │ │ ├── JsonObjectTypeTemplateSelector.cs │ │ ├── JsonEditor.xaml.cs │ │ └── JsonEditor.xaml │ ├── Themes │ │ └── Generic.xaml │ ├── App.xaml.cs │ ├── Utilities │ │ └── JsonApplicationConfiguration.cs │ ├── VisualJsonEditor.csproj │ └── ViewModels │ │ └── MainWindowModel.cs ├── .nuget │ ├── NuGet.exe │ ├── NuGet.Config │ └── NuGet.targets ├── VisualJsonEditor.sln └── VisualJsonEditor.Installer │ ├── VisualJsonEditor.Installer.wixproj │ └── Product.wxs ├── assets ├── FileIcon.png ├── ApplicationIcon.png ├── ApplicationIconSite.png ├── FileIcon.metrop └── ApplicationIcon.metrop ├── .gitignore ├── README.md └── LICENSE.md /src/VisualJsonEditor/Localization/Strings.fr.Designer.cs: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/VisualJsonEditor/Localization/Strings.pl.Designer.cs: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/FileIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RicoSuter/VisualJsonEditor/HEAD/assets/FileIcon.png -------------------------------------------------------------------------------- /src/.nuget/NuGet.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RicoSuter/VisualJsonEditor/HEAD/src/.nuget/NuGet.exe -------------------------------------------------------------------------------- /assets/ApplicationIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RicoSuter/VisualJsonEditor/HEAD/assets/ApplicationIcon.png -------------------------------------------------------------------------------- /assets/ApplicationIconSite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RicoSuter/VisualJsonEditor/HEAD/assets/ApplicationIconSite.png -------------------------------------------------------------------------------- /src/VisualJsonEditor/FileIcon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RicoSuter/VisualJsonEditor/HEAD/src/VisualJsonEditor/FileIcon.ico -------------------------------------------------------------------------------- /src/VisualJsonEditor/SplashScreen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RicoSuter/VisualJsonEditor/HEAD/src/VisualJsonEditor/SplashScreen.png -------------------------------------------------------------------------------- /src/VisualJsonEditor/ApplicationIcon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RicoSuter/VisualJsonEditor/HEAD/src/VisualJsonEditor/ApplicationIcon.ico -------------------------------------------------------------------------------- /src/VisualJsonEditor/Images/ButtonAboutLarge.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RicoSuter/VisualJsonEditor/HEAD/src/VisualJsonEditor/Images/ButtonAboutLarge.png -------------------------------------------------------------------------------- /src/VisualJsonEditor/Images/ButtonAboutSmall.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RicoSuter/VisualJsonEditor/HEAD/src/VisualJsonEditor/Images/ButtonAboutSmall.png -------------------------------------------------------------------------------- /src/VisualJsonEditor/Images/ButtonCloseLarge.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RicoSuter/VisualJsonEditor/HEAD/src/VisualJsonEditor/Images/ButtonCloseLarge.png -------------------------------------------------------------------------------- /src/VisualJsonEditor/Images/ButtonCloseSmall.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RicoSuter/VisualJsonEditor/HEAD/src/VisualJsonEditor/Images/ButtonCloseSmall.png -------------------------------------------------------------------------------- /src/VisualJsonEditor/Images/ButtonExitSmall.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RicoSuter/VisualJsonEditor/HEAD/src/VisualJsonEditor/Images/ButtonExitSmall.png -------------------------------------------------------------------------------- /src/VisualJsonEditor/Images/ButtonOpenLarge.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RicoSuter/VisualJsonEditor/HEAD/src/VisualJsonEditor/Images/ButtonOpenLarge.png -------------------------------------------------------------------------------- /src/VisualJsonEditor/Images/ButtonOpenSmall.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RicoSuter/VisualJsonEditor/HEAD/src/VisualJsonEditor/Images/ButtonOpenSmall.png -------------------------------------------------------------------------------- /src/VisualJsonEditor/Images/ButtonRedoSmall.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RicoSuter/VisualJsonEditor/HEAD/src/VisualJsonEditor/Images/ButtonRedoSmall.png -------------------------------------------------------------------------------- /src/VisualJsonEditor/Images/ButtonSaveLarge.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RicoSuter/VisualJsonEditor/HEAD/src/VisualJsonEditor/Images/ButtonSaveLarge.png -------------------------------------------------------------------------------- /src/VisualJsonEditor/Images/ButtonSaveSmall.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RicoSuter/VisualJsonEditor/HEAD/src/VisualJsonEditor/Images/ButtonSaveSmall.png -------------------------------------------------------------------------------- /src/VisualJsonEditor/Images/ButtonUndoSmall.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RicoSuter/VisualJsonEditor/HEAD/src/VisualJsonEditor/Images/ButtonUndoSmall.png -------------------------------------------------------------------------------- /src/VisualJsonEditor/Images/ButtonCreateLarge.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RicoSuter/VisualJsonEditor/HEAD/src/VisualJsonEditor/Images/ButtonCreateLarge.png -------------------------------------------------------------------------------- /src/VisualJsonEditor/Images/ButtonCreateLarge2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RicoSuter/VisualJsonEditor/HEAD/src/VisualJsonEditor/Images/ButtonCreateLarge2.png -------------------------------------------------------------------------------- /src/VisualJsonEditor/Images/ButtonCreateSmall.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RicoSuter/VisualJsonEditor/HEAD/src/VisualJsonEditor/Images/ButtonCreateSmall.png -------------------------------------------------------------------------------- /src/VisualJsonEditor/Images/ButtonCreateSmall2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RicoSuter/VisualJsonEditor/HEAD/src/VisualJsonEditor/Images/ButtonCreateSmall2.png -------------------------------------------------------------------------------- /src/VisualJsonEditor/Images/ButtonValidateLarge.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RicoSuter/VisualJsonEditor/HEAD/src/VisualJsonEditor/Images/ButtonValidateLarge.png -------------------------------------------------------------------------------- /src/VisualJsonEditor/Images/ButtonValidateSmall.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RicoSuter/VisualJsonEditor/HEAD/src/VisualJsonEditor/Images/ButtonValidateSmall.png -------------------------------------------------------------------------------- /src/VisualJsonEditor/Images/ButtonConfigurationLarge.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RicoSuter/VisualJsonEditor/HEAD/src/VisualJsonEditor/Images/ButtonConfigurationLarge.png -------------------------------------------------------------------------------- /src/VisualJsonEditor/Images/ButtonConfigurationSmall.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RicoSuter/VisualJsonEditor/HEAD/src/VisualJsonEditor/Images/ButtonConfigurationSmall.png -------------------------------------------------------------------------------- /src/.nuget/NuGet.Config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/VisualJsonEditor/Properties/Settings.settings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | **/bin/** 2 | **/obj/** 3 | **/packages/** 4 | 5 | **.suo 6 | **.user 7 | **.DotSettings 8 | 9 | /src/VisualJsonEditor.sln.ide 10 | /src/UpgradeLog.htm 11 | /src/VisualJsonEditor.sln.GhostDoc.xml 12 | /src/VisualJsonEditor/VisualJsonEditor.previous.nugetreferenceswitcher 13 | /src/.vs/ 14 | -------------------------------------------------------------------------------- /src/VisualJsonEditor/App.xaml: -------------------------------------------------------------------------------- 1 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/VisualJsonEditor/Samples/Sample.json: -------------------------------------------------------------------------------- 1 | { 2 | "StringValue": "a", 3 | "StringValueFormatByte": "dGVzdA==", 4 | "BoolValue": false, 5 | "NumberValue": 2.3, 6 | "DateTimeValue": "2014-08-13T21:00:00", 7 | "DateValue": "2014-08-14", 8 | "TimeValue": "02:00:00", 9 | "EnumValue": "two", 10 | "IntegerValue": 1, 11 | "Test": { 12 | "Abc": "e", 13 | "Def": "d", 14 | "Geh": "d" 15 | }, 16 | "List": [ 17 | { 18 | "Abc": "a", 19 | "Def": "b", 20 | "Geh": "c" 21 | }, 22 | { 23 | "Abc": "", 24 | "Def": "b", 25 | "Geh": "c" 26 | } 27 | ] 28 | } -------------------------------------------------------------------------------- /src/VisualJsonEditor/packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /src/VisualJsonEditor/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.InteropServices; 3 | using System.Windows; 4 | 5 | [assembly: AssemblyTitle("VisualJsonEditor")] 6 | [assembly: AssemblyDescription("")] 7 | [assembly: AssemblyConfiguration("")] 8 | [assembly: AssemblyCompany("Rico Suter")] 9 | [assembly: AssemblyProduct("VisualJsonEditor")] 10 | [assembly: AssemblyCopyright("Copyright © Rico Suter, 2020")] 11 | [assembly: AssemblyTrademark("")] 12 | [assembly: AssemblyCulture("")] 13 | 14 | [assembly: ComVisible(false)] 15 | 16 | [assembly: ThemeInfo( 17 | ResourceDictionaryLocation.None, 18 | ResourceDictionaryLocation.SourceAssembly 19 | )] 20 | 21 | [assembly: AssemblyVersion("2.11.*")] 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Visual JSON Editor 2 | 3 | [![Build status](https://ci.appveyor.com/api/projects/status/x25686ex1dp8smax?svg=true)](https://ci.appveyor.com/project/rsuter/visualjsoneditor) 4 | 5 | Visual JSON Editor is a JSON schema draft v4 based file editor for Windows: When opening a JSON file, the application auto-generates an editor GUI based on the provided JSON schema. The goal is to make JSON editing more effective and easier for users. 6 | 7 | **[Download latest Visual JSON Editor installer (MSI)](http://rsuter.com/Projects/VisualJsonEditor/installer.php)** 8 | 9 | **[Article describing a usage scenario](https://blog.rsuter.com/use-json-files-with-schema-for-application-configuration-2/)** 10 | 11 | **Tip:** Use the [NJsonSchema](http://njsonschema.org) library to generate JSON Schemas from your C# classes. 12 | 13 | Visual JSON Editor is developed by [Rico Suter](http://rsuter.com) using the [MyToolkit](http://mytoolkit.io) and [NJsonSchema](http://njsonschema.org) libraries. 14 | 15 | ![](http://rsuter.com/Projects/VisualJsonEditor/Screenshot02.png) 16 | 17 | ![](http://rsuter.com/Projects/VisualJsonEditor/Screenshot01.png) 18 | -------------------------------------------------------------------------------- /src/VisualJsonEditor/Converters/DateTimeConverter.cs: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------- 2 | // 3 | // Copyright (c) Rico Suter. All rights reserved. 4 | // 5 | // http://visualjsoneditor.codeplex.com/license 6 | // Rico Suter, mail@rsuter.com 7 | //----------------------------------------------------------------------- 8 | 9 | using System; 10 | using System.Globalization; 11 | using System.Windows.Data; 12 | 13 | namespace VisualJsonEditor.Converters 14 | { 15 | public class DateTimeConverter : IValueConverter 16 | { 17 | public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 18 | { 19 | if (value == null) 20 | return null; 21 | 22 | return value is DateTime ? value : DateTime.Parse(value.ToString()); 23 | } 24 | 25 | public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 26 | { 27 | return value; 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Rico Suter 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/VisualJsonEditor/Converters/DecimalUpDownRangeConverter.cs: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------- 2 | // 3 | // Copyright (c) Rico Suter. All rights reserved. 4 | // 5 | // http://visualjsoneditor.codeplex.com/license 6 | // Rico Suter, mail@rsuter.com 7 | //----------------------------------------------------------------------- 8 | 9 | using System; 10 | using System.Globalization; 11 | using System.Windows.Data; 12 | 13 | namespace VisualJsonEditor.Converters 14 | { 15 | public class DecimalUpDownRangeConverter : IValueConverter 16 | { 17 | public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 18 | { 19 | if (value == null) 20 | return parameter.ToString() == "min" ? decimal.MinValue : decimal.MaxValue; 21 | return (decimal)value; 22 | } 23 | 24 | public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 25 | { 26 | return value; 27 | } 28 | } 29 | } -------------------------------------------------------------------------------- /src/VisualJsonEditor/Messages/OpenJsonDocumentMessage.cs: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------- 2 | // 3 | // Copyright (c) Rico Suter. All rights reserved. 4 | // 5 | // http://visualjsoneditor.codeplex.com/license 6 | // Rico Suter, mail@rsuter.com 7 | //----------------------------------------------------------------------- 8 | 9 | using MyToolkit.Messaging; 10 | 11 | namespace VisualJsonEditor.Messages 12 | { 13 | /// Message to show the file open dialog to open a JSON document. 14 | public class OpenJsonDocumentMessage : CallbackMessage 15 | { 16 | /// Initializes a new instance of the class. 17 | /// The title to show in the dialog. 18 | public OpenJsonDocumentMessage(string title) 19 | { 20 | Title = title; 21 | } 22 | 23 | /// Gets or sets the file name. 24 | public string Title { get; private set; } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/VisualJsonEditor/Messages/SaveJsonDocumentMessage.cs: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------- 2 | // 3 | // Copyright (c) Rico Suter. All rights reserved. 4 | // 5 | // http://visualjsoneditor.codeplex.com/license 6 | // Rico Suter, mail@rsuter.com 7 | //----------------------------------------------------------------------- 8 | 9 | using MyToolkit.Messaging; 10 | 11 | namespace VisualJsonEditor.Messages 12 | { 13 | /// Message to show the save file dialog for a JSON document. 14 | public class SaveJsonDocumentMessage : CallbackMessage 15 | { 16 | /// Initializes a new instance of the class. 17 | /// The default file path of the JSON document. 18 | public SaveJsonDocumentMessage(string fileName) 19 | { 20 | FileName = fileName; 21 | } 22 | 23 | /// Gets or sets the file name. 24 | public string FileName { get; private set; } 25 | } 26 | } -------------------------------------------------------------------------------- /src/VisualJsonEditor/Properties/Settings.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.34014 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace VisualJsonEditor.Properties 12 | { 13 | 14 | 15 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 16 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")] 17 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase 18 | { 19 | 20 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); 21 | 22 | public static Settings Default 23 | { 24 | get 25 | { 26 | return defaultInstance; 27 | } 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/VisualJsonEditor/Converters/IntegerConverter.cs: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------- 2 | // 3 | // Copyright (c) Rico Suter. All rights reserved. 4 | // 5 | // http://visualjsoneditor.codeplex.com/license 6 | // Rico Suter, mail@rsuter.com 7 | //----------------------------------------------------------------------- 8 | 9 | using System; 10 | using System.Globalization; 11 | using System.Windows.Data; 12 | 13 | namespace VisualJsonEditor.Converters 14 | { 15 | public class IntegerConverter : IValueConverter 16 | { 17 | public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 18 | { 19 | return value != null ? value.ToString() : null; 20 | } 21 | 22 | public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 23 | { 24 | try 25 | { 26 | return long.Parse(value.ToString()); 27 | } 28 | catch 29 | { 30 | return default(long); 31 | } 32 | } 33 | } 34 | } -------------------------------------------------------------------------------- /src/VisualJsonEditor/Converters/DateConverter.cs: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------- 2 | // 3 | // Copyright (c) Rico Suter. All rights reserved. 4 | // 5 | // http://visualjsoneditor.codeplex.com/license 6 | // Rico Suter, mail@rsuter.com 7 | //----------------------------------------------------------------------- 8 | 9 | using System; 10 | using System.Globalization; 11 | using System.Windows.Data; 12 | 13 | namespace VisualJsonEditor.Converters 14 | { 15 | public class DateConverter : IValueConverter 16 | { 17 | public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 18 | { 19 | if (value == null) 20 | return null; 21 | 22 | return value is DateTime ? value : DateTime.Parse(value.ToString()); 23 | } 24 | 25 | public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 26 | { 27 | if (value is DateTime) 28 | { 29 | return ((DateTime)value).ToString("yyyy-MM-dd"); 30 | } 31 | return null; 32 | } 33 | } 34 | } -------------------------------------------------------------------------------- /src/VisualJsonEditor/Converters/TimeConverter.cs: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------- 2 | // 3 | // Copyright (c) Rico Suter. All rights reserved. 4 | // 5 | // http://visualjsoneditor.codeplex.com/license 6 | // Rico Suter, mail@rsuter.com 7 | //----------------------------------------------------------------------- 8 | 9 | using System; 10 | using System.Globalization; 11 | using System.Windows.Data; 12 | 13 | namespace VisualJsonEditor.Converters 14 | { 15 | public class TimeConverter : IValueConverter 16 | { 17 | public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 18 | { 19 | if (value == null) 20 | return null; 21 | 22 | return value is TimeSpan ? 23 | DateTime.MinValue + (TimeSpan)value : 24 | DateTime.MinValue + TimeSpan.Parse(value.ToString()); 25 | } 26 | 27 | public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 28 | { 29 | if (value is DateTime) 30 | return ((DateTime)value).TimeOfDay; 31 | 32 | return value; 33 | } 34 | } 35 | } -------------------------------------------------------------------------------- /src/VisualJsonEditor/Converters/IndexConverter.cs: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------- 2 | // 3 | // Copyright (c) Rico Suter. All rights reserved. 4 | // 5 | // http://visualjsoneditor.codeplex.com/license 6 | // Rico Suter, mail@rsuter.com 7 | //----------------------------------------------------------------------- 8 | 9 | using System; 10 | using System.Collections; 11 | using System.Globalization; 12 | using System.Windows.Data; 13 | 14 | namespace VisualJsonEditor.Converters 15 | { 16 | public class IndexConverter : IMultiValueConverter 17 | { 18 | public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) 19 | { 20 | var list = (IList)values[1]; 21 | if (list != null) 22 | { 23 | var index = list.IndexOf(values[0]) + 1; 24 | return targetType == typeof(string) ? index.ToString() : (object)index; 25 | } 26 | return null; 27 | } 28 | 29 | public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) 30 | { 31 | throw new NotImplementedException(); 32 | } 33 | } 34 | } -------------------------------------------------------------------------------- /src/VisualJsonEditor/Converters/IntegerUpDownRangeConverter.cs: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------- 2 | // 3 | // Copyright (c) Rico Suter. All rights reserved. 4 | // 5 | // http://visualjsoneditor.codeplex.com/license 6 | // Rico Suter, mail@rsuter.com 7 | //----------------------------------------------------------------------- 8 | 9 | using System; 10 | using System.Globalization; 11 | using System.Windows.Data; 12 | 13 | namespace VisualJsonEditor.Converters 14 | { 15 | public class IntegerUpDownRangeConverter : IValueConverter 16 | { 17 | public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 18 | { 19 | if (value == null) 20 | return parameter.ToString() == "min" ? int.MinValue : int.MaxValue; 21 | 22 | if (value is decimal) 23 | return (int)(decimal)value; 24 | if (value is double) 25 | return (int)(double)value; 26 | 27 | return (int)value; 28 | } 29 | 30 | public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 31 | { 32 | return value; 33 | } 34 | } 35 | } -------------------------------------------------------------------------------- /src/VisualJsonEditor/Views/AboutWindow.xaml.cs: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------- 2 | // 3 | // Copyright (c) Rico Suter. All rights reserved. 4 | // 5 | // http://visualjsoneditor.codeplex.com/license 6 | // Rico Suter, mail@rsuter.com 7 | //----------------------------------------------------------------------- 8 | 9 | using System.Diagnostics; 10 | using System.Reflection; 11 | using System.Windows; 12 | using System.Windows.Documents; 13 | using MyToolkit.Utilities; 14 | 15 | namespace VisualJsonEditor.Views 16 | { 17 | /// Interaction logic for AboutWindow.xaml 18 | public partial class AboutWindow : Window 19 | { 20 | public AboutWindow() 21 | { 22 | InitializeComponent(); 23 | Version.Text = "v" + Assembly.GetExecutingAssembly().GetVersionWithBuildTime(); 24 | } 25 | 26 | private void OnOpenHyperlink(object sender, RoutedEventArgs e) 27 | { 28 | var uri = ((Hyperlink)sender).NavigateUri; 29 | Process.Start(uri.ToString()); 30 | } 31 | 32 | private void OnClose(object sender, RoutedEventArgs e) 33 | { 34 | Close(); 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /assets/FileIcon.metrop: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/VisualJsonEditor/App.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /assets/ApplicationIcon.metrop: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/VisualJsonEditor/Converters/NumberConverter.cs: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------- 2 | // 3 | // Copyright (c) Rico Suter. All rights reserved. 4 | // 5 | // http://visualjsoneditor.codeplex.com/license 6 | // Rico Suter, mail@rsuter.com 7 | //----------------------------------------------------------------------- 8 | 9 | using System; 10 | using System.Globalization; 11 | using System.Windows.Data; 12 | 13 | namespace VisualJsonEditor.Converters 14 | { 15 | public class NumberConverter : IValueConverter 16 | { 17 | public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 18 | { 19 | return value != null ? value.ToString() : null; 20 | } 21 | 22 | public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 23 | { 24 | if (targetType == typeof(decimal)) 25 | { 26 | try 27 | { 28 | return decimal.Parse(value.ToString()); 29 | } 30 | catch 31 | { 32 | return default(decimal); 33 | } 34 | } 35 | else 36 | { 37 | try 38 | { 39 | return double.Parse(value.ToString()); 40 | } 41 | catch 42 | { 43 | return default(double); 44 | } 45 | } 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/VisualJsonEditor/Models/JsonTokenModel.cs: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------- 2 | // 3 | // Copyright (c) Rico Suter. All rights reserved. 4 | // 5 | // http://visualjsoneditor.codeplex.com/license 6 | // Rico Suter, mail@rsuter.com 7 | //----------------------------------------------------------------------- 8 | 9 | using System.Collections.ObjectModel; 10 | using MyToolkit.Collections; 11 | using Newtonsoft.Json; 12 | using Newtonsoft.Json.Linq; 13 | using NJsonSchema; 14 | 15 | namespace VisualJsonEditor.Models 16 | { 17 | /// Represents a JSON token which may be an object or a single value. 18 | public abstract class JsonTokenModel : ObservableDictionary 19 | { 20 | /// Gets or sets the schema of the token. 21 | public JsonSchema Schema { get; set; } 22 | 23 | /// Gets or sets the parent list if applicable (may be null). 24 | public ObservableCollection ParentList { get; set; } 25 | 26 | /// Converts the token to a JSON string. 27 | /// The JSON string. 28 | public string ToJson() 29 | { 30 | var token = ToJToken(); 31 | return JsonConvert.SerializeObject(token, Formatting.Indented); 32 | } 33 | 34 | /// Converts the to a . 35 | /// The . 36 | public abstract JToken ToJToken(); 37 | } 38 | } -------------------------------------------------------------------------------- /src/VisualJsonEditor/ApplicationConfiguration.cs: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------- 2 | // 3 | // Copyright (c) Rico Suter. All rights reserved. 4 | // 5 | // http://visualjsoneditor.codeplex.com/license 6 | // Rico Suter, mail@rsuter.com 7 | //----------------------------------------------------------------------- 8 | 9 | using System.Collections.ObjectModel; 10 | using System.IO; 11 | using System.Windows; 12 | using Newtonsoft.Json; 13 | 14 | namespace VisualJsonEditor 15 | { 16 | /// Stores the application configuration. 17 | public class ApplicationConfiguration 18 | { 19 | public ApplicationConfiguration() 20 | { 21 | IsFirstStart = true; 22 | 23 | WindowHeight = 600; 24 | WindowWidth = 700; 25 | WindowState = WindowState.Normal; 26 | 27 | RecentFiles = new ObservableCollection(); 28 | } 29 | 30 | public bool IsFirstStart { get; set; } 31 | public double WindowWidth { get; set; } 32 | public double WindowHeight { get; set; } 33 | public WindowState WindowState { get; set; } 34 | public ObservableCollection RecentFiles { get; set; } 35 | } 36 | 37 | /// Describes a recently opened file. 38 | public class RecentFile 39 | { 40 | /// Gets or sets the file path. 41 | public string FilePath { get; set; } 42 | 43 | [JsonIgnore] 44 | public string FileName { get { return Path.GetFileName(FilePath); } } 45 | } 46 | } -------------------------------------------------------------------------------- /src/VisualJsonEditor/Models/JsonValueModel.cs: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------- 2 | // 3 | // Copyright (c) Rico Suter. All rights reserved. 4 | // 5 | // http://visualjsoneditor.codeplex.com/license 6 | // Rico Suter, mail@rsuter.com 7 | //----------------------------------------------------------------------- 8 | 9 | using Newtonsoft.Json.Linq; 10 | using NJsonSchema; 11 | 12 | namespace VisualJsonEditor.Models 13 | { 14 | /// Represents a single JSON value. 15 | public class JsonValueModel : JsonTokenModel 16 | { 17 | /// Initializes a new instance of the class. 18 | public JsonValueModel() 19 | { 20 | this["Value"] = null; 21 | } 22 | 23 | /// Creates a from a and a given schema. 24 | /// The value. 25 | /// The schema. 26 | /// The . 27 | public static JsonValueModel FromJson(JValue value, JsonSchema schema) 28 | { 29 | return new JsonValueModel 30 | { 31 | Schema = schema, 32 | Value = value.Value 33 | }; 34 | } 35 | 36 | /// Gets or sets the value. 37 | public object Value 38 | { 39 | get { return ContainsKey("Value") ? this["Value"] : null; } 40 | set { this["Value"] = value; } 41 | } 42 | 43 | /// Converts the to a . 44 | /// The . 45 | public override JToken ToJToken() 46 | { 47 | return new JValue(Value); 48 | } 49 | } 50 | } -------------------------------------------------------------------------------- /src/VisualJsonEditor/Samples/Sample.schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "object", 3 | "title": "Person", 4 | "required": [ 5 | "StringValue", 6 | "BoolValue", 7 | "NumberValue", 8 | "DateTimeValue", 9 | "DateValue", 10 | "TimeValue", 11 | "IntegerValue", 12 | "Test", 13 | "List" 14 | ], 15 | "properties": { 16 | "StringValue": { 17 | "type": "string", 18 | "default": "n/a" 19 | }, 20 | "StringValueFormatByte": { 21 | "type": "string", 22 | "format": "byte" 23 | }, 24 | "BoolValue": { 25 | "type": "boolean" 26 | }, 27 | "NumberValue": { 28 | "type": "number", 29 | "minimum": -1 30 | }, 31 | "DateTimeValue": { 32 | "type": "string", 33 | "format": "date-time" 34 | }, 35 | "DateValue": { 36 | "type": "string", 37 | "format": "date" 38 | }, 39 | "TimeValue": { 40 | "type": "string", 41 | "format": "time" 42 | }, 43 | "IntegerValue": { 44 | "type": "integer", 45 | "minimum": 0 46 | }, 47 | "EnumValue": { 48 | "type": "string", 49 | "enum": [ "one", "two", "three" ], 50 | "x-enumNames": [ "One", "Two", "Three" ] 51 | }, 52 | "Test": { 53 | "type": "object", 54 | "required": [ 55 | "Abc", 56 | "Def", 57 | "Geh" 58 | ], 59 | "properties": { 60 | "Abc": { 61 | "type": "string" 62 | }, 63 | "Def": { 64 | "type": "string" 65 | }, 66 | "Geh": { 67 | "type": "string" 68 | } 69 | } 70 | }, 71 | "List": { 72 | "type": "array", 73 | "items": { 74 | "type": "object", 75 | "properties": { 76 | "Abc": { 77 | "type": "string", 78 | "minLength": 1 79 | }, 80 | "Def": { 81 | "type": "string" 82 | }, 83 | "Geh": { 84 | "type": "string" 85 | } 86 | } 87 | } 88 | } 89 | } 90 | } -------------------------------------------------------------------------------- /src/VisualJsonEditor.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2013 4 | VisualStudioVersion = 12.0.31101.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VisualJsonEditor", "VisualJsonEditor\VisualJsonEditor.csproj", "{CA84EB04-87DC-4287-A7FB-56A0C61C06BA}" 7 | EndProject 8 | Project("{930C7802-8A8C-48F9-8165-68863BCCD9DD}") = "VisualJsonEditor.Installer", "VisualJsonEditor.Installer\VisualJsonEditor.Installer.wixproj", "{16A1D263-97CA-421B-B03A-96BDEFE05F89}" 9 | EndProject 10 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{E4B6C387-F4A5-4DD1-B36F-97AB02D8A266}" 11 | ProjectSection(SolutionItems) = preProject 12 | .nuget\NuGet.Config = .nuget\NuGet.Config 13 | .nuget\NuGet.exe = .nuget\NuGet.exe 14 | .nuget\NuGet.targets = .nuget\NuGet.targets 15 | EndProjectSection 16 | EndProject 17 | Global 18 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 19 | Debug|Any CPU = Debug|Any CPU 20 | Debug|Mixed Platforms = Debug|Mixed Platforms 21 | Release|Any CPU = Release|Any CPU 22 | Release|Mixed Platforms = Release|Mixed Platforms 23 | EndGlobalSection 24 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 25 | {CA84EB04-87DC-4287-A7FB-56A0C61C06BA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 26 | {CA84EB04-87DC-4287-A7FB-56A0C61C06BA}.Debug|Any CPU.Build.0 = Debug|Any CPU 27 | {CA84EB04-87DC-4287-A7FB-56A0C61C06BA}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU 28 | {CA84EB04-87DC-4287-A7FB-56A0C61C06BA}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU 29 | {CA84EB04-87DC-4287-A7FB-56A0C61C06BA}.Release|Any CPU.ActiveCfg = Release|Any CPU 30 | {CA84EB04-87DC-4287-A7FB-56A0C61C06BA}.Release|Any CPU.Build.0 = Release|Any CPU 31 | {CA84EB04-87DC-4287-A7FB-56A0C61C06BA}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU 32 | {CA84EB04-87DC-4287-A7FB-56A0C61C06BA}.Release|Mixed Platforms.Build.0 = Release|Any CPU 33 | {16A1D263-97CA-421B-B03A-96BDEFE05F89}.Debug|Any CPU.ActiveCfg = Debug|x86 34 | {16A1D263-97CA-421B-B03A-96BDEFE05F89}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 35 | {16A1D263-97CA-421B-B03A-96BDEFE05F89}.Debug|Mixed Platforms.Build.0 = Debug|x86 36 | {16A1D263-97CA-421B-B03A-96BDEFE05F89}.Release|Any CPU.ActiveCfg = Release|x86 37 | {16A1D263-97CA-421B-B03A-96BDEFE05F89}.Release|Any CPU.Build.0 = Release|x86 38 | {16A1D263-97CA-421B-B03A-96BDEFE05F89}.Release|Mixed Platforms.ActiveCfg = Release|x86 39 | {16A1D263-97CA-421B-B03A-96BDEFE05F89}.Release|Mixed Platforms.Build.0 = Release|x86 40 | EndGlobalSection 41 | GlobalSection(SolutionProperties) = preSolution 42 | HideSolutionNode = FALSE 43 | EndGlobalSection 44 | EndGlobal 45 | -------------------------------------------------------------------------------- /src/VisualJsonEditor/Properties/Resources.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.34014 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace VisualJsonEditor.Properties 12 | { 13 | 14 | 15 | /// 16 | /// A strongly-typed resource class, for looking up localized strings, etc. 17 | /// 18 | // This class was auto-generated by the StronglyTypedResourceBuilder 19 | // class via a tool like ResGen or Visual Studio. 20 | // To add or remove a member, edit your .ResX file then rerun ResGen 21 | // with the /str option, or rebuild your VS project. 22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] 23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 25 | internal class Resources 26 | { 27 | 28 | private static global::System.Resources.ResourceManager resourceMan; 29 | 30 | private static global::System.Globalization.CultureInfo resourceCulture; 31 | 32 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 33 | internal Resources() 34 | { 35 | } 36 | 37 | /// 38 | /// Returns the cached ResourceManager instance used by this class. 39 | /// 40 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 41 | internal static global::System.Resources.ResourceManager ResourceManager 42 | { 43 | get 44 | { 45 | if ((resourceMan == null)) 46 | { 47 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("VisualJsonEditor.Properties.Resources", typeof(Resources).Assembly); 48 | resourceMan = temp; 49 | } 50 | return resourceMan; 51 | } 52 | } 53 | 54 | /// 55 | /// Overrides the current thread's CurrentUICulture property for all 56 | /// resource lookups using this strongly typed resource class. 57 | /// 58 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 59 | internal static global::System.Globalization.CultureInfo Culture 60 | { 61 | get 62 | { 63 | return resourceCulture; 64 | } 65 | set 66 | { 67 | resourceCulture = value; 68 | } 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/VisualJsonEditor/Controls/ExpandingGroupBox.cs: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------- 2 | // 3 | // Copyright (c) Rico Suter. All rights reserved. 4 | // 5 | // http://visualjsoneditor.codeplex.com/license 6 | // Rico Suter, mail@rsuter.com 7 | //----------------------------------------------------------------------- 8 | 9 | using System.Windows; 10 | using System.Windows.Controls; 11 | using MyToolkit.Utilities; 12 | 13 | namespace VisualJsonEditor.Controls 14 | { 15 | /// A group box with expander. 16 | public class ExpandingGroupBox : ContentControl 17 | { 18 | static ExpandingGroupBox() 19 | { 20 | DefaultStyleKeyProperty.OverrideMetadata(typeof(ExpandingGroupBox), new FrameworkPropertyMetadata(typeof(ExpandingGroupBox))); 21 | } 22 | 23 | public static readonly DependencyProperty HeaderProperty = DependencyProperty.Register( 24 | "Header", typeof (object), typeof (ExpandingGroupBox), new PropertyMetadata(default(object))); 25 | 26 | /// Gets or sets the header object (data context of header template). 27 | public object Header 28 | { 29 | get { return (object) GetValue(HeaderProperty); } 30 | set { SetValue(HeaderProperty, value); } 31 | } 32 | 33 | public static readonly DependencyProperty HeaderTemplateProperty = DependencyProperty.Register( 34 | "HeaderTemplate", typeof (DataTemplate), typeof (ExpandingGroupBox), new PropertyMetadata(default(DataTemplate))); 35 | 36 | /// Gets or sets the header template (always visible). 37 | public DataTemplate HeaderTemplate 38 | { 39 | get { return (DataTemplate) GetValue(HeaderTemplateProperty); } 40 | set { SetValue(HeaderTemplateProperty, value); } 41 | } 42 | 43 | public static readonly DependencyProperty IsExpandedProperty = DependencyProperty.Register( 44 | "IsExpanded", typeof (bool), typeof (ExpandingGroupBox), new PropertyMetadata(true)); 45 | 46 | /// Gets or sets a value indicating whether the group box is expanded. 47 | public bool IsExpanded 48 | { 49 | get { return (bool) GetValue(IsExpandedProperty); } 50 | set { SetValue(IsExpandedProperty, value); } 51 | } 52 | 53 | /// When overridden in a derived class, is invoked whenever application code or internal 54 | /// processes call . 55 | public override void OnApplyTemplate() 56 | { 57 | base.OnApplyTemplate(); 58 | 59 | Loaded += delegate 60 | { 61 | var button = this.FindVisualChild 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 70 | 71 | 75 | 76 | 80 | 81 | 84 | 87 | 88 | 90 | 91 | 92 | 93 | 94 | 95 | 97 | 99 | 101 | 102 | 103 | 104 | 105 | 106 | 111 | 116 | 121 | 122 | 123 | 126 | 127 | 128 | 129 | 130 | 131 | 134 | 135 | 136 | 137 | 138 | 139 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 151 | 152 | 154 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 166 | 167 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 193 | 194 | 196 | 197 | 199 | 200 | 201 | 202 | 203 | 204 | -------------------------------------------------------------------------------- /src/VisualJsonEditor/VisualJsonEditor.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {CA84EB04-87DC-4287-A7FB-56A0C61C06BA} 8 | WinExe 9 | Properties 10 | VisualJsonEditor 11 | VisualJsonEditor 12 | v4.5 13 | 512 14 | {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 15 | 4 16 | ..\ 17 | true 18 | 19 | 20 | AnyCPU 21 | true 22 | full 23 | false 24 | bin\Debug\ 25 | DEBUG;TRACE 26 | prompt 27 | 4 28 | 29 | 30 | AnyCPU 31 | pdbonly 32 | true 33 | bin\Release\ 34 | TRACE 35 | prompt 36 | 4 37 | 38 | 39 | ApplicationIcon.ico 40 | 41 | 42 | 43 | False 44 | ..\packages\Fluent.Ribbon.3.4.0\lib\net45\Fluent.dll 45 | 46 | 47 | ..\packages\Microsoft.ApplicationInsights.2.0.1\lib\net45\Microsoft.ApplicationInsights.dll 48 | True 49 | 50 | 51 | ..\packages\MyToolkit.2.5.16\lib\portable-net45+wp8+win8+wpa81\MyToolkit.dll 52 | True 53 | 54 | 55 | ..\packages\MyToolkit.Extended.2.5.16\lib\net45\MyToolkit.Extended.dll 56 | True 57 | 58 | 59 | ..\packages\Namotion.Reflection.2.0.5\lib\net45\Namotion.Reflection.dll 60 | 61 | 62 | ..\packages\Newtonsoft.Json.13.0.1\lib\net45\Newtonsoft.Json.dll 63 | 64 | 65 | ..\packages\NJsonSchema.10.5.2\lib\net45\NJsonSchema.dll 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | ..\packages\Fluent.Ribbon.3.4.0\lib\net45\System.Windows.Interactivity.dll 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 4.0 86 | 87 | 88 | 89 | 90 | 91 | False 92 | ..\packages\Extended.Wpf.Toolkit.2.4\lib\net40\Xceed.Wpf.AvalonDock.dll 93 | 94 | 95 | False 96 | ..\packages\Extended.Wpf.Toolkit.2.4\lib\net40\Xceed.Wpf.AvalonDock.Themes.Aero.dll 97 | 98 | 99 | False 100 | ..\packages\Extended.Wpf.Toolkit.2.4\lib\net40\Xceed.Wpf.AvalonDock.Themes.Metro.dll 101 | 102 | 103 | False 104 | ..\packages\Extended.Wpf.Toolkit.2.4\lib\net40\Xceed.Wpf.AvalonDock.Themes.VS2010.dll 105 | 106 | 107 | False 108 | ..\packages\Extended.Wpf.Toolkit.2.4\lib\net40\Xceed.Wpf.DataGrid.dll 109 | 110 | 111 | False 112 | ..\packages\Extended.Wpf.Toolkit.2.4\lib\net40\Xceed.Wpf.Toolkit.dll 113 | 114 | 115 | 116 | 117 | MSBuild:Compile 118 | Designer 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | Strings.pl.resx 131 | True 132 | True 133 | 134 | 135 | Strings.fr.resx 136 | True 137 | True 138 | 139 | 140 | 141 | 142 | True 143 | True 144 | Strings.resx 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | AboutWindow.xaml 155 | 156 | 157 | JsonEditor.xaml 158 | 159 | 160 | 161 | 162 | MSBuild:Compile 163 | Designer 164 | 165 | 166 | Designer 167 | MSBuild:Compile 168 | 169 | 170 | MSBuild:Compile 171 | Designer 172 | 173 | 174 | App.xaml 175 | Code 176 | 177 | 178 | MainWindow.xaml 179 | Code 180 | 181 | 182 | Designer 183 | MSBuild:Compile 184 | 185 | 186 | 187 | 188 | Code 189 | 190 | 191 | True 192 | True 193 | Resources.resx 194 | 195 | 196 | True 197 | Settings.settings 198 | True 199 | 200 | 201 | 202 | PublicResXFileCodeGenerator 203 | Strings.pl.Designer.cs 204 | Designer 205 | 206 | 207 | PublicResXFileCodeGenerator 208 | Strings.fr.Designer.cs 209 | Designer 210 | 211 | 212 | PublicResXFileCodeGenerator 213 | Strings.Designer.cs 214 | Designer 215 | 216 | 217 | ResXFileCodeGenerator 218 | Resources.Designer.cs 219 | 220 | 221 | Designer 222 | 223 | 224 | SettingsSingleFileGenerator 225 | Settings.Designer.cs 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | PreserveNewest 247 | 248 | 249 | PreserveNewest 250 | 251 | 252 | PreserveNewest 253 | 254 | 255 | PreserveNewest 256 | 257 | 258 | 259 | 260 | Designer 261 | 262 | 263 | 264 | 265 | 266 | 267 | This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. 268 | 269 | 270 | 271 | 278 | -------------------------------------------------------------------------------- /src/VisualJsonEditor/ViewModels/MainWindowModel.cs: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------- 2 | // 3 | // Copyright (c) Rico Suter. All rights reserved. 4 | // 5 | // http://visualjsoneditor.codeplex.com/license 6 | // Rico Suter, mail@rsuter.com 7 | //----------------------------------------------------------------------- 8 | 9 | using System; 10 | using System.Collections.ObjectModel; 11 | using System.ComponentModel; 12 | using System.Diagnostics; 13 | using System.IO; 14 | using System.Linq; 15 | using System.Threading.Tasks; 16 | using System.Windows; 17 | using MyToolkit.Command; 18 | using MyToolkit.Composition; 19 | using MyToolkit.Data; 20 | using MyToolkit.Dialogs; 21 | using MyToolkit.Messaging; 22 | using MyToolkit.Model; 23 | using MyToolkit.Mvvm; 24 | using VisualJsonEditor.Localization; 25 | using VisualJsonEditor.Messages; 26 | using VisualJsonEditor.Models; 27 | 28 | namespace VisualJsonEditor.ViewModels 29 | { 30 | public class MainWindowModel : ViewModelBase 31 | { 32 | private JsonDocumentModel _selectedDocument; 33 | private ApplicationConfiguration _configuration; 34 | 35 | public MainWindowModel() 36 | { 37 | Documents = new ObservableCollection(); 38 | 39 | CreateDocumentCommand = new AsyncRelayCommand(CreateDocumentAsync); 40 | OpenDocumentCommand = new AsyncRelayCommand(OpenDocumentAsync); 41 | OpenDocumentFromPathCommand = new AsyncRelayCommand(OpenDocumentAsync); 42 | SaveDocumentCommand = new AsyncRelayCommand(SaveDocumentAsync, d => d != null && d.UndoRedoManager.CanUndo); 43 | SaveDocumentAsCommand = new AsyncRelayCommand(SaveDocumentAsAsync, d => d != null); 44 | SaveDocumentSchemaAsCommand = new AsyncRelayCommand(SaveDocumentSchemaAsAsync, d => d != null); 45 | CloseDocumentCommand = new AsyncRelayCommand(CloseDocumentAsync, d => d != null); 46 | ValidateDocumentCommand = new AsyncRelayCommand(ValidateDocumentAsync, d => d != null); 47 | 48 | UndoCommand = new RelayCommand(d => d.UndoRedoManager.Undo(), d => d != null && d.UndoRedoManager.CanUndo); 49 | RedoCommand = new RelayCommand(d => d.UndoRedoManager.Redo(), d => d != null && d.UndoRedoManager.CanRedo); 50 | } 51 | 52 | public Strings Strings 53 | { 54 | get { return new Strings(); } 55 | } 56 | 57 | /// Gets or sets the application configuration. 58 | public ApplicationConfiguration Configuration 59 | { 60 | get { return _configuration; } 61 | set { Set(ref _configuration, value); } 62 | } 63 | 64 | /// Gets the command to open a document from a file path. 65 | public AsyncRelayCommand OpenDocumentFromPathCommand { get; set; } 66 | 67 | /// Gets the command to undo the last action. 68 | public RelayCommand UndoCommand { get; private set; } 69 | 70 | /// Gets the command to redo the last action. 71 | public RelayCommand RedoCommand { get; set; } 72 | 73 | /// Gets the command to close a document. 74 | public AsyncRelayCommand CloseDocumentCommand { get; private set; } 75 | 76 | /// Gets the command to validate a document. 77 | public AsyncRelayCommand ValidateDocumentCommand { get; private set; } 78 | 79 | /// Gets the command to create a new document. 80 | public AsyncRelayCommand CreateDocumentCommand { get; private set; } 81 | 82 | /// Gets the command to save a document. 83 | public AsyncRelayCommand SaveDocumentCommand { get; private set; } 84 | 85 | /// Gets the command to save a copy of a document. 86 | public AsyncRelayCommand SaveDocumentAsCommand { get; private set; } 87 | 88 | /// Gets the command to save a copy of a document schema. 89 | public AsyncRelayCommand SaveDocumentSchemaAsCommand { get; private set; } 90 | 91 | /// Gets the command to open a document with the file open dialog. 92 | public AsyncRelayCommand OpenDocumentCommand { get; private set; } 93 | 94 | /// Gets the list of opened documents. 95 | public ObservableCollection Documents { get; private set; } 96 | 97 | /// Gets or sets the currently selected document. 98 | public JsonDocumentModel SelectedDocument 99 | { 100 | get { return _selectedDocument; } 101 | set 102 | { 103 | if (Set(ref _selectedDocument, value)) 104 | { 105 | ValidateDocumentCommand.RaiseCanExecuteChanged(); 106 | CloseDocumentCommand.RaiseCanExecuteChanged(); 107 | 108 | UndoCommand.RaiseCanExecuteChanged(); 109 | RedoCommand.RaiseCanExecuteChanged(); 110 | 111 | SaveDocumentCommand.RaiseCanExecuteChanged(); 112 | SaveDocumentAsCommand.RaiseCanExecuteChanged(); 113 | SaveDocumentSchemaAsCommand.RaiseCanExecuteChanged(); 114 | } 115 | } 116 | } 117 | 118 | /// Closes the given document and saves it if needed. 119 | /// The document to close. 120 | /// The task. 121 | public async Task CloseDocumentAsync(JsonDocumentModel document) 122 | { 123 | if (document.UndoRedoManager.CanUndo) 124 | { 125 | var message = new TextMessage(string.Format(Strings.MessageSaveDocumentText, document.DisplayTitle), 126 | Strings.MessageSaveDocumentTitle, MessageButton.YesNoCancel); 127 | 128 | var result = await Messenger.Default.SendAsync(message); 129 | if (result.Result == MessageResult.Cancel) 130 | return false; 131 | 132 | if (result.Result == MessageResult.Yes) 133 | await SaveDocumentAsync(document); 134 | } 135 | 136 | RemoveDocument(document); 137 | return true; 138 | } 139 | 140 | /// Creates a new document from a given JSON schema. 141 | /// The path of the JSON schema file. 142 | /// The task. 143 | public async Task CreateDocumentAsync(string schemaPath) 144 | { 145 | await RunTaskAsync(async token => 146 | { 147 | var document = await JsonDocumentModel.CreateAsync(schemaPath, ServiceLocator.Default.Resolve()); 148 | AddDocument(document); 149 | }); 150 | } 151 | 152 | /// Opens a document with the file open dialog. 153 | /// The task. 154 | public async Task OpenDocumentAsync() 155 | { 156 | var result = await Messenger.Default.SendAsync(new OpenJsonDocumentMessage(Strings.OpenJsonDocumentDialog)); 157 | if (result.Success) 158 | await OpenDocumentAsync(result.Result); 159 | } 160 | 161 | /// Opens a document from a given file name. 162 | /// The file name. 163 | /// The task. 164 | public async Task OpenDocumentAsync(string fileName) 165 | { 166 | var isReadOnly = await RunTaskAsync(() => File.GetAttributes(fileName).HasFlag(FileAttributes.ReadOnly)); 167 | await OpenDocumentAsync(fileName, isReadOnly); 168 | } 169 | 170 | /// Opens a document from a given file name. 171 | /// The file name. 172 | /// The value indicating whether the document can be changed. 173 | /// The task. 174 | public async Task OpenDocumentAsync(string fileName, bool isReadOnly) 175 | { 176 | var existingDocument = Documents.SingleOrDefault(d => d.FilePath == fileName); 177 | if (existingDocument != null) 178 | SelectedDocument = existingDocument; 179 | else 180 | { 181 | await RunTaskAsync(async token => 182 | { 183 | JsonDocumentModel document = null; 184 | 185 | // First try to load the schema from the default location 186 | var defaultSchemaPath = JsonDocumentModel.GetDefaultSchemaPath(fileName); 187 | if (File.Exists(defaultSchemaPath)) 188 | document = await JsonDocumentModel.LoadAsync(fileName, defaultSchemaPath, ServiceLocator.Default.Resolve()); 189 | 190 | // If no schema was found, check for a "_schema" property on the document 191 | if (document == null) 192 | { 193 | var schemaPropertyPath = JsonObjectModel.GetSchemaProperty(fileName); 194 | if (!String.IsNullOrWhiteSpace(schemaPropertyPath) && File.Exists(schemaPropertyPath)) 195 | document = await JsonDocumentModel.LoadAsync(fileName, schemaPropertyPath, ServiceLocator.Default.Resolve()); 196 | } 197 | 198 | // If no default schema or no schema property, prompt. 199 | if(document == null) 200 | { 201 | var result = await Messenger.Default.SendAsync(new OpenJsonDocumentMessage(Strings.OpenJsonSchemaDocumentDialog)); 202 | if (!result.Success) 203 | return; 204 | 205 | document = await JsonDocumentModel.LoadAsync(fileName, result.Result, ServiceLocator.Default.Resolve()); 206 | } 207 | 208 | document.IsReadOnly = isReadOnly; 209 | 210 | AddDocument(document); 211 | AddRecentFile(fileName); 212 | }); 213 | } 214 | } 215 | 216 | /// Handles an exception which occured in the method. 217 | /// The exception. 218 | public override void HandleException(Exception exception) 219 | { 220 | ExceptionBox.Show(Strings.MessageErrorTitle, exception, Application.Current.MainWindow); 221 | } 222 | 223 | private async Task CreateDocumentAsync() 224 | { 225 | var result = await Messenger.Default.SendAsync(new OpenJsonDocumentMessage(Strings.OpenJsonSchemaDocumentDialog)); 226 | if (result.Success) 227 | await CreateDocumentAsync(result.Result); 228 | } 229 | 230 | private void AddDocument(JsonDocumentModel document) 231 | { 232 | Documents.Add(document); 233 | SelectedDocument = document; 234 | 235 | document.UndoRedoManager.PropertyChanged += UndoRedoManagerOnPropertyChanged; 236 | } 237 | 238 | private void RemoveDocument(JsonDocumentModel document) 239 | { 240 | Documents.Remove(document); 241 | 242 | document.UndoRedoManager.PropertyChanged -= UndoRedoManagerOnPropertyChanged; 243 | } 244 | 245 | private async Task ValidateDocumentAsync(JsonDocumentModel document) 246 | { 247 | var errors = await document.Data.ValidateAsync(); 248 | if (errors.Length == 0) 249 | { 250 | await Messenger.Default.SendAsync( 251 | new TextMessage(string.Format(Strings.MessageValidDocumentText, document.DisplayTitle), 252 | Strings.MessageValidDocumentTitle)); 253 | } 254 | else 255 | { 256 | await Messenger.Default.SendAsync( 257 | new TextMessage( 258 | string.Format(Strings.MessageNotValidDocumentText, document.DisplayTitle, errors), 259 | Strings.MessageNotValidDocumentTitle)); 260 | } 261 | } 262 | 263 | private void UndoRedoManagerOnPropertyChanged(object sender, PropertyChangedEventArgs args) 264 | { 265 | if (args.IsProperty(i => i.CanUndo)) 266 | { 267 | UndoCommand.RaiseCanExecuteChanged(); 268 | 269 | SaveDocumentCommand.RaiseCanExecuteChanged(); 270 | SaveDocumentAsCommand.RaiseCanExecuteChanged(); 271 | } 272 | 273 | if (args.IsProperty(i => i.CanRedo)) 274 | RedoCommand.RaiseCanExecuteChanged(); 275 | } 276 | 277 | private void AddRecentFile(string fileName) 278 | { 279 | foreach (var entry in Configuration.RecentFiles.Where(f => f.FilePath == fileName).ToArray()) 280 | Configuration.RecentFiles.Remove(entry); 281 | 282 | Configuration.RecentFiles.Insert(0, new RecentFile { FilePath = fileName }); 283 | 284 | if (Configuration.RecentFiles.Count > 10) 285 | Configuration.RecentFiles.Remove(Configuration.RecentFiles.Last()); 286 | } 287 | 288 | private Task SaveDocumentAsync(JsonDocumentModel document) 289 | { 290 | return SaveDocumentAsync(document, false); 291 | } 292 | 293 | private Task SaveDocumentAsAsync(JsonDocumentModel document) 294 | { 295 | return SaveDocumentAsync(document, true); 296 | } 297 | 298 | private async Task SaveDocumentAsync(JsonDocumentModel document, bool saveAs) 299 | { 300 | if (!document.HasFileLocation || saveAs) 301 | { 302 | var fileName = document.HasFileLocation ? 303 | Path.GetFileNameWithoutExtension(document.FilePath) + ".json" : 304 | Strings.DefaultFileName + ".json"; 305 | 306 | var result = await Messenger.Default.SendAsync(new SaveJsonDocumentMessage(fileName)); 307 | if (result.Success) 308 | { 309 | AddRecentFile(result.Result); 310 | document.FilePath = result.Result; 311 | } 312 | else 313 | return; 314 | } 315 | 316 | await RunTaskAsync(async token => 317 | { 318 | await document.SaveAsync(saveAs); 319 | }); 320 | } 321 | 322 | private async Task SaveDocumentSchemaAsAsync(JsonDocumentModel document) 323 | { 324 | var fileName = Path.GetFileNameWithoutExtension(document.FilePath) + ".schema.json"; 325 | var result = await Messenger.Default.SendAsync(new SaveJsonDocumentMessage(fileName)); 326 | if (result.Success) 327 | { 328 | await RunTaskAsync(async token => 329 | { 330 | await Task.Run(() => File.WriteAllText(result.Result, document.Data.Schema.ToJson()), token); 331 | }); 332 | } 333 | } 334 | } 335 | } 336 | -------------------------------------------------------------------------------- /src/VisualJsonEditor/Controls/JsonEditor.xaml: -------------------------------------------------------------------------------- 1 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 45 | 47 | 48 | 49 | 50 | 51 | 52 | 54 | 56 | 57 | 58 | 59 | 60 | 61 | 63 | 66 | 67 | 68 | 69 | 70 | 71 | 73 | 75 | 77 | 78 | 79 | 80 | 81 | 82 | 84 | 88 | 90 | 91 | 92 | 93 | 94 | 95 | 97 | 101 | 103 | 104 | 105 | 106 | 107 | 108 | 110 | 112 | 113 | 114 | 115 | 116 | 117 | 119 | 120 | 121 | 122 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 138 | 139 | 141 | 142 | 143 | 144 | 145 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | () 182 | 183 | 184 | 185 | 186 | 187 | 188 |