├── MechaView ├── version ├── MechaView.MahApps │ ├── content │ │ └── app.ico │ ├── tools │ │ ├── MechaView.psd1 │ │ ├── uninstall.ps1 │ │ ├── init.ps1 │ │ ├── install.ps1 │ │ ├── Mecha.Wpf.Ma.App │ │ │ ├── packages.config │ │ │ ├── MainWindow.xaml.cs │ │ │ ├── App.xaml.cs │ │ │ ├── MainWindow.xaml │ │ │ ├── App.xaml │ │ │ └── Properties │ │ │ │ └── AssemblyInfo.cs │ │ └── MechaView.psm1 │ └── MechaView.MahApps.nuspec ├── Mecha.Core │ ├── packages.config │ ├── ViewModel │ │ ├── IAction.cs │ │ ├── IMessage.cs │ │ ├── MessageDialog.cs │ │ ├── IProgress.cs │ │ ├── Validation.cs │ │ └── InpcInterceptor.cs │ ├── Exceptions │ │ └── ControlNotFoundException.cs │ ├── ViewModel.Elements │ │ ├── Button.cs │ │ ├── CheckBox.cs │ │ ├── TextView.cs │ │ ├── TextInput.cs │ │ ├── DateInput.cs │ │ ├── EnumInput.cs │ │ ├── SlideInput.cs │ │ ├── RangeSlider.cs │ │ ├── PasswordInput.cs │ │ ├── TableView.cs │ │ ├── PathInput.cs │ │ ├── ActionElement.cs │ │ ├── StateElement.cs │ │ ├── Container.cs │ │ └── Element.cs │ ├── ViewModel.Attributes │ │ ├── Action.cs │ │ ├── DateInput.cs │ │ ├── Password.cs │ │ ├── Readonly.cs │ │ ├── Range.cs │ │ ├── TextInput.cs │ │ ├── State.cs │ │ ├── Path.cs │ │ ├── Group.cs │ │ ├── Message.cs │ │ ├── Progress.cs │ │ ├── Element.cs │ │ └── Confirm.cs │ ├── Mecha.Core.nuspec │ ├── Helpers │ │ └── Utils.cs │ ├── Properties │ │ └── AssemblyInfo.cs │ └── Mecha.Core.csproj ├── Mecha.Core.Wpf │ ├── App.config │ ├── Properties │ │ ├── Settings.settings │ │ ├── Settings.Designer.cs │ │ ├── AssemblyInfo.cs │ │ ├── Resources.Designer.cs │ │ └── Resources.resx │ └── View │ │ └── Wpf │ │ ├── Controls │ │ ├── ILabeled.cs │ │ ├── RowGrid.xaml │ │ ├── ActionPanel.xaml │ │ ├── GroupPanel.xaml │ │ ├── MainPanel.xaml │ │ ├── TablePanel.xaml │ │ ├── ActionPanel.xaml.cs │ │ ├── GroupPanel.xaml.cs │ │ ├── TablePanel.xaml.cs │ │ ├── TextView.xaml │ │ ├── TextInput.xaml │ │ ├── PasswordInput.xaml │ │ ├── EnumInput.xaml │ │ ├── DateInput.xaml │ │ ├── PathInput.xaml │ │ ├── MandatoryInputRule.cs │ │ ├── RowGrid.xaml.cs │ │ ├── TextView.xaml.cs │ │ ├── MainPanel.xaml.cs │ │ ├── DateInput.xaml.cs │ │ ├── TextInput.xaml.cs │ │ ├── EnumInput.xaml.cs │ │ └── PasswordInput.xaml.cs │ │ ├── ButtonHandle.cs │ │ ├── Converters │ │ ├── IntToVisibilityConverter.cs │ │ └── CollectionToVisibilityConverter.cs │ │ ├── Helpers │ │ └── Utils.cs │ │ ├── Dialogs.cs │ │ ├── MergedStylesExtension.cs │ │ └── Styles.xaml ├── Mecha.Wpf.Ma.Dev │ ├── App.config │ ├── packages.config │ ├── Properties │ │ ├── Settings.settings │ │ ├── Settings.Designer.cs │ │ ├── AssemblyInfo.cs │ │ ├── Resources.Designer.cs │ │ └── Resources.resx │ ├── MainWindow.xaml.cs │ ├── App.xaml.cs │ ├── MainWindow.xaml │ ├── App.xaml │ ├── Mecha.Wpf.Ma.Dev.csproj │ └── DevApp.cs ├── Mecha.Wpf.Ma │ ├── packages.config │ ├── ProgressDialog.cs │ ├── Properties │ │ └── AssemblyInfo.cs │ ├── AppHandler.cs │ ├── Mecha.Wpf.Ma.csproj │ ├── WindowHandler.cs │ └── Resources.xaml ├── Mecha.Wpf.Settings │ ├── IApp.cs │ ├── ColorMode.cs │ ├── AppSettings.cs │ ├── WindowSettings.cs │ ├── Accent.cs │ ├── Properties │ │ └── AssemblyInfo.cs │ └── Mecha.Wpf.Settings.csproj ├── SettingManager │ ├── SettingManager │ │ ├── SettingManager.projitems │ │ ├── SettingManagerShared.shproj │ │ └── SettingManager.cs │ └── SettingManager.sln ├── publish.ps1 └── MechaView.sln ├── docs ├── basics-dark.png ├── basics-light.png ├── dial-err-light.png ├── dial-msg-light.png ├── grouping-light.png ├── conventions-dark.png ├── conventions-light.png ├── decoration-light.png ├── validation-light.png ├── dial-confirm-light.png └── dial-dynprog-light.png ├── Samples ├── Samples │ ├── app.ico │ ├── packages.config │ ├── InputValidation.cs │ ├── App.cs │ ├── ElementDecoration.cs │ ├── ActionDialogs.cs │ ├── Properties │ │ └── AssemblyInfo.cs │ ├── ElementConventions.cs │ ├── ElementGrouping.cs │ └── Samples.csproj └── Samples.sln ├── LICENSE ├── .gitattributes ├── .gitignore └── README.md /MechaView/version: -------------------------------------------------------------------------------- 1 | 0.0.152 2 | -------------------------------------------------------------------------------- /docs/basics-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marktoman/mechaview/HEAD/docs/basics-dark.png -------------------------------------------------------------------------------- /docs/basics-light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marktoman/mechaview/HEAD/docs/basics-light.png -------------------------------------------------------------------------------- /Samples/Samples/app.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marktoman/mechaview/HEAD/Samples/Samples/app.ico -------------------------------------------------------------------------------- /docs/dial-err-light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marktoman/mechaview/HEAD/docs/dial-err-light.png -------------------------------------------------------------------------------- /docs/dial-msg-light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marktoman/mechaview/HEAD/docs/dial-msg-light.png -------------------------------------------------------------------------------- /docs/grouping-light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marktoman/mechaview/HEAD/docs/grouping-light.png -------------------------------------------------------------------------------- /docs/conventions-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marktoman/mechaview/HEAD/docs/conventions-dark.png -------------------------------------------------------------------------------- /docs/conventions-light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marktoman/mechaview/HEAD/docs/conventions-light.png -------------------------------------------------------------------------------- /docs/decoration-light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marktoman/mechaview/HEAD/docs/decoration-light.png -------------------------------------------------------------------------------- /docs/validation-light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marktoman/mechaview/HEAD/docs/validation-light.png -------------------------------------------------------------------------------- /docs/dial-confirm-light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marktoman/mechaview/HEAD/docs/dial-confirm-light.png -------------------------------------------------------------------------------- /docs/dial-dynprog-light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marktoman/mechaview/HEAD/docs/dial-dynprog-light.png -------------------------------------------------------------------------------- /MechaView/MechaView.MahApps/content/app.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marktoman/mechaview/HEAD/MechaView/MechaView.MahApps/content/app.ico -------------------------------------------------------------------------------- /MechaView/MechaView.MahApps/tools/MechaView.psd1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marktoman/mechaview/HEAD/MechaView/MechaView.MahApps/tools/MechaView.psd1 -------------------------------------------------------------------------------- /MechaView/MechaView.MahApps/tools/uninstall.ps1: -------------------------------------------------------------------------------- 1 | param($installPath, $toolsPath, $package, $project) 2 | 3 | remove-module $package.id -ErrorAction SilentlyContinue -------------------------------------------------------------------------------- /MechaView/Mecha.Core/packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /Samples/Samples/packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /MechaView/MechaView.MahApps/tools/init.ps1: -------------------------------------------------------------------------------- 1 | param($installPath, $toolsPath, $package) 2 | 3 | #import-module (join-path $toolsPath "$($package.id).psm1") 4 | import-module (join-path $toolsPath "MechaView.psm1") 5 | 6 | -------------------------------------------------------------------------------- /MechaView/Mecha.Core.Wpf/App.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /MechaView/Mecha.Wpf.Ma.Dev/App.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /MechaView/Mecha.Wpf.Ma/packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /MechaView/Mecha.Wpf.Ma.Dev/packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /MechaView/Mecha.Core.Wpf/Properties/Settings.settings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /MechaView/Mecha.Wpf.Ma.Dev/Properties/Settings.settings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /MechaView/Mecha.Wpf.Settings/IApp.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Mecha.Wpf.Settings 8 | { 9 | public interface IApp 10 | { 11 | void Init(AppSettings s); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /MechaView/Mecha.Core/ViewModel/IAction.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Mecha.ViewModel 8 | { 9 | public interface IMechaAction 10 | { 11 | string Label { get; set; } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /MechaView/Mecha.Wpf.Settings/ColorMode.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Mecha.Wpf.Settings 8 | { 9 | public enum ColorMode 10 | { 11 | Auto, 12 | Light, 13 | Dark 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /MechaView/Mecha.Core.Wpf/View/Wpf/Controls/ILabeled.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Mecha.View.Wpf.Controls 8 | { 9 | public interface ILabeled 10 | { 11 | double LabelWidth { get; set; } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /MechaView/Mecha.Core/Exceptions/ControlNotFoundException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace Mecha.Exceptions 6 | { 7 | public class ControlNotFoundException : Exception 8 | { 9 | public ControlNotFoundException(string message) : base(message) { } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /MechaView/Mecha.Core/ViewModel/IMessage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Mecha.ViewModel 8 | { 9 | public interface IMechaMessage 10 | { 11 | string Title { get; set; } 12 | string Message { get; set; } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /MechaView/Mecha.Core/ViewModel.Elements/Button.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Reflection; 4 | using System.Text; 5 | 6 | namespace Mecha.ViewModel.Elements 7 | { 8 | internal class Button : ActionElement 9 | { 10 | public Button(Container parent, MethodInfo method, string name) : base(parent, method, name) { } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /MechaView/Mecha.Core/ViewModel.Elements/CheckBox.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Reflection; 4 | using System.Text; 5 | 6 | namespace Mecha.ViewModel.Elements 7 | { 8 | internal class CheckBox : StateElement 9 | { 10 | public CheckBox(Container parent, PropertyInfo property, string name) : base(parent, property, name) { } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /MechaView/Mecha.Core/ViewModel.Elements/TextView.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Reflection; 4 | using System.Text; 5 | 6 | namespace Mecha.ViewModel.Elements 7 | { 8 | internal class TextView : StateElement 9 | { 10 | public TextView(Container parent, PropertyInfo property, string name) : base(parent, property, name) { } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /MechaView/Mecha.Core/ViewModel/MessageDialog.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Mecha.ViewModel 8 | { 9 | public class MessageDialog : IMechaMessage 10 | { 11 | public string Message { get; set; } 12 | public string Title { get; set; } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /MechaView/MechaView.MahApps/tools/install.ps1: -------------------------------------------------------------------------------- 1 | param($installPath, $toolsPath, $package, $project) 2 | 3 | $project.object.references| 4 | Where-Object Name -in ` 5 | 'Mecha.Core.Wpf', 6 | 'Mecha.Wpf.Ma', 7 | 'MahApps.Metro', 8 | 'System.Windows.Interactivity', 9 | 'ControlzEx', 10 | 'Castle.Core' | 11 | ForEach-Object Remove 12 | 13 | $project.save() 14 | -------------------------------------------------------------------------------- /MechaView/Mecha.Core/ViewModel.Attributes/Action.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace Mecha.ViewModel.Attributes 6 | { 7 | [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] 8 | public class ActionAttribute : Attribute 9 | { 10 | public ActionAttribute() { } 11 | public bool DisableValidation { get; set; } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /MechaView/Mecha.Wpf.Settings/AppSettings.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Mecha.Wpf.Settings 8 | { 9 | public class AppSettings 10 | { 11 | public WindowSettings Window { get; set; } 12 | public string Title { get; set; } 13 | public Type Content { get; set; } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /MechaView/Mecha.Core/ViewModel.Elements/TextInput.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Reflection; 4 | using System.Text; 5 | using Mecha.ViewModel.Attributes; 6 | 7 | namespace Mecha.ViewModel.Elements 8 | { 9 | internal class TextInput : StateElement 10 | { 11 | public TextInput(Container parent, PropertyInfo property, string name) : base(parent, property, name) { } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /MechaView/Mecha.Core/ViewModel.Attributes/DateInput.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Mecha.ViewModel.Attributes 8 | { 9 | public class DateInputAttribute : StateAttribute 10 | { 11 | public DateInputAttribute() { } 12 | public DateInputAttribute(string displayName) : base(displayName) { } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /MechaView/Mecha.Core/ViewModel.Attributes/Password.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Mecha.ViewModel.Attributes 8 | { 9 | public class PasswordAttribute : StateAttribute 10 | { 11 | public PasswordAttribute() : base() { } 12 | public PasswordAttribute(string displayName) : base(displayName) { } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /MechaView/Mecha.Core/ViewModel.Attributes/Readonly.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Mecha.ViewModel.Attributes 8 | { 9 | public class ReadonlyAttribute : StateAttribute 10 | { 11 | public ReadonlyAttribute() : base() { } 12 | public ReadonlyAttribute(string displayName) : base(displayName) { } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /MechaView/Mecha.Core/ViewModel.Elements/DateInput.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Reflection; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace Mecha.ViewModel.Elements 9 | { 10 | internal class DateInput : StateElement 11 | { 12 | public DateInput(Container parent, PropertyInfo property, string name) : base(parent, property, name) { } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /MechaView/Mecha.Core/ViewModel.Attributes/Range.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace Mecha.ViewModel.Attributes 6 | { 7 | public class RangeAttribute : StateAttribute 8 | { 9 | public RangeAttribute() { } 10 | public RangeAttribute(string displayName) : base(displayName) { } 11 | 12 | public double Min { get; set; } 13 | public double Max { get; set; } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /MechaView/Mecha.Wpf.Settings/WindowSettings.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Mecha.Wpf.Settings 8 | { 9 | public class WindowSettings 10 | { 11 | public ColorMode ColorMode { get; set; } 12 | public Accent Accent { get; set; } 13 | public int Width { get; set; } 14 | public int Height { get; set; } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /MechaView/Mecha.Core/Mecha.Core.nuspec: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | $id$ 5 | $version$ 6 | $title$ 7 | $author$ 8 | $author$ 9 | false 10 | $description$ 11 | Init. 12 | Copyright 2015 13 | 14 | -------------------------------------------------------------------------------- /MechaView/Mecha.Core/ViewModel.Elements/EnumInput.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Reflection; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using Mecha.Helpers; 8 | 9 | namespace Mecha.ViewModel.Elements 10 | { 11 | internal class EnumInput : StateElement 12 | { 13 | public EnumInput(Container parent, PropertyInfo property, string name) : base(parent, property, name) { } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /MechaView/Mecha.Wpf.Ma.Dev/MainWindow.xaml.cs: -------------------------------------------------------------------------------- 1 | using MahApps.Metro.Controls; 2 | using System.Windows; 3 | 4 | namespace Mecha.Wpf.Ma.Dev 5 | { 6 | public partial class MainWindow : MetroWindow 7 | { 8 | readonly WindowHandler handler; 9 | 10 | public MainWindow() 11 | { 12 | InitializeComponent(); 13 | 14 | var wpfApp = (App)Application.Current; 15 | handler = new WindowHandler(this, wpfApp.Settings); 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /MechaView/Mecha.Core/ViewModel.Attributes/TextInput.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Mecha.ViewModel.Attributes 8 | { 9 | public class TextInputAttribute : StateAttribute 10 | { 11 | public TextInputAttribute() : base() { } 12 | public TextInputAttribute(string displayName) : base(displayName) { } 13 | 14 | public bool Multiline { get; set; } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /MechaView/MechaView.MahApps/tools/Mecha.Wpf.Ma.App/packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /MechaView/MechaView.MahApps/tools/Mecha.Wpf.Ma.App/MainWindow.xaml.cs: -------------------------------------------------------------------------------- 1 | using MahApps.Metro.Controls; 2 | using System.Windows; 3 | 4 | namespace Mecha.Wpf.Ma.App 5 | { 6 | public partial class MainWindow : MetroWindow 7 | { 8 | readonly WindowHandler handler; 9 | 10 | public MainWindow() 11 | { 12 | InitializeComponent(); 13 | 14 | var wpfApp = (App)Application.Current; 15 | handler = new WindowHandler(this, wpfApp.Settings); 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /MechaView/Mecha.Wpf.Ma.Dev/App.xaml.cs: -------------------------------------------------------------------------------- 1 | using Mecha.Wpf.Settings; 2 | using System.Windows; 3 | 4 | namespace Mecha.Wpf.Ma.Dev 5 | { 6 | /// 7 | /// Interaction logic for App.xaml 8 | /// 9 | public partial class App : Application 10 | { 11 | readonly AppHandler handler; 12 | public AppSettings Settings => handler.Settings; 13 | 14 | public App() 15 | { 16 | IApp app = new global::MechaApp(); 17 | handler = new AppHandler(app, this); 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Samples/Samples/InputValidation.cs: -------------------------------------------------------------------------------- 1 | using Mecha.ViewModel.Attributes; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace SampleApp 9 | { 10 | public class InputValidation 11 | { 12 | [TextInput(Mandatory = true, Description = "User name")] 13 | public virtual string User { get; set; } 14 | 15 | public void BoundAction() { } 16 | 17 | [Action(DisableValidation = true)] 18 | public void UnboundAction() { } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /MechaView/MechaView.MahApps/tools/Mecha.Wpf.Ma.App/App.xaml.cs: -------------------------------------------------------------------------------- 1 | using Mecha.Wpf.Settings; 2 | using System.Windows; 3 | 4 | namespace Mecha.Wpf.Ma.App 5 | { 6 | /// 7 | /// Interaction logic for App.xaml 8 | /// 9 | public partial class App : Application 10 | { 11 | readonly AppHandler handler; 12 | public AppSettings Settings => handler.Settings; 13 | 14 | public App() 15 | { 16 | IApp app = new global::App(); 17 | handler = new AppHandler(app, this); 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /MechaView/MechaView.MahApps/tools/Mecha.Wpf.Ma.App/MainWindow.xaml: -------------------------------------------------------------------------------- 1 | 8 | -------------------------------------------------------------------------------- /MechaView/Mecha.Core/ViewModel.Attributes/State.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Mecha.ViewModel.Attributes 8 | { 9 | public class StateAttribute : ElementAttribute 10 | { 11 | public StateAttribute() { } 12 | public StateAttribute(string displayName) : base(displayName) { } 13 | 14 | public bool Mandatory { get; set; } 15 | public bool Persistent { get; set; } 16 | public double Height { get; set; } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /MechaView/Mecha.Core/ViewModel.Elements/SlideInput.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using System.Reflection; 5 | 6 | namespace Mecha.ViewModel.Elements 7 | { 8 | internal class SlideInput : StateElement 9 | { 10 | public SlideInput(double min, double max, Container parent, PropertyInfo property, string name) : base(parent, property, name) 11 | { 12 | Min = min; 13 | Max = max; 14 | } 15 | 16 | public double Min { get; } 17 | public double Max { get; } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /MechaView/Mecha.Core.Wpf/View/Wpf/Controls/RowGrid.xaml: -------------------------------------------------------------------------------- 1 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /MechaView/Mecha.Core.Wpf/View/Wpf/Controls/ActionPanel.xaml: -------------------------------------------------------------------------------- 1 | 9 | 10 | -------------------------------------------------------------------------------- /MechaView/Mecha.Core.Wpf/View/Wpf/Controls/GroupPanel.xaml: -------------------------------------------------------------------------------- 1 | 9 | 10 | -------------------------------------------------------------------------------- /MechaView/Mecha.Core/ViewModel/IProgress.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Mecha.ViewModel 8 | { 9 | public interface IMechaProgress 10 | { 11 | string Message { get; set; } 12 | string Title { get; set; } 13 | double Progress { get; set; } 14 | bool IsIndeterminate { get; set; } 15 | bool IsCancelable { get; set; } 16 | bool IsCanceled { get; } 17 | 18 | bool IsOpen { get; } 19 | 20 | Task CloseAsync(); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /MechaView/Mecha.Wpf.Ma.Dev/MainWindow.xaml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /MechaView/Mecha.Core.Wpf/View/Wpf/Controls/MainPanel.xaml: -------------------------------------------------------------------------------- 1 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /MechaView/Mecha.Core/ViewModel.Elements/RangeSlider.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using Mecha.ViewModel.Attributes; 3 | 4 | namespace Mecha.ViewModel.Elements 5 | { 6 | internal class RangeSlider : SlideInput 7 | { 8 | public RangeSlider(double min, double max, Container parent, PropertyInfo property, string name) : base(min, max, parent, property, name) 9 | { 10 | 11 | } 12 | 13 | public RangeAttribute RangeAttribute 14 | { 15 | get { return base.StateAttribute as RangeAttribute; } 16 | set { base.StateAttribute = value; } 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /MechaView/Mecha.Core.Wpf/View/Wpf/ButtonHandle.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Mecha.ViewModel; 3 | using Mecha.ViewModel.Elements; 4 | 5 | namespace Mecha.View.Wpf 6 | { 7 | internal class ButtonHandle : IMechaAction 8 | { 9 | readonly Button button; 10 | public ButtonHandle(Button button) 11 | { 12 | if (button == null) 13 | throw new ArgumentNullException(); 14 | 15 | this.button = button; 16 | } 17 | 18 | public string Label 19 | { 20 | get { return button.DisplayName; } 21 | set { button.DisplayName = value; } 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /Samples/Samples/App.cs: -------------------------------------------------------------------------------- 1 | using Mecha.Wpf.Settings; 2 | using System; 3 | 4 | public class App : IApp 5 | { 6 | public void Init(AppSettings s) 7 | { 8 | s.Title = "Element Grouping"; 9 | s.Window.Width = 450; 10 | 11 | s.Content = typeof(SampleApp.ElementGrouping); 12 | //s.Content = typeof(SampleApp.ElementConventions); 13 | //s.Content = typeof(SampleApp.ElementDecoration); 14 | //s.Content = typeof(SampleApp.InputValidation); 15 | //s.Content = typeof(SampleApp.ActionDialogs); 16 | 17 | s.Window.Accent = Accent.Cobalt; 18 | s.Window.ColorMode = ColorMode.Light; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /MechaView/Mecha.Core.Wpf/View/Wpf/Controls/TablePanel.xaml: -------------------------------------------------------------------------------- 1 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /MechaView/SettingManager/SettingManager/SettingManager.projitems: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | $(MSBuildAllProjects);$(MSBuildThisFileFullPath) 5 | true 6 | 423ab3e4-56e8-4228-93c4-fa169ce18ad9 7 | 8 | 9 | SettingManagement 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /MechaView/Mecha.Core/ViewModel.Elements/PasswordInput.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Reflection; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using Mecha.ViewModel.Attributes; 8 | 9 | namespace Mecha.ViewModel.Elements 10 | { 11 | internal class PasswordInput : StateElement 12 | { 13 | public PasswordInput(Container parent, PropertyInfo property, string name) : base(parent, property, name) { } 14 | 15 | public PasswordAttribute PasswordAttribute 16 | { 17 | get { return base.Attribute as PasswordAttribute; } 18 | set { base.Attribute = value; } 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /MechaView/Mecha.Core/ViewModel.Elements/TableView.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Reflection; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace Mecha.ViewModel.Elements 9 | { 10 | internal class TableView : StateElement 11 | { 12 | public TableView(Type itemType, Container parent, PropertyInfo property, string name) 13 | : base(parent, property, name) 14 | { 15 | if (itemType == null) 16 | throw new ArgumentNullException(nameof(itemType)); 17 | 18 | ItemType = itemType; 19 | } 20 | 21 | public Type ItemType { get; } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /MechaView/SettingManager/SettingManager.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 14 4 | VisualStudioVersion = 14.0.23107.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "SettingManagerShared", "SettingManager\SettingManagerShared.shproj", "{423AB3E4-56E8-4228-93C4-FA169CE18AD9}" 7 | EndProject 8 | Global 9 | GlobalSection(SharedMSBuildProjectFiles) = preSolution 10 | SettingManager\SettingManager.projitems*{423ab3e4-56e8-4228-93c4-fa169ce18ad9}*SharedItemsImports = 13 11 | EndGlobalSection 12 | GlobalSection(SolutionProperties) = preSolution 13 | HideSolutionNode = FALSE 14 | EndGlobalSection 15 | EndGlobal 16 | -------------------------------------------------------------------------------- /MechaView/Mecha.Wpf.Ma.Dev/App.xaml: -------------------------------------------------------------------------------- 1 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /MechaView/Mecha.Wpf.Settings/Accent.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Mecha.Wpf.Settings 8 | { 9 | public enum Accent 10 | { 11 | Blue, 12 | Red, 13 | Green, 14 | Purple, 15 | Orange, 16 | Lime, 17 | Emerald, 18 | Teal, 19 | Cyan, 20 | Cobalt, 21 | Indigo, 22 | Violet, 23 | Pink, 24 | Magenta, 25 | Crimson, 26 | Amber, 27 | Yellow, 28 | Brown, 29 | Olive, 30 | Steel, 31 | Mauve, 32 | Taupe, 33 | Sienna 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /MechaView/MechaView.MahApps/tools/Mecha.Wpf.Ma.App/App.xaml: -------------------------------------------------------------------------------- 1 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /MechaView/MechaView.MahApps/MechaView.MahApps.nuspec: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | MechaView.MahApps 5 | $version$ 6 | MechaView.MahApps 7 | Marek Toman 8 | Marek Toman 9 | false 10 | Automatic WPF UI for single purpose tools 11 | 12 | 13 | Copyright 2019 14 | wpf ui generator mahapps 15 | en-US 16 | MIT 17 | https://github.com/marektoman/mechaview 18 | 19 | -------------------------------------------------------------------------------- /MechaView/Mecha.Core/ViewModel.Elements/PathInput.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Reflection; 4 | using System.Text; 5 | using Mecha.ViewModel.Attributes; 6 | 7 | namespace Mecha.ViewModel.Elements 8 | { 9 | internal class PathInput : TextInput 10 | { 11 | public PathInput(Container parent, PropertyInfo property, string name, PathType pathType) : base(parent, property, name) 12 | { 13 | PathType = pathType; 14 | } 15 | 16 | public PathAttribute PathAttribute 17 | { 18 | get { return base.StateAttribute as PathAttribute; } 19 | set { base.StateAttribute = value; } 20 | } 21 | 22 | public PathType PathType { get; } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /MechaView/Mecha.Core.Wpf/View/Wpf/Controls/ActionPanel.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.Windows; 7 | using System.Windows.Controls; 8 | using System.Windows.Data; 9 | using System.Windows.Documents; 10 | using System.Windows.Input; 11 | using System.Windows.Media; 12 | using System.Windows.Media.Imaging; 13 | using System.Windows.Navigation; 14 | using System.Windows.Shapes; 15 | 16 | namespace Mecha.View.Wpf.Controls 17 | { 18 | /// 19 | /// Interaction logic for ActionPanel.xaml 20 | /// 21 | public partial class ActionPanel : WrapPanel 22 | { 23 | public ActionPanel() 24 | { 25 | InitializeComponent(); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /MechaView/Mecha.Core.Wpf/View/Wpf/Controls/GroupPanel.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.Windows; 7 | using System.Windows.Controls; 8 | using System.Windows.Data; 9 | using System.Windows.Documents; 10 | using System.Windows.Input; 11 | using System.Windows.Media; 12 | using System.Windows.Media.Imaging; 13 | using System.Windows.Navigation; 14 | using System.Windows.Shapes; 15 | 16 | namespace Mecha.View.Wpf.Controls 17 | { 18 | /// 19 | /// Interaction logic for GroupPanel.xaml 20 | /// 21 | public partial class GroupPanel : StackPanel 22 | { 23 | public GroupPanel() 24 | { 25 | InitializeComponent(); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /MechaView/Mecha.Core.Wpf/View/Wpf/Controls/TablePanel.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.Windows; 7 | using System.Windows.Controls; 8 | using System.Windows.Data; 9 | using System.Windows.Documents; 10 | using System.Windows.Input; 11 | using System.Windows.Media; 12 | using System.Windows.Media.Imaging; 13 | using System.Windows.Navigation; 14 | using System.Windows.Shapes; 15 | 16 | namespace Mecha.View.Wpf.Controls 17 | { 18 | /// 19 | /// Interaction logic for TablePanel.xaml 20 | /// 21 | public partial class TablePanel : UserControl 22 | { 23 | public TablePanel() 24 | { 25 | InitializeComponent(); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /MechaView/Mecha.Core/ViewModel.Attributes/Path.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace Mecha.ViewModel.Attributes 6 | { 7 | public enum PathType { Auto, Open, Save, Folder } 8 | 9 | [AttributeUsage(AttributeTargets.Property)] 10 | public class PathAttribute : StateAttribute 11 | { 12 | public PathAttribute(PathType type, params string[] ext) 13 | { 14 | Type = type; 15 | } 16 | public PathAttribute(params string[] ext) 17 | { 18 | Type = PathType.Auto; 19 | Ext = ext; 20 | } 21 | 22 | public string[] Ext { get; } 23 | 24 | public bool All { get; set; } 25 | 26 | public PathType Type { get; set; } 27 | public string FileName { get; set; } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /MechaView/Mecha.Core/ViewModel.Attributes/Group.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Mecha.ViewModel.Attributes 8 | { 9 | [AttributeUsage(AttributeTargets.Field)] 10 | public class GroupAttribute : Attribute 11 | { 12 | public GroupAttribute(bool invisible) 13 | { 14 | Invisible = invisible; 15 | } 16 | public GroupAttribute(string displayName) 17 | { 18 | if (string.IsNullOrWhiteSpace(displayName)) 19 | throw new ArgumentNullException(); 20 | 21 | DisplayName = displayName; 22 | Invisible = false; 23 | } 24 | public string DisplayName { get; } 25 | 26 | public bool Invisible { get; } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /MechaView/Mecha.Core/ViewModel.Attributes/Message.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Mecha.ViewModel.Attributes 8 | { 9 | [AttributeUsage(AttributeTargets.Method)] 10 | public class MessageAttribute : ActionAttribute 11 | { 12 | public MessageAttribute(string title, string message) 13 | { 14 | if (string.IsNullOrWhiteSpace(title)) 15 | throw new ArgumentNullException(nameof(title)); 16 | if (string.IsNullOrWhiteSpace(message)) 17 | throw new ArgumentNullException(nameof(message)); 18 | 19 | Title = title; 20 | Message = message; 21 | } 22 | 23 | public string Title { get; } 24 | public string Message { get; } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /MechaView/Mecha.Core/ViewModel.Attributes/Progress.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Mecha.ViewModel.Attributes 8 | { 9 | [AttributeUsage(AttributeTargets.Method)] 10 | public class ProgressAttribute : ActionAttribute 11 | { 12 | public ProgressAttribute(string title, string message) 13 | { 14 | if (string.IsNullOrWhiteSpace(title)) 15 | throw new ArgumentNullException(nameof(title)); 16 | if (string.IsNullOrWhiteSpace(message)) 17 | throw new ArgumentNullException(nameof(message)); 18 | 19 | Title = title; 20 | Message = message; 21 | } 22 | 23 | public string Title { get; } 24 | public string Message { get; } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /MechaView/Mecha.Core.Wpf/View/Wpf/Controls/TextView.xaml: -------------------------------------------------------------------------------- 1 | 9 | 10 | 13 | 14 | 17 | 18 | -------------------------------------------------------------------------------- /MechaView/Mecha.Core/ViewModel.Elements/ActionElement.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Reflection; 4 | using System.Text; 5 | using Mecha.ViewModel; 6 | using Mecha.ViewModel.Attributes; 7 | 8 | namespace Mecha.ViewModel.Elements 9 | { 10 | internal class ActionElement : Element 11 | { 12 | public ActionElement(Container parent, MethodInfo method, string name) : base(parent, name) 13 | { 14 | if (method == null) 15 | throw new ArgumentNullException(nameof(method)); 16 | 17 | this.Method = method; 18 | } 19 | 20 | public object Invoke(params object[] args) 21 | { 22 | return Method.Invoke(Parent.Source, args); 23 | } 24 | 25 | public MethodInfo Method { get; } 26 | 27 | public ActionAttribute[] ActionAttributes { get; set; } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /MechaView/Mecha.Core/ViewModel.Attributes/Element.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace Mecha.ViewModel.Attributes 6 | { 7 | [AttributeUsage( 8 | AttributeTargets.Property | AttributeTargets.Method, 9 | Inherited = true, 10 | AllowMultiple = false)] 11 | public class ElementAttribute : Attribute 12 | { 13 | public ElementAttribute() { } 14 | public ElementAttribute(string displayName) 15 | { 16 | DisplayName = displayName; 17 | } 18 | 19 | public string DisplayName { get; set; } 20 | public string Description { get; set; } 21 | 22 | /// 23 | /// A value of a user defined enum 24 | /// 25 | public object Group { get; set; } 26 | public double Position { get; set; } = -1; 27 | public int Width { get; set; } = -1; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /MechaView/Mecha.Core.Wpf/View/Wpf/Converters/IntToVisibilityConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Globalization; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using System.Windows; 8 | using System.Windows.Data; 9 | 10 | namespace Mecha.View.Wpf.Converters 11 | { 12 | [Localizability(LocalizationCategory.NeverLocalize)] 13 | public class IntToVisibilityConverter : IValueConverter 14 | { 15 | public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 16 | { 17 | return value is int x && x > 0 18 | ? Visibility.Visible 19 | : Visibility.Hidden; 20 | } 21 | 22 | public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 23 | { 24 | throw new InvalidOperationException(); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Samples/Samples/ElementDecoration.cs: -------------------------------------------------------------------------------- 1 | using Mecha.ViewModel.Attributes; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace SampleApp 9 | { 10 | public class ElementDecoration 11 | { 12 | [Readonly("Status Label")] 13 | public virtual string Status { get; set; } 14 | 15 | [TextInput(Persistent = true)] 16 | public virtual string User { get; set; } 17 | 18 | [Password(Persistent = true)] 19 | public virtual string Pass { get; set; } 20 | 21 | [TextInput(Persistent = true, Multiline = true)] 22 | public virtual string Description { get; set; } 23 | 24 | [DateInput(Persistent = true)] 25 | public virtual DateTime Start { get; set; } = DateTime.Now; 26 | 27 | [Path("txt", "md", Type = PathType.Open, Persistent = true)] 28 | public virtual string File { get; set; } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /MechaView/Mecha.Core.Wpf/View/Wpf/Controls/TextInput.xaml: -------------------------------------------------------------------------------- 1 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 20 | 21 | -------------------------------------------------------------------------------- /MechaView/Mecha.Core/ViewModel.Attributes/Confirm.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Mecha.ViewModel.Attributes 8 | { 9 | [AttributeUsage(AttributeTargets.Method)] 10 | public class ConfirmAttribute : ActionAttribute 11 | { 12 | public ConfirmAttribute(string title, string message) 13 | { 14 | if (string.IsNullOrWhiteSpace(title)) 15 | throw new ArgumentNullException(nameof(title)); 16 | if (string.IsNullOrWhiteSpace(message)) 17 | throw new ArgumentNullException(nameof(message)); 18 | 19 | Title = title; 20 | Message = message; 21 | } 22 | 23 | public string Title { get; } 24 | public string Message { get; } 25 | public string AffirmativeText { get; set; } 26 | public string DismissiveText { get; set; } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /MechaView/Mecha.Core.Wpf/View/Wpf/Controls/PasswordInput.xaml: -------------------------------------------------------------------------------- 1 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 20 | 21 | -------------------------------------------------------------------------------- /MechaView/Mecha.Core.Wpf/View/Wpf/Controls/EnumInput.xaml: -------------------------------------------------------------------------------- 1 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 20 | 21 | -------------------------------------------------------------------------------- /MechaView/Mecha.Core.Wpf/View/Wpf/Converters/CollectionToVisibilityConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Globalization; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using System.Windows; 8 | using System.Windows.Data; 9 | 10 | namespace Mecha.View.Wpf.Converters 11 | { 12 | [Localizability(LocalizationCategory.NeverLocalize)] 13 | public class CollectionToVisibilityConverter : IValueConverter 14 | { 15 | public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 16 | { 17 | if (value == null) return Visibility.Hidden; 18 | if (value is ICollection col && col.Count > 0) return Visibility.Visible; 19 | return Visibility.Hidden; 20 | } 21 | 22 | public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 23 | { 24 | throw new InvalidOperationException(); 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /MechaView/Mecha.Core.Wpf/View/Wpf/Controls/DateInput.xaml: -------------------------------------------------------------------------------- 1 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 20 | 21 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Marek Toman 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 | -------------------------------------------------------------------------------- /MechaView/Mecha.Core.Wpf/View/Wpf/Controls/PathInput.xaml: -------------------------------------------------------------------------------- 1 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 23 | 24 | -------------------------------------------------------------------------------- /MechaView/Mecha.Core.Wpf/View/Wpf/Controls/MandatoryInputRule.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Globalization; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using System.Windows.Controls; 8 | using VM = Mecha.ViewModel.Elements; 9 | 10 | namespace Mecha.View.Wpf.Controls 11 | { 12 | internal class MandatoryInputRule : ValidationRule 13 | { 14 | readonly VM.StateElement stateVM; 15 | public MandatoryInputRule(VM.StateElement stateVM) 16 | { 17 | if (stateVM == null) 18 | throw new ArgumentNullException(nameof(stateVM)); 19 | this.stateVM = stateVM; 20 | } 21 | 22 | public override ValidationResult Validate(object value, CultureInfo cultureInfo) 23 | { 24 | if (stateVM.StateAttribute?.Mandatory == true) 25 | { 26 | if (string.IsNullOrWhiteSpace(value as string)) 27 | return new ValidationResult(false, "Required"); 28 | } 29 | 30 | return new ValidationResult(true, value); 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /MechaView/SettingManager/SettingManager/SettingManagerShared.shproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 423ab3e4-56e8-4228-93c4-fa169ce18ad9 5 | 14.0 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /MechaView/Mecha.Core.Wpf/View/Wpf/Helpers/Utils.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Globalization; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using System.Windows; 8 | using System.Windows.Controls; 9 | using System.Windows.Media; 10 | 11 | namespace Mecha.View.Wpf.Helpers 12 | { 13 | internal static class Utils 14 | { 15 | public static Size MeasureString(this Label ctrl) 16 | { 17 | if (string.IsNullOrEmpty(ctrl.Content?.ToString())) 18 | return new Size(); 19 | 20 | return MeasureString(ctrl, ctrl.Content.ToString()); 21 | } 22 | public static Size MeasureString(this Label ctrl, string candidate) 23 | { 24 | var ft = new FormattedText( 25 | candidate, 26 | CultureInfo.CurrentUICulture, 27 | FlowDirection.LeftToRight, 28 | new Typeface(ctrl.FontFamily, ctrl.FontStyle, ctrl.FontWeight, ctrl.FontStretch), 29 | ctrl.FontSize, 30 | Brushes.Black); 31 | 32 | return new Size(ft.Width, ft.Height); 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /MechaView/Mecha.Core.Wpf/Properties/Settings.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 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 Mecha.Properties { 12 | 13 | 14 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 15 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "14.0.0.0")] 16 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { 17 | 18 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); 19 | 20 | public static Settings Default { 21 | get { 22 | return defaultInstance; 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Samples/Samples.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.29025.244 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Samples", "Samples\Samples.csproj", "{E78B1A54-4D33-4F25-8BCE-B0B753D42A71}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {E78B1A54-4D33-4F25-8BCE-B0B753D42A71}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {E78B1A54-4D33-4F25-8BCE-B0B753D42A71}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {E78B1A54-4D33-4F25-8BCE-B0B753D42A71}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {E78B1A54-4D33-4F25-8BCE-B0B753D42A71}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | GlobalSection(ExtensibilityGlobals) = postSolution 23 | SolutionGuid = {58C82D39-A5DC-4542-B8F3-D28D9E98A6A9} 24 | EndGlobalSection 25 | EndGlobal 26 | -------------------------------------------------------------------------------- /MechaView/Mecha.Wpf.Ma.Dev/Properties/Settings.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 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 Mecha.Wpf.Ma.Dev.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 | -------------------------------------------------------------------------------- /MechaView/Mecha.Core.Wpf/View/Wpf/Controls/RowGrid.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.Windows; 7 | using System.Windows.Controls; 8 | using System.Windows.Data; 9 | using System.Windows.Documents; 10 | using System.Windows.Input; 11 | using System.Windows.Media; 12 | using System.Windows.Media.Imaging; 13 | using System.Windows.Navigation; 14 | using System.Windows.Shapes; 15 | 16 | namespace Mecha.View.Wpf.Controls 17 | { 18 | /// 19 | /// Interaction logic for RowGrid.xaml 20 | /// 21 | public partial class RowGrid : Grid, ILabeled 22 | { 23 | public RowGrid() 24 | { 25 | InitializeComponent(); 26 | } 27 | 28 | public double LabelWidth 29 | { 30 | get 31 | { 32 | return (Children.Cast().FirstOrDefault() as ILabeled)?.LabelWidth ?? 0; 33 | } 34 | set 35 | { 36 | var il = Children.Cast().FirstOrDefault() as ILabeled; 37 | if (il != null) 38 | il.LabelWidth = value; 39 | } 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /MechaView/Mecha.Core/ViewModel/Validation.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using Mecha.ViewModel.Elements; 7 | 8 | namespace Mecha.ViewModel 9 | { 10 | internal class Validation 11 | { 12 | public IEnumerable ValidateStateChildren(Container container) 13 | { 14 | if (container == null) 15 | throw new ArgumentNullException(nameof(container)); 16 | 17 | var states = container.Elements 18 | .OfType() 19 | .Where(x => x.StateAttribute?.Mandatory == true); 20 | 21 | foreach (var se in states) 22 | { 23 | var t = se.Property.PropertyType; 24 | 25 | bool isValid = 26 | t == typeof(string) 27 | ? !string.IsNullOrWhiteSpace((string)se.Value) : 28 | t.IsValueType 29 | ? se.Value != Activator.CreateInstance(t) 30 | : se.Value != null; 31 | 32 | yield return new 33 | { 34 | IsValid = isValid, 35 | StateElement = se 36 | }; 37 | } 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /MechaView/Mecha.Core.Wpf/View/Wpf/Controls/TextView.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.Windows; 7 | using System.Windows.Controls; 8 | using System.Windows.Data; 9 | using System.Windows.Documents; 10 | using System.Windows.Input; 11 | using System.Windows.Media; 12 | using System.Windows.Media.Imaging; 13 | using System.Windows.Navigation; 14 | using System.Windows.Shapes; 15 | using VM = Mecha.ViewModel.Elements; 16 | 17 | namespace Mecha.View.Wpf.Controls 18 | { 19 | /// 20 | /// Interaction logic for TextView.xaml 21 | /// 22 | public partial class TextView : UserControl 23 | { 24 | VM.TextView vm; 25 | internal VM.TextView ViewModel 26 | { 27 | get { return vm; } 28 | set 29 | { 30 | vm = value; 31 | DataContext = vm; 32 | 33 | if (vm.StateAttribute?.Height > 0) 34 | Height = vm.StateAttribute.Height; 35 | 36 | label.DataContext = vm; 37 | label.SetBinding(Label.ContentProperty, new Binding(vm.Path)); 38 | } 39 | } 40 | 41 | public TextView() 42 | { 43 | InitializeComponent(); 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /Samples/Samples/ActionDialogs.cs: -------------------------------------------------------------------------------- 1 | using Mecha.ViewModel; 2 | using Mecha.ViewModel.Attributes; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | using MV = Mecha.ViewModel; 9 | 10 | namespace SampleApp 11 | { 12 | public class ActionDialogs 13 | { 14 | public virtual string StatusLabel { get; set; } 15 | 16 | [Confirm("Confirmation", "Continue?")] 17 | [Progress("Static Progress", "Processing...")] 18 | [Message("Static Message", "Done")] 19 | public async Task StaticAll() 20 | { 21 | await Task.Delay(1500); 22 | } 23 | 24 | public void DynamicMessage(IMechaMessage msg) 25 | { 26 | msg.Title = "Dynamic Message"; 27 | msg.Message = "Done at " + DateTime.Now.ToShortTimeString(); 28 | } 29 | 30 | public async Task DynamicProgress(IMechaProgress prog) 31 | { 32 | prog.Title = "Dynamic Progress"; 33 | prog.IsCancelable = true; 34 | 35 | for (int i = 0; !prog.IsCanceled && i < 100; i++) 36 | { 37 | prog.Progress = .01 * i; 38 | prog.Message = $"Processing... ({i}%)"; 39 | await Task.Delay(10); 40 | } 41 | } 42 | 43 | public void ThrowError() 44 | { 45 | throw new Exception("Invalid something"); 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /Samples/Samples/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("MechaSample1")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("MechaSample1")] 13 | [assembly: AssemblyCopyright("Copyright © 2019")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("e78b1a54-4d33-4f25-8bce-b0b753d42a71")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /MechaView/Mecha.Core.Wpf/View/Wpf/Controls/MainPanel.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.Windows; 7 | using System.Windows.Controls; 8 | using System.Windows.Data; 9 | using System.Windows.Documents; 10 | using System.Windows.Input; 11 | using System.Windows.Media; 12 | using System.Windows.Media.Imaging; 13 | using System.Windows.Navigation; 14 | using System.Windows.Shapes; 15 | 16 | namespace Mecha.View.Wpf.Controls 17 | { 18 | /// 19 | /// Interaction logic for MainPanel.xaml 20 | /// 21 | public partial class MainPanel : StackPanel 22 | { 23 | public MainPanel() 24 | { 25 | InitializeComponent(); 26 | } 27 | 28 | public static readonly DependencyProperty HasRootPanels = DependencyProperty.RegisterAttached( 29 | nameof(HasRootPanels), 30 | typeof(bool), 31 | typeof(MainPanel), 32 | new PropertyMetadata(false)); 33 | 34 | public static bool GetHasRootPanels(DependencyObject d) 35 | { 36 | return (bool)d.GetValue(HasRootPanels); 37 | } 38 | public static void SetHasRootPanels(DependencyObject d, bool value) 39 | { 40 | d.SetValue(HasRootPanels, value); 41 | } 42 | 43 | public bool HasRootPanelControls 44 | { 45 | get { return (bool)GetValue(HasRootPanels); } 46 | set { SetValue(HasRootPanels, value); } 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /MechaView/Mecha.Core/ViewModel.Elements/StateElement.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Reflection; 5 | using System.Runtime.CompilerServices; 6 | using System.Text; 7 | using Mecha.ViewModel.Attributes; 8 | 9 | namespace Mecha.ViewModel.Elements 10 | { 11 | internal class StateElement : Element 12 | { 13 | public PropertyInfo Property { get; } 14 | 15 | public StateElement(Container parent, PropertyInfo property, string name) : base(parent, name) 16 | { 17 | if (property == null) 18 | throw new ArgumentNullException(nameof(property)); 19 | 20 | this.Property = property; 21 | } 22 | 23 | public object Value 24 | { 25 | get { return Property.GetValue(Parent.Source, null); } 26 | set { Property.SetValue(Parent.Source, value, null); } 27 | } 28 | 29 | public StateAttribute StateAttribute 30 | { 31 | get { return base.Attribute as StateAttribute; } 32 | set { base.Attribute = value; } 33 | } 34 | 35 | public bool Validate() 36 | { 37 | if (OnValidation == null) 38 | return true; 39 | 40 | var res = new ValidationResult(); 41 | 42 | OnValidation(this, res); 43 | 44 | return !res.HasError; 45 | } 46 | public event EventHandler OnValidation; 47 | } 48 | 49 | public class ValidationResult 50 | { 51 | public bool HasError { get; set; } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /MechaView/Mecha.Wpf.Settings/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("Mecha.Wpf.Settings")] 9 | [assembly: AssemblyDescription("Mecha.Wpf Settings")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("Mecha.Wpf.Settings")] 13 | [assembly: AssemblyCopyright("Copyright © 2015")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("fbcdeb01-6f10-4c49-8618-8a5074dce240")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.*")] 36 | //[assembly: AssemblyVersion("1.0.0.0")] 37 | //[assembly: AssemblyFileVersion("1.0.0.0")] 38 | -------------------------------------------------------------------------------- /MechaView/Mecha.Core/Helpers/Utils.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Globalization; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Text.RegularExpressions; 7 | 8 | namespace Mecha.Helpers 9 | { 10 | internal static class Utils 11 | { 12 | public static IEnumerable NameToDisplay(string value) 13 | { 14 | var fullWords = Regex.Matches(value, "[A-Z][a-z]+"); 15 | 16 | if (fullWords.Count == 0) 17 | yield return value; 18 | 19 | int i = 0; 20 | foreach (Match x in fullWords) 21 | { 22 | int tmp = i; 23 | i = x.Index + x.Length; 24 | if (tmp < x.Index) 25 | yield return value.Substring(tmp, x.Index - tmp); 26 | yield return x.Value; 27 | } 28 | } 29 | 30 | public static string NameToDisplayName(string value) 31 | { 32 | return string.Join(" ", NameToDisplay(value)); 33 | } 34 | 35 | public static string TrimEnd(this string s, string value) 36 | { 37 | if (string.IsNullOrWhiteSpace(s)) 38 | throw new ArgumentNullException(nameof(s)); 39 | 40 | return s.EndsWith(value, StringComparison.CurrentCulture) 41 | ? s.Remove(s.Length - value.Length) 42 | : s; 43 | } 44 | 45 | public static bool IsNumeric(this Type type) 46 | { 47 | if (type == null) 48 | throw new ArgumentNullException(nameof(type)); 49 | 50 | return type.IsPrimitive && type != typeof(bool) && type != typeof(char); 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /MechaView/Mecha.Core/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("MechaView")] 9 | [assembly: AssemblyDescription("View generator")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("MechaView")] 13 | [assembly: AssemblyCopyright("Copyright © 2015")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("1de7e8ac-63bd-4892-9834-f6a32d657b80")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.*")] 36 | [assembly: AssemblyInformationalVersion("1.0.*")] 37 | //[assembly: AssemblyVersion("1.0.0.0")] 38 | //[assembly: AssemblyFileVersion("1.0.0.0")] 39 | 40 | [assembly: InternalsVisibleTo("Mecha.Core.Wpf", AllInternalsVisible = true)] 41 | -------------------------------------------------------------------------------- /MechaView/Mecha.Core/ViewModel.Elements/Container.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Linq; 5 | using System.Reflection; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | using Castle.DynamicProxy; 9 | 10 | namespace Mecha.ViewModel.Elements 11 | { 12 | internal class Container : Element 13 | { 14 | object CreateProxy(Type sourceType) 15 | { 16 | return new ProxyGenerator().CreateClassProxy( 17 | sourceType, 18 | new[] { typeof(INotifyPropertyChanged) }, 19 | interceptor); 20 | } 21 | readonly InpcInterceptor interceptor = new InpcInterceptor(); 22 | 23 | public Container(Type sourceType) : base(sourceType?.Name) 24 | { 25 | Source = CreateProxy(sourceType); 26 | Elements = ElementBuilder.CreateElements(Source.GetType(), this); 27 | } 28 | public Container(Type sourceType, Container parent, string name) : base(parent, name) 29 | { 30 | if (sourceType == null) 31 | throw new ArgumentNullException(nameof(sourceType)); 32 | 33 | Source = CreateProxy(sourceType); 34 | Elements = ElementBuilder.CreateElements(Source.GetType(), this); 35 | } 36 | public Container(Type sourceType, string name) : base(name) 37 | { 38 | if (sourceType == null) 39 | throw new ArgumentNullException(nameof(sourceType)); 40 | 41 | Source = CreateProxy(sourceType); 42 | Elements = ElementBuilder.CreateElements(Source.GetType(), this); 43 | } 44 | 45 | public object Source { get; } 46 | public Element[] Elements { get; } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /MechaView/Mecha.Core.Wpf/View/Wpf/Dialogs.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using Mecha.ViewModel; 7 | 8 | namespace Mecha.View.Wpf 9 | { 10 | public delegate Task ShowProgressDialog(string title, string message, bool isCancelable); 11 | public delegate Task ShowErrorDialog(string title, string message); 12 | public delegate Task ShowInfoDialog(string title, string message); 13 | public delegate Task ShowConfirmDialog(string title, string message, string affirmativeText, string dismissiveText); 14 | //public delegate void CloseDialog(); 15 | 16 | public class Dialogs 17 | { 18 | public Dialogs( 19 | ShowProgressDialog showProgress, 20 | ShowErrorDialog showError, 21 | ShowInfoDialog showInfo, 22 | ShowConfirmDialog showConfirm) 23 | { 24 | if (showProgress == null) 25 | throw new ArgumentNullException(nameof(showProgress)); 26 | if (showError == null) 27 | throw new ArgumentNullException(nameof(showError)); 28 | if (showInfo == null) 29 | throw new ArgumentNullException(nameof(showInfo)); 30 | if (showConfirm == null) 31 | throw new ArgumentNullException(nameof(showConfirm)); 32 | 33 | ShowProgress = showProgress; 34 | ShowError = showError; 35 | ShowInfo = showInfo; 36 | ShowConfirm = showConfirm; 37 | } 38 | public ShowProgressDialog ShowProgress { get; } 39 | public ShowErrorDialog ShowError { get; } 40 | public ShowInfoDialog ShowInfo { get; } 41 | public ShowConfirmDialog ShowConfirm { get; } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /Samples/Samples/ElementConventions.cs: -------------------------------------------------------------------------------- 1 | using Mecha.ViewModel.Attributes; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.ComponentModel; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | namespace SampleApp 10 | { 11 | public class ElementConventions 12 | { 13 | public virtual string StatusLabel { get; set; } 14 | 15 | public virtual string User { get; set; } 16 | public virtual string Password { get; set; } 17 | public virtual DateTime Start { get; set; } = DateTime.Now.Date.AddDays(-1); 18 | public virtual string SaveToPath { get; set; } 19 | 20 | public enum Dimension { ThreeDimensional, TwoDimensional } 21 | public virtual Dimension PointDimension { get; set; } 22 | 23 | public virtual bool FilterOutNegative { get; set; } 24 | public virtual Point[] Points { get; set; } 25 | 26 | public async Task GetPoints() 27 | { 28 | StatusLabel = $"Getting points since {Start}..."; 29 | await Task.Delay(1500); 30 | 31 | Points = Enumerable.Range(-10, 90) 32 | .Select(i => new Point { X = i, Y = i + 10, Z = PointDimension == Dimension.ThreeDimensional ? i * 10 : 0 }) 33 | .Where(x => !FilterOutNegative || (x.X >= 0 && x.Y >= 0 && x.Z >= 0)) 34 | .ToArray(); 35 | 36 | if (SaveToPath != null) 37 | { 38 | StatusLabel = $"Saving points to {SaveToPath}..."; 39 | await Task.Delay(1000); 40 | } 41 | 42 | StatusLabel = "Success!"; 43 | } 44 | } 45 | public struct Point 46 | { 47 | public int X { get; set; } 48 | public int Y { get; set; } 49 | public int Z { get; set; } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /MechaView/Mecha.Core/ViewModel.Elements/Element.cs: -------------------------------------------------------------------------------- 1 | using Mecha.ViewModel.Attributes; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Text; 5 | using System.ComponentModel; 6 | using System.Runtime.CompilerServices; 7 | 8 | namespace Mecha.ViewModel.Elements 9 | { 10 | internal class Element : INotifyPropertyChanged 11 | { 12 | public Element(string name) 13 | { 14 | if (name == null) 15 | throw new ArgumentNullException(nameof(name)); 16 | 17 | Name = name; 18 | IsRootElement = true; 19 | } 20 | public Element(Container parent, string name) : this(name) 21 | { 22 | if (parent == null) 23 | throw new ArgumentNullException(nameof(parent)); 24 | 25 | Parent = parent; 26 | } 27 | 28 | public bool IsRootElement { get; } 29 | public Container Parent { get; } 30 | public string Name { get; } 31 | 32 | string displayName; 33 | public string DisplayName 34 | { 35 | get { return displayName; } 36 | set 37 | { 38 | displayName = value; 39 | OnPropertyChanged(); 40 | } 41 | } 42 | 43 | public string Description { get; set; } 44 | 45 | public ElementAttribute Attribute { get; set; } 46 | 47 | public string Path 48 | { 49 | get 50 | { 51 | return Parent != null 52 | ? nameof(Parent) +"."+ nameof(Parent.Source) +"."+ Name 53 | : null; 54 | } 55 | } 56 | 57 | public event PropertyChangedEventHandler PropertyChanged; 58 | void OnPropertyChanged([CallerMemberName] string name = null) 59 | { 60 | PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name)); 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /MechaView/Mecha.Core.Wpf/View/Wpf/Controls/DateInput.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.Windows; 7 | using System.Windows.Controls; 8 | using System.Windows.Data; 9 | using System.Windows.Documents; 10 | using System.Windows.Input; 11 | using System.Windows.Media; 12 | using System.Windows.Media.Imaging; 13 | using System.Windows.Navigation; 14 | using System.Windows.Shapes; 15 | using VM = Mecha.ViewModel.Elements; 16 | 17 | namespace Mecha.View.Wpf.Controls 18 | { 19 | /// 20 | /// Interaction logic for DateInput.xaml 21 | /// 22 | public partial class DateInput : UserControl, ILabeled 23 | { 24 | public DateInput() 25 | { 26 | InitializeComponent(); 27 | } 28 | 29 | bool isSetup; 30 | 31 | VM.DateInput vm; 32 | internal VM.DateInput ViewModel 33 | { 34 | get { return vm; } 35 | set 36 | { 37 | if (isSetup) 38 | throw new InvalidOperationException("ViewModel can be set only once."); 39 | isSetup = true; 40 | 41 | vm = value; 42 | 43 | DataContext = vm; 44 | label.DataContext = vm; 45 | dateBox.DataContext = vm; 46 | 47 | var binding = new Binding(vm.Path) 48 | { 49 | UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged, 50 | ValidatesOnExceptions = true, 51 | }; 52 | dateBox.SetBinding(DatePicker.SelectedDateProperty, binding); 53 | 54 | //if (vm == null || vm.Value == default) 55 | // dateBox.SelectedDate = DateTime.Now; 56 | } 57 | } 58 | 59 | public double LabelWidth 60 | { 61 | get { return label.ActualWidth; } 62 | set { label.Width = value; } 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /MechaView/Mecha.Core.Wpf/View/Wpf/MergedStylesExtension.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.Windows; 7 | using System.Windows.Markup; 8 | 9 | namespace Mecha.View.Wpf 10 | { 11 | [MarkupExtensionReturnType(typeof(Style))] 12 | public class MergedStylesExtension : MarkupExtension 13 | { 14 | public Style BasedOn { get; set; } 15 | public Style Merged { get; set; } 16 | public Style Merged2 { get; set; } 17 | public Style Merged3 { get; set; } 18 | public Style Merged4 { get; set; } 19 | public Style Merged5 { get; set; } 20 | 21 | public override object ProvideValue(IServiceProvider serviceProvider) 22 | { 23 | if (BasedOn == null) 24 | throw new ArgumentNullException(nameof(BasedOn)); 25 | if (Merged == null) 26 | throw new ArgumentNullException(nameof(Merged)); 27 | 28 | var newStyle = new Style(BasedOn.TargetType, BasedOn); 29 | 30 | MergeWithStyle(newStyle, Merged); 31 | 32 | if (Merged2 != null) 33 | MergeWithStyle(newStyle, Merged2); 34 | if (Merged3 != null) 35 | MergeWithStyle(newStyle, Merged3); 36 | if (Merged4 != null) 37 | MergeWithStyle(newStyle, Merged4); 38 | if (Merged5 != null) 39 | MergeWithStyle(newStyle, Merged5); 40 | 41 | return newStyle; 42 | } 43 | 44 | static void MergeWithStyle(Style style, Style mergeStyle) 45 | { 46 | // Recursively merge this style with any style it may be based on. 47 | if (mergeStyle.BasedOn != null) 48 | MergeWithStyle(style, mergeStyle.BasedOn); 49 | 50 | foreach (var setter in mergeStyle.Setters) 51 | style.Setters.Add(setter); 52 | 53 | foreach (var trigger in mergeStyle.Triggers) 54 | style.Triggers.Add(trigger); 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /MechaView/Mecha.Core/ViewModel/InpcInterceptor.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using Castle.DynamicProxy; 8 | 9 | namespace Mecha.ViewModel 10 | { 11 | internal class InpcInterceptor : IInterceptor 12 | { 13 | PropertyChangedEventHandler eventHandler; 14 | 15 | public void Intercept(IInvocation invocation) 16 | { 17 | string methodName = invocation.Method.Name; 18 | object[] args = invocation.Arguments; 19 | object proxy = invocation.Proxy; 20 | 21 | if (invocation.Method.DeclaringType.Equals(typeof(INotifyPropertyChanged))) 22 | { 23 | if (methodName == "add_PropertyChanged") 24 | eventHandler = (PropertyChangedEventHandler)Delegate.Combine(eventHandler, (Delegate)args[0]); 25 | else if (methodName == "remove_PropertyChanged") 26 | eventHandler = (PropertyChangedEventHandler)Delegate.Remove(eventHandler, (Delegate)args[0]); 27 | } 28 | 29 | if (!ShouldProceedWithInvocation(methodName)) 30 | return; 31 | 32 | invocation.Proceed(); 33 | 34 | NotifyPropertyChanged(methodName, proxy); 35 | } 36 | 37 | protected void OnPropertyChanged(Object sender, PropertyChangedEventArgs e) 38 | { 39 | if (eventHandler != null) 40 | eventHandler(sender, e); 41 | } 42 | 43 | protected void NotifyPropertyChanged(string methodName, object proxy) 44 | { 45 | if (methodName.StartsWith("set_")) 46 | { 47 | var propName = methodName.Substring(4); 48 | OnPropertyChanged(proxy, new PropertyChangedEventArgs(propName)); 49 | } 50 | } 51 | 52 | protected bool ShouldProceedWithInvocation(string methodName) 53 | { 54 | return 55 | methodName != "add_PropertyChanged" && 56 | methodName != "remove_PropertyChanged"; 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /Samples/Samples/ElementGrouping.cs: -------------------------------------------------------------------------------- 1 | using Mecha.ViewModel.Attributes; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace SampleApp 9 | { 10 | public class ElementGrouping 11 | { 12 | enum Grp 13 | { 14 | Input, 15 | [Group(invisible: true)] Result 16 | } 17 | 18 | // 19 | // User 20 | // 21 | 22 | [Element(Group = Grp.Input, Position = 0.0)] 23 | public virtual string User { get; set; } 24 | 25 | [Element(Group = Grp.Input, Position = 0.1)] 26 | public virtual string Password { get; set; } 27 | 28 | [Element(Group = Grp.Input, Position = 1)] 29 | public virtual bool FilterOutNegative { get; set; } 30 | 31 | [Element(Group = Grp.Input, Position = 2)] 32 | public virtual string SaveToPath { get; set; } 33 | 34 | public enum PointDimension { ThreeDimensional, TwoDimensional } 35 | [Element(Group = Grp.Input, Position = 3.0)] 36 | public virtual DateTime Start { get; set; } = DateTime.Now.AddDays(-1); 37 | 38 | [Element(Group = Grp.Input, Position = 3.1)] 39 | public virtual PointDimension Dimension { get; set; } 40 | 41 | [Element(Group = Grp.Input)] 42 | public void Clear() 43 | { 44 | User = Password = SaveToPath = null; 45 | } 46 | 47 | // 48 | // Result 49 | // 50 | 51 | [Element(Group = Grp.Result)] 52 | public virtual string StatusLabel { get; set; } 53 | 54 | [Element(Group = Grp.Result)] 55 | public virtual Point[] Points { get; set; } 56 | 57 | public async Task GetPoints() 58 | { 59 | StatusLabel = $"Getting points since {Start}..."; 60 | await Task.Delay(1500); 61 | 62 | Points = Enumerable.Range(-10, 90) 63 | .Select(i => new Point { X = i, Y = i + 10, Z = Dimension == PointDimension.ThreeDimensional ? i * 10 : 0 }) 64 | .Where(x => !FilterOutNegative || (x.X >= 0 && x.Y >= 0 && x.Z >= 0)) 65 | .ToArray(); 66 | 67 | StatusLabel = "Success!"; 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /MechaView/Mecha.Wpf.Ma/ProgressDialog.cs: -------------------------------------------------------------------------------- 1 | using MahApps.Metro.Controls.Dialogs; 2 | using Mecha.ViewModel; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | namespace Mecha.Wpf.Ma 10 | { 11 | public class ProgressDialog : IMechaProgress 12 | { 13 | ProgressDialogController ctrl; 14 | bool isCancelable; 15 | string title; 16 | string message; 17 | double progress; 18 | 19 | public ProgressDialog(string title, string message, bool isCancelable, ProgressDialogController ctrl) 20 | { 21 | if (ctrl == null) 22 | throw new ArgumentNullException(nameof(ctrl)); 23 | 24 | this.ctrl = ctrl; 25 | this.title = title; 26 | this.message = message; 27 | this.isCancelable = isCancelable; 28 | } 29 | 30 | public bool IsOpen { get { return ctrl.IsOpen; } } 31 | 32 | public string Message 33 | { 34 | get { return message; } 35 | set 36 | { 37 | message = value; 38 | ctrl.SetMessage(value); 39 | } 40 | } 41 | 42 | public bool IsIndeterminate 43 | { 44 | get { return double.IsNaN(progress) || progress < 0; } 45 | set { progress = double.NaN; } 46 | } 47 | 48 | public double Progress 49 | { 50 | get { return progress; } 51 | set 52 | { 53 | progress = value; 54 | if (double.IsNaN(value) || value < 0) 55 | ctrl.SetIndeterminate(); 56 | else 57 | ctrl.SetProgress(value); 58 | } 59 | } 60 | 61 | public string Title 62 | { 63 | get { return title; } 64 | set 65 | { 66 | title = value; 67 | ctrl.SetTitle(value); 68 | } 69 | } 70 | 71 | public bool IsCancelable 72 | { 73 | get { return isCancelable; } 74 | set 75 | { 76 | isCancelable = value; 77 | ctrl.SetCancelable(value); 78 | } 79 | } 80 | 81 | public bool IsCanceled 82 | { 83 | get { return ctrl.IsCanceled; } 84 | } 85 | 86 | public Task CloseAsync() 87 | { 88 | return ctrl.CloseAsync(); 89 | } 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /MechaView/Mecha.Wpf.Ma/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Resources; 3 | using System.Runtime.CompilerServices; 4 | using System.Runtime.InteropServices; 5 | using System.Windows; 6 | 7 | // General Information about an assembly is controlled through the following 8 | // set of attributes. Change these attribute values to modify the information 9 | // associated with an assembly. 10 | [assembly: AssemblyTitle("Mecha.Wpf.Ma")] 11 | [assembly: AssemblyDescription("")] 12 | [assembly: AssemblyConfiguration("")] 13 | [assembly: AssemblyCompany("")] 14 | [assembly: AssemblyProduct("Mecha.Wpf.Ma")] 15 | [assembly: AssemblyCopyright("Copyright © 2019")] 16 | [assembly: AssemblyTrademark("")] 17 | [assembly: AssemblyCulture("")] 18 | 19 | // Setting ComVisible to false makes the types in this assembly not visible 20 | // to COM components. If you need to access a type in this assembly from 21 | // COM, set the ComVisible attribute to true on that type. 22 | [assembly: ComVisible(false)] 23 | 24 | //In order to begin building localizable applications, set 25 | //CultureYouAreCodingWith in your .csproj file 26 | //inside a . For example, if you are using US english 27 | //in your source files, set the to en-US. Then uncomment 28 | //the NeutralResourceLanguage attribute below. Update the "en-US" in 29 | //the line below to match the UICulture setting in the project file. 30 | 31 | //[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)] 32 | 33 | 34 | [assembly:ThemeInfo( 35 | ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located 36 | //(used if a resource is not found in the page, 37 | // or application resource dictionaries) 38 | ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located 39 | //(used if a resource is not found in the page, 40 | // app, or any theme specific resource dictionaries) 41 | )] 42 | 43 | 44 | // Version information for an assembly consists of the following four values: 45 | // 46 | // Major Version 47 | // Minor Version 48 | // Build Number 49 | // Revision 50 | // 51 | // You can specify all the values or you can default the Build and Revision Numbers 52 | // by using the '*' as shown below: 53 | // [assembly: AssemblyVersion("1.0.*")] 54 | [assembly: AssemblyVersion("1.0.0.0")] 55 | [assembly: AssemblyFileVersion("1.0.0.0")] 56 | -------------------------------------------------------------------------------- /MechaView/Mecha.Wpf.Ma.Dev/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Resources; 3 | using System.Runtime.CompilerServices; 4 | using System.Runtime.InteropServices; 5 | using System.Windows; 6 | 7 | // General Information about an assembly is controlled through the following 8 | // set of attributes. Change these attribute values to modify the information 9 | // associated with an assembly. 10 | [assembly: AssemblyTitle("Mecha.Wpf.Ma.Dev")] 11 | [assembly: AssemblyDescription("")] 12 | [assembly: AssemblyConfiguration("")] 13 | [assembly: AssemblyCompany("")] 14 | [assembly: AssemblyProduct("Mecha.Wpf.Ma.Dev")] 15 | [assembly: AssemblyCopyright("Copyright © 2019")] 16 | [assembly: AssemblyTrademark("")] 17 | [assembly: AssemblyCulture("")] 18 | 19 | // Setting ComVisible to false makes the types in this assembly not visible 20 | // to COM components. If you need to access a type in this assembly from 21 | // COM, set the ComVisible attribute to true on that type. 22 | [assembly: ComVisible(false)] 23 | 24 | //In order to begin building localizable applications, set 25 | //CultureYouAreCodingWith in your .csproj file 26 | //inside a . For example, if you are using US english 27 | //in your source files, set the to en-US. Then uncomment 28 | //the NeutralResourceLanguage attribute below. Update the "en-US" in 29 | //the line below to match the UICulture setting in the project file. 30 | 31 | //[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)] 32 | 33 | 34 | [assembly: ThemeInfo( 35 | ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located 36 | //(used if a resource is not found in the page, 37 | // or application resource dictionaries) 38 | ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located 39 | //(used if a resource is not found in the page, 40 | // app, or any theme specific resource dictionaries) 41 | )] 42 | 43 | 44 | // Version information for an assembly consists of the following four values: 45 | // 46 | // Major Version 47 | // Minor Version 48 | // Build Number 49 | // Revision 50 | // 51 | // You can specify all the values or you can default the Build and Revision Numbers 52 | // by using the '*' as shown below: 53 | // [assembly: AssemblyVersion("1.0.*")] 54 | [assembly: AssemblyVersion("1.0.0.0")] 55 | [assembly: AssemblyFileVersion("1.0.0.0")] 56 | -------------------------------------------------------------------------------- /MechaView/MechaView.MahApps/tools/Mecha.Wpf.Ma.App/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Resources; 3 | using System.Runtime.CompilerServices; 4 | using System.Runtime.InteropServices; 5 | using System.Windows; 6 | 7 | // General Information about an assembly is controlled through the following 8 | // set of attributes. Change these attribute values to modify the information 9 | // associated with an assembly. 10 | //[assembly: AssemblyTitle(App.Title)] 11 | [assembly: AssemblyTitle("Application")] 12 | [assembly: AssemblyDescription("")] 13 | [assembly: AssemblyConfiguration("")] 14 | [assembly: AssemblyCompany("")] 15 | [assembly: AssemblyProduct("Application")] 16 | [assembly: AssemblyCopyright("Copyright © 2015")] 17 | [assembly: AssemblyTrademark("")] 18 | [assembly: AssemblyCulture("")] 19 | 20 | // Setting ComVisible to false makes the types in this assembly not visible 21 | // to COM components. If you need to access a type in this assembly from 22 | // COM, set the ComVisible attribute to true on that type. 23 | [assembly: ComVisible(false)] 24 | 25 | //In order to begin building localizable applications, set 26 | //CultureYouAreCodingWith in your .csproj file 27 | //inside a . For example, if you are using US english 28 | //in your source files, set the to en-US. Then uncomment 29 | //the NeutralResourceLanguage attribute below. Update the "en-US" in 30 | //the line below to match the UICulture setting in the project file. 31 | 32 | //[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)] 33 | 34 | 35 | [assembly: ThemeInfo( 36 | ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located 37 | //(used if a resource is not found in the page, 38 | // or application resource dictionaries) 39 | ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located 40 | //(used if a resource is not found in the page, 41 | // app, or any theme specific resource dictionaries) 42 | )] 43 | 44 | 45 | // Version information for an assembly consists of the following four values: 46 | // 47 | // Major Version 48 | // Minor Version 49 | // Build Number 50 | // Revision 51 | // 52 | // You can specify all the values or you can default the Build and Revision Numbers 53 | // by using the '*' as shown below: 54 | // [assembly: AssemblyVersion("1.0.*")] 55 | [assembly: AssemblyVersion("1.0.0.0")] 56 | [assembly: AssemblyFileVersion("1.0.0.0")] 57 | -------------------------------------------------------------------------------- /MechaView/publish.ps1: -------------------------------------------------------------------------------- 1 | $ErrorActionPreference = 'stop' 2 | #$msbuild = "${env:ProgramFiles(x86)}\MSBuild\14.0\Bin\MSbuild.exe" 3 | $msbuild = 'msbuild' 4 | $fw = 'net45' 5 | $gloablNugetDir = 'C:\lib\nuget' 6 | $coreProj = "$PSScriptRoot\Mecha.Core\Mecha.Core.csproj" 7 | $coreWpfProj = "$PSScriptRoot\Mecha.Core.Wpf\Mecha.Core.Wpf.csproj" 8 | $pkgDir = "$PSScriptRoot\MechaView.MahApps" 9 | $wpfMaAppDir = "$pkgDir\tools\Mecha.Wpf.Ma.App" 10 | $lib = "$pkgDir\lib\$fw\" 11 | $wpfNuspec = "$pkgDir\MechaView.MahApps.nuspec" 12 | $settingsProj = "$PSScriptRoot\Mecha.Wpf.Settings\Mecha.Wpf.Settings.csproj" 13 | $wpfMaProj = "$PSScriptRoot\Mecha.Wpf.Ma\Mecha.Wpf.Ma.csproj" 14 | 15 | function Set-Version 16 | { 17 | param( 18 | [Parameter(Mandatory, ValueFromPipeLine, ValueFromPipelineByPropertyName)] 19 | $Version, 20 | [Parameter()] 21 | [string] $Path = '.') 22 | 23 | begin {$a = @()} 24 | process {$a += $Version} 25 | end { 26 | $ErrorActionPreference = 'Stop' 27 | [int[]] $ver = $a.foreach({$_ -split '\.'}) 28 | $Path = join-path $Path version 29 | set-content $Path ($ver -join '.') 30 | } 31 | } 32 | function Get-Version 33 | { 34 | param( 35 | [Parameter()] 36 | [nullable[int]] $Increment, 37 | [Parameter()] 38 | [string] $Path = '.', 39 | [Parameter()] 40 | [switch] $AsNum) 41 | 42 | $Path = join-path $Path version 43 | 44 | [int[]] $ver = 45 | if (test-path $Path) 46 | {(get-content $Path) -split '\.'} 47 | else 48 | {0,0,0} 49 | 50 | if ($Increment -ne $null) { 51 | $ver[$Increment]++ 52 | 53 | if ($Increment -lt 0) 54 | {$Increment = $ver.Length + $Increment} 55 | 56 | for ($i = $Increment + 1; $i -lt $ver.Length; $i++) 57 | {$ver[$i] = 0} 58 | } 59 | 60 | if ($AsNum) {$ver} else {$ver -join '.'} 61 | } 62 | 63 | function build($proj) { 64 | write-host "Building $(split-path $proj -Leaf)" 65 | $err = & $msbuild $proj ` 66 | /t:Build /p:Configuration=Release /p:Platform=AnyCPU /v:quiet /nologo ` 67 | /clp:ErrorsOnly ` 68 | /p:OutputPath="$lib" 69 | if ($err) {throw $err} 70 | } 71 | 72 | $ver = get-version -inc -1 -path $PSScriptRoot 73 | 74 | Remove-Item "$wpfMaAppDir\.vs","$wpfMaAppDir\obj" -Recurse -ErrorAction SilentlyContinue 75 | mkdir $lib -ea 0|out-null 76 | 77 | build $coreProj 78 | build $coreWpfProj 79 | build $settingsProj 80 | build $wpfMaProj 81 | 82 | nuget pack $wpfNuspec -outputdirectory $gloablNugetDir -version $ver 2>&1 83 | 84 | set-version $ver -path $PSScriptRoot 85 | 86 | -------------------------------------------------------------------------------- /MechaView/Mecha.Core.Wpf/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Resources; 3 | using System.Runtime.CompilerServices; 4 | using System.Runtime.InteropServices; 5 | using System.Windows; 6 | 7 | // General Information about an assembly is controlled through the following 8 | // set of attributes. Change these attribute values to modify the information 9 | // associated with an assembly. 10 | [assembly: AssemblyTitle("MechaView.Wpf")] 11 | [assembly: AssemblyDescription("")] 12 | [assembly: AssemblyConfiguration("")] 13 | [assembly: AssemblyCompany("")] 14 | [assembly: AssemblyProduct("MechaView.Wpf")] 15 | [assembly: AssemblyCopyright("Copyright © 2016")] 16 | [assembly: AssemblyTrademark("")] 17 | [assembly: AssemblyCulture("")] 18 | 19 | // Setting ComVisible to false makes the types in this assembly not visible 20 | // to COM components. If you need to access a type in this assembly from 21 | // COM, set the ComVisible attribute to true on that type. 22 | [assembly: ComVisible(false)] 23 | 24 | //In order to begin building localizable applications, set 25 | //CultureYouAreCodingWith in your .csproj file 26 | //inside a . For example, if you are using US english 27 | //in your source files, set the to en-US. Then uncomment 28 | //the NeutralResourceLanguage attribute below. Update the "en-US" in 29 | //the line below to match the UICulture setting in the project file. 30 | 31 | //[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)] 32 | 33 | 34 | [assembly: ThemeInfo( 35 | ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located 36 | //(used if a resource is not found in the page, 37 | // or application resource dictionaries) 38 | ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located 39 | //(used if a resource is not found in the page, 40 | // app, or any theme specific resource dictionaries) 41 | )] 42 | 43 | 44 | // Version information for an assembly consists of the following four values: 45 | // 46 | // Major Version 47 | // Minor Version 48 | // Build Number 49 | // Revision 50 | // 51 | // You can specify all the values or you can default the Build and Revision Numbers 52 | // by using the '*' as shown below: 53 | // [assembly: AssemblyVersion("1.0.*")] 54 | //[assembly: AssemblyVersion("1.0.0.0")] 55 | //[assembly: AssemblyFileVersion("1.0.0.0")] 56 | [assembly: AssemblyVersion("1.0.*")] 57 | [assembly: AssemblyInformationalVersion("1.0.*")] 58 | -------------------------------------------------------------------------------- /MechaView/Mecha.Core.Wpf/View/Wpf/Controls/TextInput.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Globalization; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | using System.Windows; 9 | using System.Windows.Controls; 10 | using System.Windows.Data; 11 | using System.Windows.Documents; 12 | using System.Windows.Input; 13 | using System.Windows.Media; 14 | using System.Windows.Media.Imaging; 15 | using System.Windows.Navigation; 16 | using System.Windows.Shapes; 17 | using Mecha.ViewModel.Attributes; 18 | using VM = Mecha.ViewModel.Elements; 19 | 20 | namespace Mecha.View.Wpf.Controls 21 | { 22 | /// 23 | /// Interaction logic for TextInput.xaml 24 | /// 25 | public partial class TextInput : UserControl, ILabeled 26 | { 27 | bool isSetup; 28 | 29 | VM.TextInput vm; 30 | internal VM.TextInput ViewModel 31 | { 32 | get { return vm; } 33 | set 34 | { 35 | if (isSetup) 36 | throw new InvalidOperationException("ViewModel can be set only once."); 37 | isSetup = true; 38 | 39 | vm = value; 40 | 41 | vm.OnValidation += Validate; 42 | DataContext = vm; 43 | label.DataContext = vm; 44 | txtBox.DataContext = vm; 45 | 46 | var attrib = vm.Attribute as TextInputAttribute; 47 | if (attrib?.Multiline == true) 48 | { 49 | txtBox.TextWrapping = TextWrapping.Wrap; 50 | txtBox.AcceptsReturn = true; 51 | } 52 | 53 | var binding = new Binding(vm.Path) 54 | { 55 | UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged, 56 | ValidatesOnExceptions = true, 57 | }; 58 | binding.ValidationRules.Add(new MandatoryInputRule(vm)); 59 | txtBox.SetBinding(TextBox.TextProperty, binding); 60 | } 61 | } 62 | 63 | void Validate(object vm, VM.ValidationResult result) 64 | { 65 | if (string.IsNullOrWhiteSpace(txtBox.Text)) 66 | txtBox.Text = null; 67 | 68 | result.HasError = txtBox.GetBindingExpression(TextBox.TextProperty).HasError; 69 | } 70 | 71 | public double LabelWidth 72 | { 73 | get { return label.ActualWidth; } 74 | set { label.Width = value; } 75 | } 76 | 77 | public TextInput() 78 | { 79 | InitializeComponent(); 80 | } 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /MechaView/Mecha.Wpf.Settings/Mecha.Wpf.Settings.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {FBCDEB01-6F10-4C49-8618-8A5074DCE240} 8 | Library 9 | Properties 10 | Mecha.Wpf.Settings 11 | Mecha.Wpf.Settings 12 | v4.5 13 | 512 14 | 15 | 16 | 17 | true 18 | full 19 | false 20 | bin\Debug\ 21 | DEBUG;TRACE 22 | prompt 23 | 4 24 | 25 | 26 | pdbonly 27 | true 28 | bin\Release\ 29 | TRACE 30 | prompt 31 | 4 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 59 | -------------------------------------------------------------------------------- /MechaView/Mecha.Core.Wpf/Properties/Resources.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 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 Mecha.Properties { 12 | using System; 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 | private static global::System.Resources.ResourceManager resourceMan; 28 | 29 | private static global::System.Globalization.CultureInfo resourceCulture; 30 | 31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 32 | internal Resources() { 33 | } 34 | 35 | /// 36 | /// Returns the cached ResourceManager instance used by this class. 37 | /// 38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 39 | internal static global::System.Resources.ResourceManager ResourceManager { 40 | get { 41 | if (object.ReferenceEquals(resourceMan, null)) { 42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Mecha.Properties.Resources", typeof(Resources).Assembly); 43 | resourceMan = temp; 44 | } 45 | return resourceMan; 46 | } 47 | } 48 | 49 | /// 50 | /// Overrides the current thread's CurrentUICulture property for all 51 | /// resource lookups using this strongly typed resource class. 52 | /// 53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 54 | internal static global::System.Globalization.CultureInfo Culture { 55 | get { 56 | return resourceCulture; 57 | } 58 | set { 59 | resourceCulture = value; 60 | } 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /MechaView/Mecha.Wpf.Ma.Dev/Properties/Resources.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 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 Mecha.Wpf.Ma.Dev.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("Mecha.Wpf.Ma.Dev.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 | -------------------------------------------------------------------------------- /MechaView/Mecha.Wpf.Ma/AppHandler.cs: -------------------------------------------------------------------------------- 1 | using MahApps.Metro; 2 | using Mecha.Wpf.Settings; 3 | using Microsoft.Win32; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Configuration; 7 | using System.Data; 8 | using System.Linq; 9 | using System.Reflection; 10 | using System.Threading.Tasks; 11 | using System.Windows; 12 | using System.Windows.Media; 13 | 14 | namespace Mecha.Wpf.Ma 15 | { 16 | public class AppHandler 17 | { 18 | private readonly Application wpfApp; 19 | 20 | public bool Debug { get; private set; } 21 | public AppSettings Settings { get; } 22 | 23 | public AppHandler(IApp app, Application wpfApp) 24 | { 25 | var s = new AppSettings { Window = new WindowSettings() }; 26 | app.Init(s); 27 | 28 | if (string.IsNullOrWhiteSpace(s.Title)) 29 | throw new ArgumentNullException(nameof(s.Title)); 30 | if (s.Content == null) 31 | throw new ArgumentNullException(nameof(s.Content)); 32 | 33 | if (s.Window == null) 34 | s.Window = new WindowSettings(); 35 | 36 | Settings = s; 37 | 38 | #if DEBUG 39 | Debug = true; 40 | #endif 41 | 42 | wpfApp.DispatcherUnhandledException += App_DispatcherUnhandledException; 43 | wpfApp.Startup += App_Startup; 44 | this.wpfApp = wpfApp; 45 | } 46 | 47 | private void App_DispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e) 48 | { 49 | HandleException(sender, e.Exception); 50 | } 51 | 52 | void HandleException(object sender, Exception exception) 53 | { 54 | if (!Debug) 55 | MessageBox.Show(exception.Message, "Error - " + Settings.Title, MessageBoxButton.OK, MessageBoxImage.Error); 56 | else 57 | MessageBox.Show(exception.ToString(), "Error - " + Settings.Title, MessageBoxButton.OK, MessageBoxImage.Error); 58 | } 59 | 60 | private void App_Startup(object sender, StartupEventArgs e) 61 | { 62 | var accent = Settings.Window.Accent.ToString(); 63 | 64 | bool useDarkTheme; 65 | if (Settings.Window.ColorMode != ColorMode.Auto) 66 | { 67 | useDarkTheme = Settings.Window.ColorMode == ColorMode.Dark; 68 | } 69 | else 70 | { 71 | try 72 | { 73 | var useLightThemeStr = Registry.GetValue(@"HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Themes\Personalize", "AppsUseLightTheme", 1)?.ToString() ?? ""; 74 | useDarkTheme = int.TryParse(useLightThemeStr, out int val) && val == 0; 75 | } 76 | catch 77 | { 78 | useDarkTheme = false; 79 | } 80 | } 81 | 82 | var theme = useDarkTheme ? "BaseDark" : "BaseLight"; 83 | ThemeManager.ChangeAppStyle(wpfApp, ThemeManager.GetAccent(accent), ThemeManager.GetAppTheme(theme)); 84 | 85 | foreach (var par in e.Args) 86 | { 87 | switch (par) 88 | { 89 | case "--debug": 90 | Debug = true; 91 | break; 92 | default: 93 | throw new InvalidOperationException($"Parameter '{par}' doesn't exist. "); 94 | } 95 | } 96 | } 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /MechaView/MechaView.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.29025.244 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Mecha.Wpf.Settings", "Mecha.Wpf.Settings\Mecha.Wpf.Settings.csproj", "{FBCDEB01-6F10-4C49-8618-8A5074DCE240}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Mecha.Core.Wpf", "Mecha.Core.Wpf\Mecha.Core.Wpf.csproj", "{CAC4B9FB-05A2-42A1-A18C-2E7DE85B404F}" 9 | EndProject 10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Mecha.Core", "Mecha.Core\Mecha.Core.csproj", "{8CA49B9D-9BC4-42CB-B9A4-059D8C936917}" 11 | EndProject 12 | Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "SettingManagerShared", "SettingManager\SettingManager\SettingManagerShared.shproj", "{423AB3E4-56E8-4228-93C4-FA169CE18AD9}" 13 | EndProject 14 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Mecha.Wpf.Ma", "Mecha.Wpf.Ma\Mecha.Wpf.Ma.csproj", "{481A99C8-678F-4367-A50B-E732F6AD05FB}" 15 | EndProject 16 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Mecha.Wpf.Ma.Dev", "Mecha.Wpf.Ma.Dev\Mecha.Wpf.Ma.Dev.csproj", "{8C2F5DC8-551D-4F14-A5D5-AC6EB4AD8686}" 17 | EndProject 18 | Global 19 | GlobalSection(SharedMSBuildProjectFiles) = preSolution 20 | SettingManager\SettingManager\SettingManager.projitems*{423ab3e4-56e8-4228-93c4-fa169ce18ad9}*SharedItemsImports = 13 21 | SettingManager\SettingManager\SettingManager.projitems*{8ca49b9d-9bc4-42cb-b9a4-059d8c936917}*SharedItemsImports = 4 22 | EndGlobalSection 23 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 24 | Debug|Any CPU = Debug|Any CPU 25 | Release|Any CPU = Release|Any CPU 26 | EndGlobalSection 27 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 28 | {FBCDEB01-6F10-4C49-8618-8A5074DCE240}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 29 | {FBCDEB01-6F10-4C49-8618-8A5074DCE240}.Debug|Any CPU.Build.0 = Debug|Any CPU 30 | {FBCDEB01-6F10-4C49-8618-8A5074DCE240}.Release|Any CPU.ActiveCfg = Release|Any CPU 31 | {FBCDEB01-6F10-4C49-8618-8A5074DCE240}.Release|Any CPU.Build.0 = Release|Any CPU 32 | {CAC4B9FB-05A2-42A1-A18C-2E7DE85B404F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 33 | {CAC4B9FB-05A2-42A1-A18C-2E7DE85B404F}.Debug|Any CPU.Build.0 = Debug|Any CPU 34 | {CAC4B9FB-05A2-42A1-A18C-2E7DE85B404F}.Release|Any CPU.ActiveCfg = Release|Any CPU 35 | {CAC4B9FB-05A2-42A1-A18C-2E7DE85B404F}.Release|Any CPU.Build.0 = Release|Any CPU 36 | {8CA49B9D-9BC4-42CB-B9A4-059D8C936917}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 37 | {8CA49B9D-9BC4-42CB-B9A4-059D8C936917}.Debug|Any CPU.Build.0 = Debug|Any CPU 38 | {8CA49B9D-9BC4-42CB-B9A4-059D8C936917}.Release|Any CPU.ActiveCfg = Release|Any CPU 39 | {8CA49B9D-9BC4-42CB-B9A4-059D8C936917}.Release|Any CPU.Build.0 = Release|Any CPU 40 | {481A99C8-678F-4367-A50B-E732F6AD05FB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 41 | {481A99C8-678F-4367-A50B-E732F6AD05FB}.Debug|Any CPU.Build.0 = Debug|Any CPU 42 | {481A99C8-678F-4367-A50B-E732F6AD05FB}.Release|Any CPU.ActiveCfg = Release|Any CPU 43 | {481A99C8-678F-4367-A50B-E732F6AD05FB}.Release|Any CPU.Build.0 = Release|Any CPU 44 | {8C2F5DC8-551D-4F14-A5D5-AC6EB4AD8686}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 45 | {8C2F5DC8-551D-4F14-A5D5-AC6EB4AD8686}.Debug|Any CPU.Build.0 = Debug|Any CPU 46 | {8C2F5DC8-551D-4F14-A5D5-AC6EB4AD8686}.Release|Any CPU.ActiveCfg = Release|Any CPU 47 | {8C2F5DC8-551D-4F14-A5D5-AC6EB4AD8686}.Release|Any CPU.Build.0 = Release|Any CPU 48 | EndGlobalSection 49 | GlobalSection(SolutionProperties) = preSolution 50 | HideSolutionNode = FALSE 51 | EndGlobalSection 52 | GlobalSection(ExtensibilityGlobals) = postSolution 53 | SolutionGuid = {509D9A93-C7DF-4D2B-A438-1ECFBB904025} 54 | EndGlobalSection 55 | EndGlobal 56 | -------------------------------------------------------------------------------- /MechaView/SettingManager/SettingManager/SettingManager.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Xml.Linq; 7 | using System.Xml.Serialization; 8 | 9 | namespace SettingManagement 10 | { 11 | public class SettingItem 12 | { 13 | public SettingItem(string name, Type type, object value) 14 | { 15 | if (string.IsNullOrWhiteSpace(name)) 16 | throw new ArgumentNullException(nameof(name)); 17 | if (type == null) 18 | throw new ArgumentNullException(nameof(type)); 19 | 20 | Name = name; 21 | Type = type; 22 | Value = value; 23 | } 24 | public string Name { get; } 25 | public object Value { get; } 26 | public Type Type { get; } 27 | } 28 | 29 | public class Settings 30 | { 31 | public SerializedSettingItem[] Items { get; set; } 32 | } 33 | public class SerializedSettingItem 34 | { 35 | public string Name { get; set; } 36 | public string Value { get; set; } 37 | public TypeCode Type { get; set; } 38 | } 39 | 40 | public static class SettingManager 41 | { 42 | public static void Save(string path, IEnumerable settings) 43 | { 44 | if (string.IsNullOrWhiteSpace(path)) 45 | throw new ArgumentNullException(nameof(path)); 46 | if (settings == null) 47 | throw new ArgumentNullException(nameof(settings)); 48 | 49 | settings.ToDictionary(x => x.Name); 50 | 51 | var items = settings 52 | .Select(x => new SerializedSettingItem 53 | { 54 | Name = x.Name, 55 | Value = x.Value != null 56 | ? (string) Convert.ChangeType(x.Value, TypeCode.String) 57 | : null, 58 | Type = Type.GetTypeCode(x.Type) 59 | }).ToArray(); 60 | 61 | Save(path, new Settings { Items = items }); 62 | } 63 | 64 | public static void Save(string path, object obj) 65 | { 66 | if (string.IsNullOrWhiteSpace(path)) 67 | throw new ArgumentNullException(nameof(path)); 68 | if (obj == null) 69 | throw new ArgumentNullException(nameof(obj)); 70 | 71 | var dir = Path.GetDirectoryName(path); 72 | if (!string.IsNullOrWhiteSpace(dir)) 73 | Directory.CreateDirectory(dir); 74 | 75 | using (var s = new StreamWriter(path)) 76 | { 77 | var xmlSerializer = new XmlSerializer(obj.GetType()); 78 | xmlSerializer.Serialize(s, obj); 79 | } 80 | } 81 | 82 | public static T Load(string path) where T : class, new() 83 | { 84 | if (string.IsNullOrWhiteSpace(path)) 85 | throw new ArgumentNullException(nameof(path)); 86 | 87 | if (File.Exists(path)) 88 | { 89 | using (var s = new StreamReader(path)) 90 | { 91 | var xmlSerializer = new XmlSerializer(typeof(T)); 92 | return xmlSerializer.Deserialize(s) as T; 93 | } 94 | } 95 | return new T(); 96 | } 97 | 98 | public static Dictionary Load(string path) 99 | { 100 | if (string.IsNullOrWhiteSpace(path)) 101 | throw new ArgumentNullException(nameof(path)); 102 | 103 | if (!File.Exists(path)) 104 | return new Dictionary(); 105 | 106 | var s = Load(path); 107 | 108 | return s.Items.ToDictionary( 109 | x => x.Name, 110 | x => !string.IsNullOrWhiteSpace(x.Value) 111 | ? Convert.ChangeType(x.Value, x.Type) 112 | : null); 113 | } 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /MechaView/MechaView.MahApps/tools/MechaView.psm1: -------------------------------------------------------------------------------- 1 | 2 | $nuget = "$PSScriptRoot/nuget.exe" 3 | $vsRoot = "${env:ProgramFiles(x86)}/Microsoft Visual Studio/" 4 | 5 | $ErrorActionPreference = 'stop' 6 | 7 | function Start-App { 8 | param( 9 | [Parameter()] 10 | [Alias('n')] 11 | [string] $Name, 12 | 13 | [Parameter()] 14 | [Alias('a','args','al')] 15 | [string[]] $Arguments 16 | ) 17 | 18 | if (!$Name) {$Name = (Get-Project).name + 'App'} 19 | 20 | $outDir = New-App -name $Name -build 21 | $build = Join-Path $outDir "$Name.exe" 22 | if (!(Test-Path $build)) {throw 'Cannot start the application. '} 23 | 24 | script:Write-Status 'Starting' 25 | Start-Process $build -ArgumentList (@('--debug') + $(if ($Arguments) {$Arguments})) 26 | } 27 | 28 | function New-App { 29 | param( 30 | [Parameter(Mandatory)] 31 | [Alias('n')] 32 | [string] $Name, 33 | 34 | [Parameter(ParameterSetName='Build')] 35 | [Alias('b')] 36 | [switch] $Build, 37 | [Parameter(ParameterSetName='Build')] 38 | [Alias('fw')] 39 | [string] $DotNetVersion, 40 | 41 | [Parameter(ParameterSetName='Publish')] 42 | [Alias('p')] 43 | [switch] $Publish, 44 | [Parameter(Mandatory, ParameterSetName='Publish')] 45 | [Alias('url')] 46 | [string] $InstallUrl) 47 | 48 | $vsFolder = Get-ChildItem $vsRoot | 49 | Where-Object Name -match '^\d+$' | 50 | Sort-Object -Descending | 51 | Get-ChildItem | 52 | Select-Object -First 1 | 53 | ForEach-Object FullName 54 | $msbuild = Join-Path "$vsFolder/" 'MSBuild/Current/Bin/msbuild.exe' 55 | if (!(Test-Path $msbuild)) {throw 'MSBuild.exe not found, please add it to your %PATH%'} 56 | 57 | if (!$Build -and !$Publish) {$Build = $true} 58 | 59 | if ($InstallUrl) {$InstallUrl = $InstallUrl.TrimEnd('\','/')} 60 | 61 | $proj = Get-Project 62 | $proj.Save() 63 | 64 | if (!$DotNetVersion) { 65 | $libTargetFw = $proj.Properties|Where-Object Name -eq 'TargetFrameworkMoniker'|ForEach-Object Value|ForEach-Object Trim 66 | $ver = $libTargetFw -replace '^\.NETFramework,Version=v([\d\.]+)$', '$1' 67 | if (!$ver) {throw '.NET Framework version could not be determined. Please use -DotNetVersion parameter.'} 68 | $DotNetVersion = $ver 69 | } 70 | 71 | $projName = $proj.Name 72 | $conf = 73 | if ($Publish) 74 | {$proj.ConfigurationManager|Where-Object ConfigurationName -eq Release} 75 | else 76 | {$proj.ConfigurationManager.ActiveConfiguration} 77 | 78 | $projAbsDir = [io.path]::GetDirectoryName($proj.FullName) 79 | $projRoot = Resolve-Path -Relative $projAbsDir 80 | $projOut = Join-Path $projRoot $conf.Object.OutputPath 81 | $confName = $conf.ConfigurationName 82 | $projRelPath = Resolve-Path -Relative $proj.FullName 83 | 84 | Set-Location $PSScriptRoot\Mecha.Wpf.Ma.App 85 | Copy-Item (Join-Path $projRoot app.ico) . -Force 86 | 87 | #& $nuget restore -PackagesDirectory ..\..\packages\ 2>&1 | Out-Null 88 | & $nuget restore -PackagesDirectory .\packages\ 2>&1 | Out-Null 89 | 90 | $target = if ($Publish) {'Publish'} else {'Build'} 91 | 92 | script:Write-Status 'Building' 93 | $err = & $msbuild Mecha.Wpf.Ma.App.csproj ` 94 | /t:$target ` 95 | /p:Configuration=$confName ` 96 | /p:Platform=AnyCPU ` 97 | /v:quiet ` 98 | /nologo ` 99 | /clp:ErrorsOnly ` 100 | /p:DotNetVersion="v$DotNetVersion" ` 101 | /p:AppName="$Name" ` 102 | /p:ProjName="$projName" ` 103 | /p:ProjPath="$projRelPath" ` 104 | /p:ProjGuid="{$($proj.Properties.Item('AssemblyGuid').Value)}" ` 105 | /p:ProjOutput="$projOut" 106 | #/p:ProjRoot="$($projRoot)" ` 107 | # /p:AppPublishUrl="$InstallUrl/$projName" 108 | if ($err) {throw $err} 109 | 110 | $projOut 111 | } 112 | 113 | function script:Write-Status($s) {Write-Host $s} 114 | -------------------------------------------------------------------------------- /Samples/Samples/Samples.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {E78B1A54-4D33-4F25-8BCE-B0B753D42A71} 8 | Library 9 | Properties 10 | Samples 11 | Samples 12 | v4.7.2 13 | 512 14 | true 15 | publish\ 16 | true 17 | Disk 18 | false 19 | Foreground 20 | 7 21 | Days 22 | false 23 | false 24 | true 25 | 0 26 | 1.0.0.%2a 27 | false 28 | false 29 | true 30 | 31 | 32 | true 33 | full 34 | false 35 | bin\Debug\ 36 | DEBUG;TRACE 37 | prompt 38 | 4 39 | 40 | 41 | pdbonly 42 | true 43 | bin\Release\ 44 | TRACE 45 | prompt 46 | 4 47 | 48 | 49 | 50 | ..\packages\MechaView.MahApps.0.0.151\lib\net45\Mecha.Core.dll 51 | 52 | 53 | ..\packages\MechaView.MahApps.0.0.151\lib\net45\Mecha.Wpf.Settings.dll 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | False 76 | .NET Framework 3.5 SP1 77 | false 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | -------------------------------------------------------------------------------- /MechaView/Mecha.Wpf.Ma/Mecha.Wpf.Ma.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {481A99C8-678F-4367-A50B-E732F6AD05FB} 8 | library 9 | Mecha.Wpf.Ma 10 | Mecha.Wpf.Ma 11 | v4.5 12 | 512 13 | {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 14 | 4 15 | true 16 | 17 | 18 | true 19 | full 20 | false 21 | bin\Debug\ 22 | DEBUG;TRACE 23 | prompt 24 | 4 25 | 26 | 27 | pdbonly 28 | true 29 | bin\Release\ 30 | TRACE 31 | prompt 32 | 4 33 | 34 | 35 | 36 | ..\packages\ControlzEx.3.0.2.4\lib\net45\ControlzEx.dll 37 | 38 | 39 | ..\packages\MahApps.Metro.1.6.5\lib\net45\MahApps.Metro.dll 40 | 41 | 42 | 43 | 44 | ..\packages\ControlzEx.3.0.2.4\lib\net45\System.Windows.Interactivity.dll 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 4.0 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | Designer 62 | MSBuild:Compile 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | Code 71 | 72 | 73 | 74 | 75 | 76 | {cac4b9fb-05a2-42a1-a18c-2e7de85b404f} 77 | Mecha.Core.Wpf 78 | 79 | 80 | {8ca49b9d-9bc4-42cb-b9a4-059d8c936917} 81 | Mecha.Core 82 | 83 | 84 | {fbcdeb01-6f10-4c49-8618-8a5074dce240} 85 | Mecha.Wpf.Settings 86 | 87 | 88 | 89 | -------------------------------------------------------------------------------- /MechaView/Mecha.Wpf.Ma/WindowHandler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Windows; 3 | using System.ComponentModel; 4 | using MahApps.Metro.Controls; 5 | using MahApps.Metro.Controls.Dialogs; 6 | using Mecha.View.Wpf; 7 | using IO = System.IO; 8 | using System.Windows.Input; 9 | using System.Windows.Controls; 10 | using System.Threading.Tasks; 11 | using Mecha.ViewModel; 12 | using Microsoft.Win32; 13 | using Mecha.Wpf.Settings; 14 | 15 | namespace Mecha.Wpf.Ma 16 | { 17 | public class WindowHandler 18 | { 19 | ControlManager ctrlMan; 20 | private readonly MetroWindow window; 21 | private readonly AppSettings appSettings; 22 | 23 | public WindowHandler(MetroWindow window, AppSettings appSettings) 24 | { 25 | this.window = window ?? throw new ArgumentNullException(nameof(window)); 26 | this.appSettings = appSettings ?? throw new ArgumentNullException(nameof(appSettings)); 27 | 28 | SetWindow(); 29 | } 30 | 31 | void SetWindow() 32 | { 33 | if (!window.IsInitialized) throw new InvalidOperationException("Window has not been initialized"); 34 | 35 | window.TitleCharacterCasing = CharacterCasing.Normal; 36 | window.Title = appSettings.Title; 37 | 38 | var dialogs = new Dialogs(ShowProgress, ShowError, ShowInfo, ShowConfirm); 39 | 40 | var settingPath = IO.Path.Combine( 41 | Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), 42 | "MechaView", 43 | appSettings.GetType().Assembly.GetName().Name, 44 | "settings.conf"); 45 | 46 | ctrlMan = new ControlManager(appSettings.Content, window, settingPath, dialogs); 47 | 48 | window.DataContext = window.Content; 49 | 50 | var w = appSettings.Window.Width > 0 51 | ? appSettings.Window.Width 52 | : 600; 53 | window.MinWidth = w; 54 | window.Width = w; 55 | 56 | var h = appSettings.Window.Height > 0 57 | ? appSettings.Window.Height 58 | : 500; 59 | window.MinHeight = h; 60 | window.Height = h; 61 | 62 | window.Loaded += Window_Loaded; 63 | 64 | window.SizeChanged += Window_SizeChanged; 65 | window.LayoutUpdated += Window_LayoutUpdated; 66 | } 67 | 68 | Task ShowConfirm(string title, string msg, string affirmativeText, string dismissiveText) 69 | { 70 | return window.Dispatcher.Invoke(() => 71 | window.ShowMessageAsync( 72 | title, 73 | msg, 74 | MessageDialogStyle.AffirmativeAndNegative, 75 | new MetroDialogSettings 76 | { 77 | AffirmativeButtonText = affirmativeText, 78 | NegativeButtonText = dismissiveText, 79 | }) 80 | .ContinueWith(x => x.Result == MessageDialogResult.Affirmative)); 81 | } 82 | Task ShowProgress(string title, string msg, bool isCancelable) 83 | { 84 | return window.Dispatcher.Invoke(() => 85 | window.ShowProgressAsync(title, msg, isCancelable)) 86 | .ContinueWith(t => (IMechaProgress)new ProgressDialog(title, msg, isCancelable, t.Result)); 87 | } 88 | Task ShowError(string title, string msg) 89 | { 90 | return window.Dispatcher.Invoke(() => window.ShowMessageAsync(title, msg, MessageDialogStyle.Affirmative)); 91 | } 92 | Task ShowInfo(string title, string msg) 93 | { 94 | return window.Dispatcher.Invoke(() => window.ShowMessageAsync(title, msg, MessageDialogStyle.Affirmative)); 95 | } 96 | 97 | private void Window_SizeChanged(object sender, SizeChangedEventArgs e) 98 | { 99 | ComputeHeight(); 100 | } 101 | 102 | private void Window_LayoutUpdated(object sender, EventArgs e) 103 | { 104 | ComputeHeight(); 105 | } 106 | 107 | void ComputeHeight() 108 | { 109 | if (ctrlMan == null) return; 110 | 111 | if (double.IsNaN(appSettings.Window.Height) || appSettings.Window.Height <= 0) 112 | { 113 | double titleBarHeight = 30; 114 | var margin = window.Margin.Top + window.Margin.Bottom; 115 | var padding = window.Padding.Top + window.Padding.Bottom; 116 | 117 | var h = ctrlMan.ComputeHeight() + margin + padding + titleBarHeight; 118 | window.MinHeight = h; 119 | window.Height = h; 120 | } 121 | } 122 | 123 | private void Window_Loaded(object sender, RoutedEventArgs e) 124 | { 125 | ctrlMan.SetChildControlsLabelWidth(); 126 | 127 | ComputeHeight(); 128 | } 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /MechaView/Mecha.Core.Wpf/View/Wpf/Styles.xaml: -------------------------------------------------------------------------------- 1 | 5 | 6 | 9 | 10 | 5,3,5,3 11 | 11,6,10,6 12 | 13 | 14 | 17 | 18 | 22 | 23 | 27 | 28 | 34 | 35 | 41 | 42 | 47 | 48 | 53 | 54 | 59 | 60 | 65 | 66 | 70 | 71 | 72 | 75 | 76 | 87 | 91 | 95 | 96 | 100 | 103 | 106 | 109 | 110 | 113 | 114 | 117 | 118 | 119 | -------------------------------------------------------------------------------- /MechaView/Mecha.Core.Wpf/View/Wpf/Controls/EnumInput.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Globalization; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | using System.Windows; 9 | using System.Windows.Controls; 10 | using System.Windows.Data; 11 | using System.Windows.Documents; 12 | using System.Windows.Input; 13 | using System.Windows.Media; 14 | using System.Windows.Media.Imaging; 15 | using System.Windows.Navigation; 16 | using System.Windows.Shapes; 17 | using Mecha.Helpers; 18 | using VM = Mecha.ViewModel.Elements; 19 | 20 | namespace Mecha.View.Wpf.Controls 21 | { 22 | /// 23 | /// Interaction logic for EnumInput.xaml 24 | /// 25 | public partial class EnumInput : UserControl, ILabeled 26 | { 27 | public ComboBoxItem[] Items { get; private set; } 28 | 29 | VM.EnumInput vm; 30 | internal VM.EnumInput ViewModel 31 | { 32 | get { return vm; } 33 | set 34 | { 35 | vm = value; 36 | 37 | Items = EnumHelper.GetComboBoxItems(vm.Property.PropertyType); 38 | comboBox.ItemsSource = Items; 39 | 40 | DataContext = vm; 41 | label.DataContext = vm; 42 | 43 | comboBox.DataContext = vm; 44 | comboBox.SetBinding( 45 | ComboBox.SelectedItemProperty, 46 | new Binding(vm.Path) 47 | { 48 | UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged, 49 | Converter = new EnumConverter(vm, Items), 50 | }); 51 | } 52 | } 53 | 54 | public double LabelWidth 55 | { 56 | get { return label.ActualWidth; } 57 | set { label.Width = value; } 58 | } 59 | 60 | public EnumInput() 61 | { 62 | InitializeComponent(); 63 | } 64 | } 65 | 66 | internal class EnumConverter : IValueConverter 67 | { 68 | readonly VM.EnumInput enumInput; 69 | readonly ComboBoxItem[] cbItems; 70 | public EnumConverter(VM.EnumInput enumInput, ComboBoxItem[] cbItems) 71 | { 72 | if (enumInput == null) 73 | throw new ArgumentNullException(nameof(enumInput)); 74 | if (cbItems == null) 75 | throw new ArgumentNullException(nameof(cbItems)); 76 | 77 | this.enumInput = enumInput; 78 | this.cbItems = cbItems; 79 | } 80 | 81 | public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 82 | { 83 | return cbItems.Single(x => x.Name == ((Enum)value).Name()); 84 | } 85 | 86 | public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 87 | { 88 | return ((ComboBoxItem)value).Value; 89 | } 90 | } 91 | 92 | public class ComboBoxItem 93 | { 94 | public string Name { get; set; } 95 | public Enum Value { get; set; } 96 | public string DisplayName { get; set; } 97 | 98 | public override string ToString() 99 | { 100 | return DisplayName; 101 | } 102 | } 103 | 104 | public static class EnumHelper 105 | { 106 | public static string Name(this Enum eValue) 107 | { 108 | if (eValue == null) 109 | throw new ArgumentNullException(nameof(eValue)); 110 | 111 | return Enum.GetName(eValue.GetType(), eValue); 112 | } 113 | 114 | /// 115 | /// Gets the description of a specific enum value. 116 | /// 117 | public static string DisplayName(this Enum eValue) 118 | { 119 | var descAttr = eValue.GetType() 120 | .GetField(eValue.ToString()) 121 | //TODO: support both DescriptionAttribute (tooltip) and DisplayNameAttribute 122 | .GetCustomAttributes(typeof(DescriptionAttribute), false) 123 | .SingleOrDefault() as DescriptionAttribute; 124 | 125 | return descAttr?.Description 126 | ?? Utils.NameToDisplayName(eValue.ToString()); 127 | } 128 | 129 | /// 130 | /// Returns an enumerable collection of all values and descriptions for an enum type. 131 | /// 132 | public static ComboBoxItem[] GetComboBoxItems() where TEnum : struct, IConvertible, IComparable, IFormattable 133 | { 134 | return GetComboBoxItems(typeof(TEnum)); 135 | } 136 | 137 | public static ComboBoxItem[] GetComboBoxItems(Type enumType) 138 | { 139 | if (!enumType.IsEnum) 140 | throw new ArgumentException("TEnum must be an Enumeration type"); 141 | 142 | return Enum.GetValues(enumType) 143 | .Cast() 144 | .Cast() 145 | .Select(e => new ComboBoxItem 146 | { 147 | Name = Enum.GetName(enumType, e), 148 | Value = e, 149 | DisplayName = e.DisplayName() 150 | }) 151 | .ToArray(); 152 | } 153 | } 154 | } 155 | -------------------------------------------------------------------------------- /MechaView/Mecha.Wpf.Ma/Resources.xaml: -------------------------------------------------------------------------------- 1 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 20 | 21 | 22 | 25 | 26 | 47 | 48 | 52 | 53 | 60 | 61 | 68 | 69 | 77 | 78 | 84 | 85 | 92 | 93 | 103 | 104 | 110 | 111 | 112 | -------------------------------------------------------------------------------- /MechaView/Mecha.Core/Mecha.Core.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {8CA49B9D-9BC4-42CB-B9A4-059D8C936917} 8 | Library 9 | Properties 10 | Mecha 11 | Mecha.Core 12 | v4.5 13 | 512 14 | 15 | 16 | true 17 | full 18 | false 19 | .\bin\Debug\ 20 | DEBUG;TRACE 21 | prompt 22 | 4 23 | 24 | 25 | pdbonly 26 | true 27 | .\bin\Release\ 28 | TRACE 29 | prompt 30 | 4 31 | AnyCPU 32 | 33 | 34 | false 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | ..\packages\Castle.Core.4.4.0\lib\net45\Castle.Core.dll 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 107 | -------------------------------------------------------------------------------- /MechaView/Mecha.Core.Wpf/View/Wpf/Controls/PasswordInput.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Linq; 5 | using System.Security.Cryptography; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | using System.Windows; 9 | using System.Windows.Controls; 10 | using System.Windows.Data; 11 | using System.Windows.Documents; 12 | using System.Windows.Input; 13 | using System.Windows.Media; 14 | using System.Windows.Media.Imaging; 15 | using System.Windows.Navigation; 16 | using System.Windows.Shapes; 17 | using VM = Mecha.ViewModel.Elements; 18 | 19 | namespace Mecha.View.Wpf.Controls 20 | { 21 | /// 22 | /// Interaction logic for PasswordInput.xaml 23 | /// 24 | public partial class PasswordInput : UserControl, ILabeled 25 | { 26 | bool isSetup; 27 | 28 | VM.PasswordInput vm; 29 | internal VM.PasswordInput ViewModel 30 | { 31 | get { return vm; } 32 | set 33 | { 34 | if (isSetup) 35 | throw new Exception("ViewModel cannot be set more than once."); 36 | isSetup = true; 37 | 38 | vm = value; 39 | DataContext = vm; 40 | 41 | label.DataContext = vm; 42 | 43 | passBox.DataContext = vm; 44 | //passBox.SetValue(PasswordBoxAssistant.BindPassword, true); 45 | var binding = new Binding(vm.Path) 46 | { 47 | UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged, 48 | Mode = BindingMode.TwoWay, 49 | ValidatesOnExceptions = true, 50 | NotifyOnValidationError = true, 51 | ValidatesOnDataErrors = true 52 | }; 53 | binding.ValidationRules.Add(new MandatoryInputRule(vm) 54 | { 55 | }); 56 | passBox.SetBinding(PasswordBoxAssistant.BoundPassword, binding); 57 | 58 | vm.OnValidation += Validate; 59 | 60 | //passBox.Password = vm.Value as string; 61 | //passBox.PasswordChanged += PassBox_PasswordChanged; 62 | //(vm.Parent.Source as INotifyPropertyChanged).PropertyChanged += Source_PropertyChanged; 63 | } 64 | } 65 | 66 | void Validate(object vm, VM.ValidationResult result) 67 | { 68 | if (string.IsNullOrWhiteSpace(passBox.Password)) 69 | { 70 | //FocusManager.SetFocusedElement(passBox.Parent, passBox); 71 | passBox.Password = " "; 72 | passBox.Password = null; 73 | } 74 | 75 | result.HasError = passBox.GetBindingExpression(PasswordBoxAssistant.BoundPassword).HasError; 76 | } 77 | 78 | //private void PassBox_PasswordChanged(object sender, RoutedEventArgs e) 79 | //{ 80 | // if (passBox.Password != (vm.Value as string)) 81 | // { 82 | // vm.Value = passBox.Password; 83 | // } 84 | //} 85 | 86 | //private void Source_PropertyChanged(object sender, PropertyChangedEventArgs e) 87 | //{ 88 | // if (e.PropertyName == vm.Property.Name && 89 | // passBox.Password != (vm.Value as string)) 90 | // { 91 | // passBox.Dispatcher.Invoke(() => passBox.Password = vm.Value as string); 92 | // } 93 | //} 94 | 95 | public double LabelWidth 96 | { 97 | get { return label.ActualWidth; } 98 | set { label.Width = value; } 99 | } 100 | 101 | public PasswordInput() 102 | { 103 | InitializeComponent(); 104 | } 105 | } 106 | 107 | public static class PasswordBoxAssistant 108 | { 109 | public static readonly DependencyProperty BoundPassword = DependencyProperty.RegisterAttached( 110 | nameof(BoundPassword), 111 | typeof(string), 112 | typeof(PasswordBoxAssistant), 113 | new PropertyMetadata(string.Empty, OnBoundPasswordChanged)); 114 | 115 | private static readonly DependencyProperty UpdatingPassword = DependencyProperty.RegisterAttached( 116 | nameof(UpdatingPassword), 117 | typeof(bool), 118 | typeof(PasswordBoxAssistant), 119 | new PropertyMetadata(false)); 120 | 121 | static void OnBoundPasswordChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 122 | { 123 | var box = (PasswordBox)d; 124 | 125 | // only handle this event when the property is attached to a PasswordBox 126 | // and when the BindPassword attached property has been set to true 127 | if (d == null) 128 | return; 129 | 130 | // avoid recursive updating by ignoring the box's changed event 131 | box.PasswordChanged -= HandlePasswordChanged; 132 | 133 | if (!(bool)box.GetValue(UpdatingPassword)) 134 | { 135 | box.Password = (string)e.NewValue; 136 | } 137 | 138 | box.PasswordChanged += HandlePasswordChanged; 139 | } 140 | 141 | static void HandlePasswordChanged(object sender, RoutedEventArgs e) 142 | { 143 | var box = (PasswordBox)sender; 144 | 145 | // set a flag to indicate that we're updating the password 146 | box.SetValue(UpdatingPassword, true); 147 | // push the new password into the BoundPassword property 148 | box.SetValue(BoundPassword, box.Password); 149 | box.SetValue(UpdatingPassword, false); 150 | } 151 | } 152 | } 153 | -------------------------------------------------------------------------------- /MechaView/Mecha.Core.Wpf/Properties/Resources.resx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | text/microsoft-resx 107 | 108 | 109 | 2.0 110 | 111 | 112 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 113 | 114 | 115 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | -------------------------------------------------------------------------------- /MechaView/Mecha.Wpf.Ma.Dev/Properties/Resources.resx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | text/microsoft-resx 107 | 108 | 109 | 2.0 110 | 111 | 112 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 113 | 114 | 115 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | -------------------------------------------------------------------------------- /MechaView/Mecha.Wpf.Ma.Dev/Mecha.Wpf.Ma.Dev.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {8C2F5DC8-551D-4F14-A5D5-AC6EB4AD8686} 8 | WinExe 9 | Mecha.Wpf.Ma.Dev 10 | Mecha.Wpf.Ma.Dev 11 | v4.5 12 | 512 13 | {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 14 | 4 15 | true 16 | 17 | 18 | AnyCPU 19 | true 20 | full 21 | false 22 | bin\Debug\ 23 | DEBUG;TRACE 24 | prompt 25 | 4 26 | 27 | 28 | AnyCPU 29 | pdbonly 30 | true 31 | bin\Release\ 32 | TRACE 33 | prompt 34 | 4 35 | 36 | 37 | 38 | ..\packages\ControlzEx.3.0.2.4\lib\net45\ControlzEx.dll 39 | 40 | 41 | ..\packages\MahApps.Metro.1.6.5\lib\net45\MahApps.Metro.dll 42 | 43 | 44 | 45 | 46 | ..\packages\ControlzEx.3.0.2.4\lib\net45\System.Windows.Interactivity.dll 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 4.0 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | MSBuild:Compile 64 | Designer 65 | 66 | 67 | MSBuild:Compile 68 | Designer 69 | 70 | 71 | App.xaml 72 | Code 73 | 74 | 75 | 76 | MainWindow.xaml 77 | Code 78 | 79 | 80 | 81 | 82 | Code 83 | 84 | 85 | True 86 | True 87 | Resources.resx 88 | 89 | 90 | True 91 | Settings.settings 92 | True 93 | 94 | 95 | ResXFileCodeGenerator 96 | Resources.Designer.cs 97 | 98 | 99 | 100 | SettingsSingleFileGenerator 101 | Settings.Designer.cs 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | {cac4b9fb-05a2-42a1-a18c-2e7de85b404f} 110 | Mecha.Core.Wpf 111 | 112 | 113 | {8ca49b9d-9bc4-42cb-b9a4-059d8c936917} 114 | Mecha.Core 115 | 116 | 117 | {481a99c8-678f-4367-a50b-e732f6ad05fb} 118 | Mecha.Wpf.Ma 119 | 120 | 121 | {fbcdeb01-6f10-4c49-8618-8a5074dce240} 122 | Mecha.Wpf.Settings 123 | 124 | 125 | 126 | -------------------------------------------------------------------------------- /MechaView/Mecha.Wpf.Ma.Dev/DevApp.cs: -------------------------------------------------------------------------------- 1 | using Mecha.ViewModel.Attributes; 2 | using Mecha.Wpf.Settings; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | public class MechaApp : IApp 10 | { 11 | public void Init(AppSettings s) 12 | { 13 | s.Title = "MechaView Dev"; 14 | s.Window.Width = 450; 15 | s.Content = typeof(Mecha.Wpf.Ma.Dev.ElementGrouping); 16 | s.Window.Accent = Accent.Cobalt; 17 | //s.Window.ColorMode = ColorMode.Light; 18 | } 19 | } 20 | 21 | namespace Mecha.Wpf.Ma.Dev 22 | { 23 | public class DevApp 24 | { 25 | public virtual string StatusLabel { get; set; } 26 | 27 | public virtual string User { get; set; } 28 | public virtual string Password { get; set; } 29 | public virtual DateTime Start { get; set; } = DateTime.Now.Date.AddDays(-1); 30 | public virtual string SaveToPath { get; set; } 31 | 32 | public enum Dimension { ThreeDimensional, TwoDimensional } 33 | public virtual Dimension PointDimension { get; set; } 34 | 35 | public virtual bool FilterOutNegative { get; set; } 36 | public virtual Point[] Points { get; set; } 37 | 38 | public async Task GetPoints() 39 | { 40 | StatusLabel = $"Getting points since {Start}..."; 41 | await Task.Delay(1500); 42 | 43 | Points = Enumerable.Range(-10, 90) 44 | .Select(i => new Point { X = i, Y = i + 10, Z = PointDimension == Dimension.ThreeDimensional ? i * 10 : 0 }) 45 | .Where(x => !FilterOutNegative || (x.X >= 0 && x.Y >= 0 && x.Z >= 0)) 46 | .ToArray(); 47 | 48 | if (SaveToPath != null) 49 | { 50 | StatusLabel = $"Saving points to {SaveToPath}..."; 51 | await Task.Delay(1000); 52 | } 53 | 54 | StatusLabel = "Success!"; 55 | } 56 | } 57 | 58 | public class DevApp2 59 | { 60 | enum Grp 61 | { 62 | Input, 63 | [Group(invisible: true)] Result 64 | } 65 | 66 | // 67 | // User 68 | // 69 | 70 | [Element(Group = Grp.Input, Position = 0.0)] 71 | public virtual string User { get; set; } 72 | 73 | [Element(Group = Grp.Input, Position = 0.1)] 74 | public virtual string Password { get; set; } 75 | 76 | [Element(Group = Grp.Input, Position = 1)] 77 | public virtual bool FilterOutNegative { get; set; } 78 | 79 | [Element(Group = Grp.Input, Position = 2)] 80 | public virtual string SaveToPath { get; set; } 81 | 82 | public enum PointDimension { ThreeDimensional, TwoDimensional } 83 | [Element(Group = Grp.Input, Position = 3.0)] 84 | public virtual DateTime Start { get; set; } = DateTime.Now.AddDays(-1); 85 | 86 | [Element(Group = Grp.Input, Position = 3.1)] 87 | public virtual PointDimension Dimension { get; set; } 88 | 89 | [Element(Group = Grp.Input)] 90 | public void Clear() 91 | { 92 | User = Password = SaveToPath = null; 93 | } 94 | 95 | // 96 | // Result 97 | // 98 | 99 | [Element(Group = Grp.Result)] 100 | public virtual string StatusLabel { get; set; } 101 | 102 | [Element(Group = Grp.Result)] 103 | public virtual Point[] Points { get; set; } 104 | 105 | public async Task GetPoints() 106 | { 107 | StatusLabel = $"Getting points since {Start}..."; 108 | await Task.Delay(1500); 109 | 110 | Points = Enumerable.Range(-10, 90) 111 | .Select(i => new Point { X = i, Y = i + 10, Z = Dimension == PointDimension.ThreeDimensional ? i * 10 : 0 }) 112 | .Where(x => !FilterOutNegative || (x.X >= 0 && x.Y >= 0 && x.Z >= 0)) 113 | .ToArray(); 114 | 115 | StatusLabel = "Success!"; 116 | } 117 | } 118 | 119 | 120 | public class ElementGrouping 121 | { 122 | enum Grp 123 | { 124 | Input, 125 | [Group(invisible: true)] Result 126 | } 127 | 128 | // 129 | // User 130 | // 131 | 132 | [Element(Group = Grp.Input, Position = 0.0)] 133 | public virtual string User { get; set; } 134 | 135 | [Element(Group = Grp.Input, Position = 0.1)] 136 | public virtual string Password { get; set; } 137 | 138 | [Element(Group = Grp.Input, Position = 1)] 139 | public virtual bool FilterOutNegative { get; set; } 140 | 141 | [Element(Group = Grp.Input, Position = 2)] 142 | public virtual string SaveToPath { get; set; } 143 | 144 | public enum PointDimension { ThreeDimensional, TwoDimensional } 145 | [Element(Group = Grp.Input, Position = 3.0)] 146 | public virtual DateTime Start { get; set; } = DateTime.Now.AddDays(-1); 147 | 148 | [Element(Group = Grp.Input, Position = 3.1)] 149 | public virtual PointDimension Dimension { get; set; } 150 | 151 | [Element(Group = Grp.Input)] 152 | public void Clear() 153 | { 154 | User = Password = SaveToPath = null; 155 | } 156 | 157 | // 158 | // Result 159 | // 160 | 161 | [Element(Group = Grp.Result)] 162 | public virtual string StatusLabel { get; set; } 163 | 164 | [Element(Group = Grp.Result)] 165 | public virtual Point[] Points { get; set; } 166 | 167 | public async Task GetPoints() 168 | { 169 | StatusLabel = $"Getting points since {Start}..."; 170 | await Task.Delay(1500); 171 | 172 | Points = Enumerable.Range(-10, 90) 173 | .Select(i => new Point { X = i, Y = i + 10, Z = Dimension == PointDimension.ThreeDimensional ? i * 10 : 0 }) 174 | .Where(x => !FilterOutNegative || (x.X >= 0 && x.Y >= 0 && x.Z >= 0)) 175 | .ToArray(); 176 | 177 | StatusLabel = "Success!"; 178 | } 179 | } 180 | 181 | 182 | public struct Point 183 | { 184 | public int X { get; set; } 185 | public int Y { get; set; } 186 | public int Z { get; set; } 187 | } 188 | } 189 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | nuget.exe 7 | lib/ 8 | 9 | # User-specific files 10 | *.rsuser 11 | *.suo 12 | *.user 13 | *.userosscache 14 | *.sln.docstates 15 | 16 | # User-specific files (MonoDevelop/Xamarin Studio) 17 | *.userprefs 18 | 19 | # Build results 20 | [Dd]ebug/ 21 | [Dd]ebugPublic/ 22 | [Rr]elease/ 23 | [Rr]eleases/ 24 | x64/ 25 | x86/ 26 | [Aa][Rr][Mm]/ 27 | [Aa][Rr][Mm]64/ 28 | bld/ 29 | [Bb]in/ 30 | [Oo]bj/ 31 | [Ll]og/ 32 | 33 | # Visual Studio 2015/2017 cache/options directory 34 | .vs/ 35 | # Uncomment if you have tasks that create the project's static files in wwwroot 36 | #wwwroot/ 37 | 38 | # Visual Studio 2017 auto generated files 39 | Generated\ Files/ 40 | 41 | # MSTest test Results 42 | [Tt]est[Rr]esult*/ 43 | [Bb]uild[Ll]og.* 44 | 45 | # NUNIT 46 | *.VisualState.xml 47 | TestResult.xml 48 | 49 | # Build Results of an ATL Project 50 | [Dd]ebugPS/ 51 | [Rr]eleasePS/ 52 | dlldata.c 53 | 54 | # Benchmark Results 55 | BenchmarkDotNet.Artifacts/ 56 | 57 | # .NET Core 58 | project.lock.json 59 | project.fragment.lock.json 60 | artifacts/ 61 | 62 | # StyleCop 63 | StyleCopReport.xml 64 | 65 | # Files built by Visual Studio 66 | *_i.c 67 | *_p.c 68 | *_h.h 69 | *.ilk 70 | *.meta 71 | *.obj 72 | *.iobj 73 | *.pch 74 | *.pdb 75 | *.ipdb 76 | *.pgc 77 | *.pgd 78 | *.rsp 79 | *.sbr 80 | *.tlb 81 | *.tli 82 | *.tlh 83 | *.tmp 84 | *.tmp_proj 85 | *_wpftmp.csproj 86 | *.log 87 | *.vspscc 88 | *.vssscc 89 | .builds 90 | *.pidb 91 | *.svclog 92 | *.scc 93 | 94 | # Chutzpah Test files 95 | _Chutzpah* 96 | 97 | # Visual C++ cache files 98 | ipch/ 99 | *.aps 100 | *.ncb 101 | *.opendb 102 | *.opensdf 103 | *.sdf 104 | *.cachefile 105 | *.VC.db 106 | *.VC.VC.opendb 107 | 108 | # Visual Studio profiler 109 | *.psess 110 | *.vsp 111 | *.vspx 112 | *.sap 113 | 114 | # Visual Studio Trace Files 115 | *.e2e 116 | 117 | # TFS 2012 Local Workspace 118 | $tf/ 119 | 120 | # Guidance Automation Toolkit 121 | *.gpState 122 | 123 | # ReSharper is a .NET coding add-in 124 | _ReSharper*/ 125 | *.[Rr]e[Ss]harper 126 | *.DotSettings.user 127 | 128 | # JustCode is a .NET coding add-in 129 | .JustCode 130 | 131 | # TeamCity is a build add-in 132 | _TeamCity* 133 | 134 | # DotCover is a Code Coverage Tool 135 | *.dotCover 136 | 137 | # AxoCover is a Code Coverage Tool 138 | .axoCover/* 139 | !.axoCover/settings.json 140 | 141 | # Visual Studio code coverage results 142 | *.coverage 143 | *.coveragexml 144 | 145 | # NCrunch 146 | _NCrunch_* 147 | .*crunch*.local.xml 148 | nCrunchTemp_* 149 | 150 | # MightyMoose 151 | *.mm.* 152 | AutoTest.Net/ 153 | 154 | # Web workbench (sass) 155 | .sass-cache/ 156 | 157 | # Installshield output folder 158 | [Ee]xpress/ 159 | 160 | # DocProject is a documentation generator add-in 161 | DocProject/buildhelp/ 162 | DocProject/Help/*.HxT 163 | DocProject/Help/*.HxC 164 | DocProject/Help/*.hhc 165 | DocProject/Help/*.hhk 166 | DocProject/Help/*.hhp 167 | DocProject/Help/Html2 168 | DocProject/Help/html 169 | 170 | # Click-Once directory 171 | publish/ 172 | 173 | # Publish Web Output 174 | *.[Pp]ublish.xml 175 | *.azurePubxml 176 | # Note: Comment the next line if you want to checkin your web deploy settings, 177 | # but database connection strings (with potential passwords) will be unencrypted 178 | *.pubxml 179 | *.publishproj 180 | 181 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 182 | # checkin your Azure Web App publish settings, but sensitive information contained 183 | # in these scripts will be unencrypted 184 | PublishScripts/ 185 | 186 | # NuGet Packages 187 | *.nupkg 188 | # The packages folder can be ignored because of Package Restore 189 | **/[Pp]ackages/* 190 | # except build/, which is used as an MSBuild target. 191 | !**/[Pp]ackages/build/ 192 | # Uncomment if necessary however generally it will be regenerated when needed 193 | #!**/[Pp]ackages/repositories.config 194 | # NuGet v3's project.json files produces more ignorable files 195 | *.nuget.props 196 | *.nuget.targets 197 | 198 | # Microsoft Azure Build Output 199 | csx/ 200 | *.build.csdef 201 | 202 | # Microsoft Azure Emulator 203 | ecf/ 204 | rcf/ 205 | 206 | # Windows Store app package directories and files 207 | AppPackages/ 208 | BundleArtifacts/ 209 | Package.StoreAssociation.xml 210 | _pkginfo.txt 211 | *.appx 212 | 213 | # Visual Studio cache files 214 | # files ending in .cache can be ignored 215 | *.[Cc]ache 216 | # but keep track of directories ending in .cache 217 | !?*.[Cc]ache/ 218 | 219 | # Others 220 | ClientBin/ 221 | ~$* 222 | *~ 223 | *.dbmdl 224 | *.dbproj.schemaview 225 | *.jfm 226 | *.pfx 227 | *.publishsettings 228 | orleans.codegen.cs 229 | 230 | # Including strong name files can present a security risk 231 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 232 | #*.snk 233 | 234 | # Since there are multiple workflows, uncomment next line to ignore bower_components 235 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 236 | #bower_components/ 237 | 238 | # RIA/Silverlight projects 239 | Generated_Code/ 240 | 241 | # Backup & report files from converting an old project file 242 | # to a newer Visual Studio version. Backup files are not needed, 243 | # because we have git ;-) 244 | _UpgradeReport_Files/ 245 | Backup*/ 246 | UpgradeLog*.XML 247 | UpgradeLog*.htm 248 | ServiceFabricBackup/ 249 | *.rptproj.bak 250 | 251 | # SQL Server files 252 | *.mdf 253 | *.ldf 254 | *.ndf 255 | 256 | # Business Intelligence projects 257 | *.rdl.data 258 | *.bim.layout 259 | *.bim_*.settings 260 | *.rptproj.rsuser 261 | *- Backup*.rdl 262 | 263 | # Microsoft Fakes 264 | FakesAssemblies/ 265 | 266 | # GhostDoc plugin setting file 267 | *.GhostDoc.xml 268 | 269 | # Node.js Tools for Visual Studio 270 | .ntvs_analysis.dat 271 | node_modules/ 272 | 273 | # Visual Studio 6 build log 274 | *.plg 275 | 276 | # Visual Studio 6 workspace options file 277 | *.opt 278 | 279 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 280 | *.vbw 281 | 282 | # Visual Studio LightSwitch build output 283 | **/*.HTMLClient/GeneratedArtifacts 284 | **/*.DesktopClient/GeneratedArtifacts 285 | **/*.DesktopClient/ModelManifest.xml 286 | **/*.Server/GeneratedArtifacts 287 | **/*.Server/ModelManifest.xml 288 | _Pvt_Extensions 289 | 290 | # Paket dependency manager 291 | .paket/paket.exe 292 | paket-files/ 293 | 294 | # FAKE - F# Make 295 | .fake/ 296 | 297 | # JetBrains Rider 298 | .idea/ 299 | *.sln.iml 300 | 301 | # CodeRush personal settings 302 | .cr/personal 303 | 304 | # Python Tools for Visual Studio (PTVS) 305 | __pycache__/ 306 | *.pyc 307 | 308 | # Cake - Uncomment if you are using it 309 | # tools/** 310 | # !tools/packages.config 311 | 312 | # Tabs Studio 313 | *.tss 314 | 315 | # Telerik's JustMock configuration file 316 | *.jmconfig 317 | 318 | # BizTalk build output 319 | *.btp.cs 320 | *.btm.cs 321 | *.odx.cs 322 | *.xsd.cs 323 | 324 | # OpenCover UI analysis results 325 | OpenCover/ 326 | 327 | # Azure Stream Analytics local run output 328 | ASALocalRun/ 329 | 330 | # MSBuild Binary and Structured Log 331 | *.binlog 332 | 333 | # NVidia Nsight GPU debugger configuration file 334 | *.nvuser 335 | 336 | # MFractors (Xamarin productivity tool) working folder 337 | .mfractor/ 338 | 339 | # Local History for Visual Studio 340 | .localhistory/ 341 | 342 | # BeatPulse healthcheck temp database 343 | healthchecksdb -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MechaView 2 | 3 | Write plain C#, get a single exe WPF app. The project is intended for simple tools. 4 | 5 | ## Run it 6 | 1. Create a class library (.NET Framework 4.5+) 7 | 2. Add the [nuget](https://www.nuget.org/packages/MechaView.MahApps/0.0.152) 8 | 3. Define your view model (see below) 9 | 4. Run `start-app` from Package Manager Console 10 | 5. Get the exe inside your bin folder (ignore the other files) 11 | 12 | ## Basics 13 | The application consists of your view model and the `App` class defined in the global namespace. It has to both have the exact name and implement the `IApp` interface. 14 | 15 | ```csharp 16 | using System; 17 | using Mecha.Wpf.Settings; 18 | 19 | public class App : IApp 20 | { 21 | public void Init(AppSettings s) 22 | { 23 | s.Title = "Basics"; 24 | s.Window.Width = 450; 25 | s.Content = typeof(BasicsVM); 26 | } 27 | } 28 | public class BasicsVM 29 | { 30 | public virtual string Label { get; set; } 31 | public void SetLabel() { Label = DateTime.Now.ToString(); } 32 | } 33 | ``` 34 | ![Basics](docs/basics-light.png) 35 | ![Basics](docs/basics-dark.png) 36 | 37 | ## Element Conventions 38 | Conventions affect how each property is represented and are defined for both types and names. In simple cases, we may rely solely on them. The following example uses the keywords Label, Password, and Path. The remaining controls are derived from the property types. 39 | 40 | ```csharp 41 | public class ElementConventionsVM 42 | { 43 | public virtual string StatusLabel { get; set; } 44 | 45 | public virtual string User { get; set; } 46 | public virtual string Password { get; set; } 47 | public virtual DateTime Start { get; set; } 48 | public virtual string SaveToPath { get; set; } 49 | public enum Dimension { ThreeDimensional, TwoDimensional } 50 | public virtual Dimension PointDimension { get; set; } 51 | public virtual bool FilterOutNegative { get; set; } 52 | 53 | public virtual Point[] Points { get; set; } 54 | 55 | public async Task GetPoints() { . . . } 56 | } 57 | ``` 58 | ![Conventions Light](docs/conventions-light.png) 59 | 60 | ## Element Decoration 61 | 62 | A property can be decorated with a matching attribute, which also lets us specify the additional configuration. In the example below, we set most of the text inputs to remember their value by specifying the `Persistent` flag. On the `File` property, we restrict the file dialog only to certain file types. 63 | 64 | ```csharp 65 | public class InputDecorationVM 66 | { 67 | [Readonly] 68 | public virtual string Status { get; set; } 69 | 70 | [TextInput] 71 | public virtual string User { get; set; } 72 | 73 | [Password(Persistent = true)] 74 | public virtual string Pass { get; set; } 75 | 76 | [TextInput(Persistent = true, Multiline = true)] 77 | public virtual string Description { get; set; } 78 | 79 | [DateInput(Persistent = true)] 80 | public virtual DateTime Start { get; set; } = DateTime.Now; 81 | 82 | [Path("txt", "md", Type = PathType.Open, Persistent = true)] 83 | public virtual string File { get; set; } 84 | } 85 | ``` 86 | ![Conventions Light](docs/decoration-light.png) 87 | 88 | 89 | ## Input Validation 90 | 91 | Each input property can be marked as `Mandatory`. Doing so prevents all default actions (i.e. methods) to run as long as the mandatory inputs are empty. An action can be specified as unbound by setting `DisableValidtion`. 92 | 93 | ```csharp 94 | public class InputValidationVM 95 | { 96 | [TextInput(Mandatory = true, Description = "User name")] 97 | public virtual string User { get; set; } 98 | 99 | public void BoundAction() { } 100 | 101 | [Action(DisableValidation = true)] 102 | public void UnboundAction() { } 103 | } 104 | ``` 105 | 106 | ![Conventions Light](docs/validation-light.png) 107 | 108 | ## Action Dialogs 109 | There are static and dynamic dialogs. Static ones are specified by decorating an action (i.e. method) with the `Confirm`, `Progress`, or `Message` attributes. Dynamic dialogs are specified by defining an `IMechaMessage` or `IMechaProgress` (or both) parameters. The method can return either `void` or `Task`. If a progress dialog is specified, it is shown until the method finishes. 110 | 111 | ```csharp 112 | public class ActionDialogsVM 113 | { 114 | public virtual string StatusLabel { get; set; } 115 | 116 | [Confirm("Confirmation", "Continue?")] 117 | [Progress("Static Progress", "Processing...")] 118 | [Message("Static Message", "Done")] 119 | public async Task StaticAll() 120 | { 121 | await Task.Delay(1500); 122 | } 123 | 124 | public void DynamicMessage(IMechaMessage msg) 125 | { 126 | msg.Title = "Dynamic Message"; 127 | msg.Message = "Done at " + DateTime.Now.ToShortTimeString(); 128 | } 129 | 130 | public async Task DynamicProgress(IMechaProgress prog) 131 | { 132 | prog.Title = "Dynamic Progress"; 133 | prog.IsCancelable = true; 134 | 135 | for (int i = 0; !prog.IsCanceled && i < 100; i++) 136 | { 137 | prog.Progress = .01 * i; 138 | prog.Message = $"Processing... ({i}%)"; 139 | await Task.Delay(10); 140 | } 141 | } 142 | 143 | public void ThrowError() 144 | { 145 | throw new Exception("Invalid something"); 146 | } 147 | } 148 | ``` 149 | 150 | ![Conventions Light](docs/dial-confirm-light.png) 151 | ![Conventions Light](docs/dial-msg-light.png) 152 | ![Conventions Light](docs/dial-dynprog-light.png) 153 | ![Conventions Light](docs/dial-err-light.png) 154 | 155 | 156 | ## Element Grouping 157 | 158 | Each element can be grouped by specifying `Group` and ordered within the group by setting `Position` . `Position` is of type double where the integer part represents a row and the fraction part represents a column. Keep in mind that each value represents order and not a fixed position. 159 | 160 | ```csharp 161 | public class ElementGroupingVM 162 | { 163 | enum Grp 164 | { 165 | Input, 166 | [Group(invisible: true)] Result 167 | } 168 | 169 | // 170 | // Input 171 | // 172 | 173 | [Element(Group = Grp.Input, Position = 0.0)] 174 | public virtual string User { get; set; } 175 | 176 | [Element(Group = Grp.Input, Position = 0.1)] 177 | public virtual string Password { get; set; } 178 | 179 | [Element(Group = Grp.Input, Position = 1)] 180 | public virtual bool FilterOutNegative { get; set; } 181 | 182 | [Element(Group = Grp.Input, Position = 2)] 183 | public virtual string SaveToPath { get; set; } 184 | 185 | public enum PointDimension { ThreeDimensional, TwoDimensional } 186 | [Element(Group = Grp.Input, Position = 3.0)] 187 | public virtual DateTime Start { get; set; } = DateTime.Now.AddDays(-1); 188 | 189 | [Element(Group = Grp.Input, Position = 3.1)] 190 | public virtual PointDimension Dimension { get; set; } 191 | 192 | [Element(Group = Grp.Input)] 193 | public void Clear() 194 | { 195 | User = Password = SaveToPath = null; 196 | } 197 | 198 | // 199 | // Result 200 | // 201 | 202 | [Element(Group = Grp.Result)] 203 | public virtual string StatusLabel { get; set; } 204 | 205 | [Element(Group = Grp.Result)] 206 | public virtual Point[] Points { get; set; } 207 | 208 | public async Task GetPoints() { . . . } 209 | } 210 | ``` 211 | 212 | ![Conventions Light](docs/grouping-light.png) 213 | 214 | 215 | ## Full Examples 216 | Get the above examples in the `Samples` folder. 217 | 218 | 219 | ## License 220 | 221 | [MIT](LICENSE) 222 | --------------------------------------------------------------------------------