From 2576ff2ca28573f71dc7ba300bfaa56caabcf0cb Mon Sep 17 00:00:00 2001 From: Darth Affe Date: Thu, 25 May 2017 20:50:00 +0200 Subject: [PATCH] Moved away from Caliburn and Added some basic stuff with ReactiveUI (I'm not quite happy with everything so far, but it seems like I'm to stupid to understand how to correctly use routing with the layout I want) --- Arge/App.xaml | 4 - Arge/App.xaml.cs | 36 +++++++- Arge/Arge.csproj | 59 +++++++----- Arge/Arge.csproj.DotSettings | 2 + Arge/Bootstrapper/ArgeBootstrapper.cs | 43 ++++++--- Arge/Bootstrapper/ArgeWindowManager.cs | 48 ---------- Arge/Bootstrapper/NavigationManager.cs | 90 +++++++++++++++++++ Arge/Bootstrapper/UnityBootstrapper.cs | 62 ++++++------- Arge/Bootstrapper/UnityDependencyResolver.cs | 55 ++++++++++++ Arge/Controls/{ => Buttons}/ImageButton.cs | 2 +- .../{ => Window}/BlurredDecorationWindow.cs | 4 +- Arge/Enums/NavigationTargets.cs | 11 +++ Arge/Misc/AbstractBindable.cs | 44 --------- Arge/Misc/ActionCommand.cs | 50 ----------- Arge/Misc/BindingProxy.cs | 28 ------ Arge/Resources/Arge.xaml | 7 +- Arge/Resources/ImageSources.cs | 7 +- Arge/Styles/BlurredDecorationWindow.xaml | 20 ++--- Arge/Styles/ImageButton.xaml | 14 +-- Arge/Themes/Theme.cs | 4 +- Arge/ViewModels/AbstractViewModel.cs | 13 +++ Arge/ViewModels/NavigationViewModel.cs | 7 ++ Arge/ViewModels/ShellViewModel.cs | 28 +++++- Arge/Views/AbstractView.cs | 17 ++++ Arge/Views/NavigationView.xaml | 14 +++ Arge/Views/NavigationView.xaml.cs | 18 ++++ Arge/Views/ShellView.xaml | 31 ++++--- Arge/Views/ShellView.xaml.cs | 16 +++- Arge/packages.config | 12 ++- 29 files changed, 464 insertions(+), 282 deletions(-) create mode 100644 Arge/Arge.csproj.DotSettings delete mode 100644 Arge/Bootstrapper/ArgeWindowManager.cs create mode 100644 Arge/Bootstrapper/NavigationManager.cs create mode 100644 Arge/Bootstrapper/UnityDependencyResolver.cs rename Arge/Controls/{ => Buttons}/ImageButton.cs (98%) rename Arge/Controls/{ => Window}/BlurredDecorationWindow.cs (97%) create mode 100644 Arge/Enums/NavigationTargets.cs delete mode 100644 Arge/Misc/AbstractBindable.cs delete mode 100644 Arge/Misc/ActionCommand.cs delete mode 100644 Arge/Misc/BindingProxy.cs create mode 100644 Arge/ViewModels/AbstractViewModel.cs create mode 100644 Arge/ViewModels/NavigationViewModel.cs create mode 100644 Arge/Views/AbstractView.cs create mode 100644 Arge/Views/NavigationView.xaml create mode 100644 Arge/Views/NavigationView.xaml.cs diff --git a/Arge/App.xaml b/Arge/App.xaml index 92036f5..bd13693 100644 --- a/Arge/App.xaml +++ b/Arge/App.xaml @@ -1,14 +1,10 @@  - - - diff --git a/Arge/App.xaml.cs b/Arge/App.xaml.cs index d44d326..7f9120b 100644 --- a/Arge/App.xaml.cs +++ b/Arge/App.xaml.cs @@ -1,7 +1,41 @@ using System.Windows; +using Arge.Bootstrapper; namespace Arge { public partial class App : Application - { } + { + #region Properties & Fields + + private readonly ArgeBootstrapper _bootstrapper; + + #endregion + + #region Constructors + + public App() + { + _bootstrapper = new ArgeBootstrapper(); + } + + #endregion + + #region Methods + + protected override void OnStartup(StartupEventArgs e) + { + base.OnStartup(e); + + _bootstrapper.OnStartup(e); + } + + protected override void OnExit(ExitEventArgs e) + { + base.OnExit(e); + + _bootstrapper.OnExit(e); + } + + #endregion + } } diff --git a/Arge/Arge.csproj b/Arge/Arge.csproj index 2f570f6..d565bee 100644 --- a/Arge/Arge.csproj +++ b/Arge/Arge.csproj @@ -36,15 +36,6 @@ Resources\ArgeBee.ico - - ..\packages\Caliburn.Micro.Core.3.0.3\lib\net45\Caliburn.Micro.dll - - - ..\packages\Caliburn.Micro.3.0.3\lib\net45\Caliburn.Micro.Platform.dll - - - ..\packages\Caliburn.Micro.3.0.3\lib\net45\Caliburn.Micro.Platform.Core.dll - ..\packages\CommonServiceLocator.1.3\lib\portable-net4+sl5+netcore45+wpa81+wp8\Microsoft.Practices.ServiceLocation.dll @@ -57,18 +48,38 @@ ..\packages\Unity.4.0.1\lib\net45\Microsoft.Practices.Unity.RegistrationByConvention.dll + + ..\packages\reactiveui-core.7.3.0\lib\Net45\ReactiveUI.dll + + + ..\packages\reactiveui-events.7.3.0\lib\Net45\ReactiveUI.Events.dll + ..\packages\RGB.NET.Core.1.0.0\lib\net45\RGB.NET.Core.dll + + ..\packages\Splat.1.4.0\lib\Net45\Splat.dll + - - - ..\packages\Caliburn.Micro.3.0.3\lib\net45\System.Windows.Interactivity.dll - True + + ..\packages\Rx-Core.2.2.5\lib\net45\System.Reactive.Core.dll + + ..\packages\Rx-Interfaces.2.2.5\lib\net45\System.Reactive.Interfaces.dll + + + ..\packages\Rx-Linq.2.2.5\lib\net45\System.Reactive.Linq.dll + + + ..\packages\Rx-PlatformServices.2.2.5\lib\net45\System.Reactive.PlatformServices.dll + + + ..\packages\Rx-XAML.2.2.5\lib\net45\System.Reactive.Windows.Threading.dll + + @@ -92,21 +103,26 @@ Code - + + - - + + + - - - + + + + + NavigationView.xaml + ShellView.xaml @@ -141,7 +157,6 @@ - @@ -172,6 +187,10 @@ Designer Always + + Designer + MSBuild:Compile + Designer MSBuild:Compile diff --git a/Arge/Arge.csproj.DotSettings b/Arge/Arge.csproj.DotSettings new file mode 100644 index 0000000..2b43c4a --- /dev/null +++ b/Arge/Arge.csproj.DotSettings @@ -0,0 +1,2 @@ + + True \ No newline at end of file diff --git a/Arge/Bootstrapper/ArgeBootstrapper.cs b/Arge/Bootstrapper/ArgeBootstrapper.cs index 22aaef8..6aeb276 100644 --- a/Arge/Bootstrapper/ArgeBootstrapper.cs +++ b/Arge/Bootstrapper/ArgeBootstrapper.cs @@ -1,10 +1,14 @@ -using System.Collections.Generic; +using System; +using System.Diagnostics; using System.Windows; +using System.Windows.Media.Imaging; using Arge.Configuration; +using Arge.Controls.Window; using Arge.Themes; using Arge.ViewModels; -using Caliburn.Micro; +using Arge.Views; using Microsoft.Practices.Unity; +using ReactiveUI; namespace Arge.Bootstrapper { @@ -14,23 +18,40 @@ namespace Arge.Bootstrapper protected override void RegisterTypes() { - RegisterInterface(); + RegisterServices(); + RegisterViews(); + } + private void RegisterServices() + { RegisterSingleton(); } - protected override void OnStartup(object sender, StartupEventArgs e) + private void RegisterViews() + { + RegisterView(); + RegisterView(); + } + + protected override void InitializeHandlers() + { + } + + protected override void Start() { Config.Instance.Load(); Container.Resolve().LoadTheme(Config.Instance[ConfigEntryType.Theme]); - Dictionary settings = new Dictionary - { - { "Title", "Arge" }, - { "Width" , 1280 }, - { "Height" , 720 } - }; - DisplayRootViewFor(settings); + BlurredDecorationWindow window = new BlurredDecorationWindow + { + Width = 1280, + Height = 720, + Icon = new BitmapImage(new Uri("pack://application:,,,/Arge;component/Resources/ArgeBee.ico")), + IconCommand = ReactiveCommand.Create(() => Process.Start("http://arge.be")), + Content = Container.Resolve() + }; + Application.Current.MainWindow = window; + window.Show(); } #endregion diff --git a/Arge/Bootstrapper/ArgeWindowManager.cs b/Arge/Bootstrapper/ArgeWindowManager.cs deleted file mode 100644 index 2fdc1f4..0000000 --- a/Arge/Bootstrapper/ArgeWindowManager.cs +++ /dev/null @@ -1,48 +0,0 @@ -using System; -using System.Diagnostics; -using System.Windows; -using System.Windows.Media.Imaging; -using Arge.Controls; -using Arge.Misc; -using Caliburn.Micro; - -namespace Arge.Bootstrapper -{ - public class ArgeWindowManager : WindowManager - { - #region Methods - - protected override Window EnsureWindow(object model, object view, bool isDialog) - { - Window window = view as Window; - if (window == null) - { - window = new BlurredDecorationWindow() - { - Content = view, - SizeToContent = SizeToContent.Manual, - Icon = new BitmapImage(new Uri("pack://application:,,,/Arge;component/Resources/ArgeBee.ico")), - IconCommand = new ActionCommand(() => Process.Start("http://arge.be")) - }; - window.SetValue(View.IsGeneratedProperty, true); - Window owner = InferOwnerOf(window); - if (owner != null) - { - window.WindowStartupLocation = WindowStartupLocation.CenterOwner; - window.Owner = owner; - } - else - window.WindowStartupLocation = WindowStartupLocation.CenterScreen; - } - else - { - Window owner = InferOwnerOf(window); - if ((owner != null) && isDialog) - window.Owner = owner; - } - return window; - } - - #endregion - } -} diff --git a/Arge/Bootstrapper/NavigationManager.cs b/Arge/Bootstrapper/NavigationManager.cs new file mode 100644 index 0000000..2b47fe3 --- /dev/null +++ b/Arge/Bootstrapper/NavigationManager.cs @@ -0,0 +1,90 @@ +using System; +using System.Collections.Generic; +using Arge.Enums; +using Microsoft.Practices.Unity; + +namespace Arge.Bootstrapper +{ + //TODO DarthAffe 21.05.2017: This allows some sort of fake VM-first - One day I should make this cleaner ... + public class NavigationManager + { + #region Properties & Fields + + public static NavigationManager Instance { get; private set; } + + private readonly Dictionary _viewTypeMapping = new Dictionary(); + + private readonly IUnityContainer _container; + + public object Navigation { get; private set; } + public object Layers { get; private set; } + public object Selection { get; private set; } + public object Action { get; private set; } + public object Surface { get; private set; } + + #endregion + + #region Constructors + + private NavigationManager(IUnityContainer container) + { + this._container = container; + } + + #endregion + + #region Methods + + public static void Initialize(IUnityContainer container) + { + Instance = new NavigationManager(container); + } + + public void RegisterViewTypes(Type viewType, Type viewModelType) + { + _viewTypeMapping[viewModelType] = viewType; + } + + public void Navigate(NavigationTargets target) + { + Navigate(target, typeof(TTarget)); + } + + public void Navigate(NavigationTargets target, Type targetType) + { + Type viewType; + if (!_viewTypeMapping.TryGetValue(targetType, out viewType)) + viewType = targetType; + + Navigate(target, _container.Resolve(viewType)); + } + + public void Navigate(NavigationTargets target, object view) + { + switch (target) + { + case NavigationTargets.Navigation: + Navigation = view; + break; + + case NavigationTargets.Layers: + Layers = view; + break; + + case NavigationTargets.Selection: + Selection = view; + break; + + case NavigationTargets.Action: + Action = view; + break; + + case NavigationTargets.Surface: + Surface = view; + break; + } + } + + #endregion + } +} diff --git a/Arge/Bootstrapper/UnityBootstrapper.cs b/Arge/Bootstrapper/UnityBootstrapper.cs index 0fb62ff..13397bb 100644 --- a/Arge/Bootstrapper/UnityBootstrapper.cs +++ b/Arge/Bootstrapper/UnityBootstrapper.cs @@ -1,11 +1,12 @@ using System; -using System.Collections.Generic; -using Caliburn.Micro; +using System.Windows; using Microsoft.Practices.Unity; +using ReactiveUI; +using Splat; namespace Arge.Bootstrapper { - public abstract class UnityBootstrapper : BootstrapperBase + public abstract class UnityBootstrapper { #region Properties & Fields @@ -13,47 +14,38 @@ namespace Arge.Bootstrapper #endregion - #region Constructors - - protected UnityBootstrapper() - { - Initialize(); - } - - #endregion - #region Methods - protected override void Configure() + public virtual void OnStartup(StartupEventArgs e) + { + Configure(); + RegisterTypes(); + InitializeHandlers(); + Start(); + } + + public virtual void OnExit(ExitEventArgs e) + { + } + + protected virtual void Configure() { Container = new UnityContainer(); RegisterSingleton(Container); - RegisterInterface(); - RegisterTypes(); + Locator.Current = new UnityDependencyResolver(Container); + NavigationManager.Initialize(Container); } protected abstract void RegisterTypes(); - protected override object GetInstance(Type service, string key) - { - return key != null ? Container.Resolve(service, key) : Container.Resolve(service); - } + protected abstract void InitializeHandlers(); - protected override IEnumerable GetAllInstances(Type service) - { - return Container.ResolveAll(service); - } - - protected override void BuildUp(object instance) - { - instance = Container.BuildUp(instance); - base.BuildUp(instance); - } + protected abstract void Start(); #region Container-Registration - protected void RegisterInterface(bool registerTypeToo = true, bool registerAsSingleton = true, string uniqueName = null) + protected void RegisterService(bool registerTypeToo = true, bool registerAsSingleton = true, string uniqueName = null) where TImplementation : TInterface { RegisterTypeIfMissing(typeof(TInterface), typeof(TImplementation), registerAsSingleton, uniqueName); @@ -61,6 +53,16 @@ namespace Arge.Bootstrapper RegisterTypeIfMissing(typeof(TImplementation), typeof(TImplementation), registerAsSingleton, uniqueName); } + protected void RegisterView() + where TView : IViewFor + where TViewModel : class, IReactiveObject + { + RegisterTypeIfMissing(typeof(TView), typeof(TView), false); + RegisterTypeIfMissing(typeof(TViewModel), typeof(TViewModel), false); + + NavigationManager.Instance.RegisterViewTypes(typeof(TView), typeof(TViewModel)); + } + protected void RegisterSingleton() { RegisterTypeIfMissing(typeof(T), typeof(T), true); diff --git a/Arge/Bootstrapper/UnityDependencyResolver.cs b/Arge/Bootstrapper/UnityDependencyResolver.cs new file mode 100644 index 0000000..624f422 --- /dev/null +++ b/Arge/Bootstrapper/UnityDependencyResolver.cs @@ -0,0 +1,55 @@ +using System; +using System.Collections.Generic; +using Microsoft.Practices.Unity; +using Splat; + +namespace Arge.Bootstrapper +{ + //HACK DarthAffe 21.05.2017: I've no idea if this a good implementation - don't think so but it seems to work ... + public class UnityDependencyResolver : IMutableDependencyResolver + { + #region Properties & Fields + + private readonly IUnityContainer _container; + private int _defaultCounter = 0; + + #endregion + + #region Constructors + + public UnityDependencyResolver(IUnityContainer container) + { + this._container = container; + } + + #endregion + + #region Methods + + public void Dispose() { } + + public object GetService(Type serviceType, string contract = null) + { + return _container.Resolve(serviceType, contract ?? "default"); + } + + public IEnumerable GetServices(Type serviceType, string contract = null) + { + return _container.ResolveAll(serviceType); + } + + public void Register(Func factory, Type serviceType, string contract = null) + { + if (_container.IsRegistered(serviceType, contract ?? "default")) + contract = $"{(contract ?? "default")}_{_defaultCounter++}"; + _container.RegisterType(serviceType, serviceType, contract ?? "default", new InjectionFactory(c => factory())); + } + + public IDisposable ServiceRegistrationCallback(Type serviceType, string contract, Action callback) + { + throw new NotSupportedException(); + } + + #endregion + } +} diff --git a/Arge/Controls/ImageButton.cs b/Arge/Controls/Buttons/ImageButton.cs similarity index 98% rename from Arge/Controls/ImageButton.cs rename to Arge/Controls/Buttons/ImageButton.cs index f36ba21..300b89c 100644 --- a/Arge/Controls/ImageButton.cs +++ b/Arge/Controls/Buttons/ImageButton.cs @@ -2,7 +2,7 @@ using System.Windows.Controls; using System.Windows.Media; -namespace Arge.Controls +namespace Arge.Controls.Buttons { public class ImageButton : Button { diff --git a/Arge/Controls/BlurredDecorationWindow.cs b/Arge/Controls/Window/BlurredDecorationWindow.cs similarity index 97% rename from Arge/Controls/BlurredDecorationWindow.cs rename to Arge/Controls/Window/BlurredDecorationWindow.cs index e62203b..821b1a2 100644 --- a/Arge/Controls/BlurredDecorationWindow.cs +++ b/Arge/Controls/Window/BlurredDecorationWindow.cs @@ -3,14 +3,14 @@ using System.Windows.Controls; using System.Windows.Input; using System.Windows.Media; -namespace Arge.Controls +namespace Arge.Controls.Window { [TemplatePart(Name = "PART_Decoration", Type = typeof(FrameworkElement))] [TemplatePart(Name = "PART_Content", Type = typeof(FrameworkElement))] [TemplatePart(Name = "PART_CloseButton", Type = typeof(Button))] [TemplatePart(Name = "PART_MinimizeButton", Type = typeof(Button))] [TemplatePart(Name = "PART_IconButton", Type = typeof(Button))] - public class BlurredDecorationWindow : Window + public class BlurredDecorationWindow : System.Windows.Window { #region DependencyProperties // ReSharper disable InconsistentNaming diff --git a/Arge/Enums/NavigationTargets.cs b/Arge/Enums/NavigationTargets.cs new file mode 100644 index 0000000..391361f --- /dev/null +++ b/Arge/Enums/NavigationTargets.cs @@ -0,0 +1,11 @@ +namespace Arge.Enums +{ + public enum NavigationTargets + { + Navigation, + Layers, + Selection, + Action, + Surface + } +} diff --git a/Arge/Misc/AbstractBindable.cs b/Arge/Misc/AbstractBindable.cs deleted file mode 100644 index f6d25c3..0000000 --- a/Arge/Misc/AbstractBindable.cs +++ /dev/null @@ -1,44 +0,0 @@ -using System.Runtime.CompilerServices; -using Caliburn.Micro; - -namespace Arge.Misc -{ - public abstract class AbstractBindable : PropertyChangedBase - { - #region Method - - /// - /// Checks if the property already matches the desirec value or needs to be updated. - /// - /// Type of the property. - /// Reference to the backing-filed. - /// Value to apply. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - protected virtual bool RequiresUpdate(ref T storage, T value) - { - return !Equals(storage, value); - } - - /// - /// Checks if the property already matches the desired value and updates it if not. - /// - /// Type of the property. - /// Reference to the backing-filed. - /// Value to apply. - /// Name of the property used to notify listeners. This value is optional - /// and can be provided automatically when invoked from compilers that support . - /// true if the value was changed, false if the existing value matched the desired value. - protected virtual bool SetProperty(ref T storage, T value, [CallerMemberName] string propertyName = null) - { - if (!RequiresUpdate(ref storage, value)) return false; - - storage = value; - // ReSharper disable once ExplicitCallerInfoArgument - NotifyOfPropertyChange(propertyName); - return true; - } - - #endregion - } -} diff --git a/Arge/Misc/ActionCommand.cs b/Arge/Misc/ActionCommand.cs deleted file mode 100644 index 45ca310..0000000 --- a/Arge/Misc/ActionCommand.cs +++ /dev/null @@ -1,50 +0,0 @@ -using System; -using System.Windows.Input; - -namespace Arge.Misc -{ - public class ActionCommand : ICommand - { - #region Properties & Fields - - private readonly Func _canExecute; - private readonly Action _command; - - #endregion - - #region Constructors - - public ActionCommand(Action command, Func canExecute = null) - { - this._command = command; - this._canExecute = canExecute; - } - - #endregion - - #region Methods - - public bool CanExecute(object parameter) - { - return _canExecute?.Invoke() ?? true; - } - - public void Execute(object parameter) - { - _command?.Invoke(); - } - - public void RaiseCanExecuteChanged() - { - CanExecuteChanged?.Invoke(this, new EventArgs()); - } - - #endregion - - #region Events - - public event EventHandler CanExecuteChanged; - - #endregion - } -} diff --git a/Arge/Misc/BindingProxy.cs b/Arge/Misc/BindingProxy.cs deleted file mode 100644 index fe63b43..0000000 --- a/Arge/Misc/BindingProxy.cs +++ /dev/null @@ -1,28 +0,0 @@ -using System.Windows; - -namespace Arge.Misc -{ - public class BindingProxy : Freezable - { - #region Properties & Fields - // ReSharper disable InconsistentNaming - - public static readonly DependencyProperty DataProperty = DependencyProperty.Register( - "Data", typeof(object), typeof(BindingProxy), new UIPropertyMetadata(null)); - - public object Data - { - get => GetValue(DataProperty); - set => SetValue(DataProperty, value); - } - - // ReSharper restore InconsistentNaming - #endregion - - #region Methods - - protected override Freezable CreateInstanceCore() => new BindingProxy(); - - #endregion - } -} diff --git a/Arge/Resources/Arge.xaml b/Arge/Resources/Arge.xaml index 9c58a17..69d731f 100644 --- a/Arge/Resources/Arge.xaml +++ b/Arge/Resources/Arge.xaml @@ -1,7 +1,8 @@  + xmlns:buttons="clr-namespace:Arge.Controls.Buttons" + xmlns:window="clr-namespace:Arge.Controls.Window"> @@ -9,8 +10,8 @@ -