Add project files.

This commit is contained in:
Daniel Clark
2022-11-01 15:26:08 +00:00
parent daa7b59f22
commit 7e4f880821
408 changed files with 16863 additions and 0 deletions
+84
View File
@@ -0,0 +1,84 @@
<Application
x:Class="TheXamlGuy.App.WeddingDisplay.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:system="clr-namespace:System;assembly=mscorlib">
<Application.Resources>
<FontFamily x:Key="ContentControlFontFamily">Segoe UI Variable Display</FontFamily>
<FontFamily x:Key="AccentFontFamily">Signature Collection</FontFamily>
<FontFamily x:Key="SemiLightContentControlFontFamily">Segoe UI Variable Display Semil</FontFamily>
<system:Double x:Key="CaptionTextBlockFontSize">12</system:Double>
<system:Double x:Key="BodyTextBlockFontSize">14</system:Double>
<system:Double x:Key="SubtitleTextBlockFontSize">20</system:Double>
<system:Double x:Key="TitleTextBlockFontSize">28</system:Double>
<system:Double x:Key="TitleLargeTextBlockFontSize">40</system:Double>
<system:Double x:Key="DisplayTextBlockFontSize">68</system:Double>
<system:Double x:Key="LargeDisplayTextBlockFontSize">120</system:Double>
<Style x:Key="BaseTextBlockStyle" TargetType="TextBlock">
<Setter Property="FontFamily" Value="{StaticResource ContentControlFontFamily}" />
<Setter Property="FontSize" Value="{StaticResource BodyTextBlockFontSize}" />
<Setter Property="FontWeight" Value="SemiBold" />
<Setter Property="TextTrimming" Value="CharacterEllipsis" />
<Setter Property="TextWrapping" Value="Wrap" />
<Setter Property="LineStackingStrategy" Value="MaxHeight" />
</Style>
<Style
x:Key="CaptionTextBlockStyle"
BasedOn="{StaticResource BaseTextBlockStyle}"
TargetType="TextBlock">
<Setter Property="FontSize" Value="{StaticResource CaptionTextBlockFontSize}" />
<Setter Property="FontWeight" Value="Normal" />
</Style>
<Style
x:Key="BodyTextBlockStyle"
BasedOn="{StaticResource BaseTextBlockStyle}"
TargetType="TextBlock">
<Setter Property="FontWeight" Value="Normal" />
</Style>
<Style
x:Key="BodyStrongTextBlockStyle"
BasedOn="{StaticResource BaseTextBlockStyle}"
TargetType="TextBlock" />
<Style
x:Key="SubtitleTextBlockStyle"
BasedOn="{StaticResource BaseTextBlockStyle}"
TargetType="TextBlock">
<Setter Property="FontSize" Value="{StaticResource SubtitleTextBlockFontSize}" />
</Style>
<Style
x:Key="TitleTextBlockStyle"
BasedOn="{StaticResource BaseTextBlockStyle}"
TargetType="TextBlock">
<Setter Property="FontSize" Value="{StaticResource TitleTextBlockFontSize}" />
</Style>
<Style
x:Key="TitleLargeTextBlockStyle"
BasedOn="{StaticResource BaseTextBlockStyle}"
TargetType="TextBlock">
<Setter Property="FontSize" Value="{StaticResource TitleLargeTextBlockFontSize}" />
</Style>
<Style
x:Key="DisplayTextBlockStyle"
BasedOn="{StaticResource BaseTextBlockStyle}"
TargetType="TextBlock">
<Setter Property="FontSize" Value="{StaticResource DisplayTextBlockFontSize}" />
</Style>
<Style
x:Key="LargeDisplayTextBlockStyle"
BasedOn="{StaticResource BaseTextBlockStyle}"
TargetType="TextBlock">
<Setter Property="FontSize" Value="{StaticResource LargeDisplayTextBlockFontSize}" />
</Style>
</Application.Resources>
</Application>
+79
View File
@@ -0,0 +1,79 @@
using System.Windows;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.DependencyInjection;
using TheXamlGuy.Framework.WPF;
using WeddingBooth.Views;
using System.Reflection;
using System;
using System.IO;
using TheXamlGuy.Framework.Core;
using TheXamlGuy.Framework.Microcontroller;
using TheXamlGuy.Framework.Serial;
using TheXamlGuy.Framework.Camera;
using WeddingBooth.LifeCycles;
namespace TheXamlGuy.App.WeddingDisplay
{
public partial class App : Application
{
protected override async void OnStartup(StartupEventArgs args)
{
base.OnStartup(args);
IHost? host = new HostBuilder()
.UseContentRoot(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), "WeddingBooth"), true)
.ConfigureAppConfiguration((context, configuration) =>
{
configuration.AddWritableJsonFile("Settings.json", false, true, writableConfiguration =>
{
writableConfiguration.AddDefaultFileStream(Assembly.GetExecutingAssembly().ExtractResource("Settings.json")!)
.AddDefaultConfiguration<StartupConfiguration>("Startup")
.AddDefaultConfiguration<NavigationConfiguration>("Navigation")
.AddDefaultConfiguration<MicrocontrollerConfiguration>("Microcontroller")
.AddDefaultConfiguration<RemoteCameraConfiguration>("RemoteCamera");
});
})
.ConfigureMicrocontrollers((context, builder) =>
{
builder.Add<MicrocontrollerConfiguration, SerialLineReader, string, MicrocontrollerModuleJsonDeserializer>(context.Configuration.GetSection("Microcontroller"))
.AddModule<CapactiveSensor>();
})
.ConfigureEvents(configuration =>
{
configuration.Add<SerialResponse<string>>().WithHandler(args => args);
configuration.Add<Navigated<NavigationView, NavigationViewModel>>().WithHandler(args => args);
configuration.Add<Captured>().WithHandler(args => args);
})
.ConfigureTemplates(configuration =>
{
configuration.Add<NavigationViewModel, NavigationView>("Navigation");
configuration.Add<WelcomeViewModel, WelcomeView>("Welcome");
configuration.Add<SeatingChartViewModel, SeatingChartView>("Seatings");
configuration.Add<CameraViewModel, CameraView>("Camera");
configuration.Add<GalleryViewModel, GalleryView>("Gallery");
})
.ConfigureCamera((context, builder) =>
{
builder.Add<RemoteCameraConfiguration>(context.Configuration.GetSection("RemoteCamera"));
})
.ConfigureServices(ConfigureServices)
.Build();
await host.RunAsync();
}
private void ConfigureServices(HostBuilderContext context, IServiceCollection services)
{
services.AddReqiredCore()
.AddRequiredWpf()
.AddHostedService<AppServices>()
.AddSingleton<MainWindow>()
.AddSingleton<MainWindowViewModel>()
.AddConfiguration<StartupConfiguration>(context.Configuration.GetSection("Startup"))
.AddConfiguration<NavigationConfiguration>(context.Configuration.GetSection("Navigation"))
.AddConfiguration<MicrocontrollerConfiguration>(context.Configuration.GetSection("Microcontroller"))
.AddConfiguration<RemoteCameraConfiguration>(context.Configuration.GetSection("RemoteCamera"))
.RegisterHandlers();
}
}
}
@@ -0,0 +1,35 @@
using Microsoft.Extensions.Hosting;
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using TheXamlGuy.Framework.Camera;
using TheXamlGuy.Framework.Core;
namespace WeddingBooth.LifeCycles
{
public class CapturedHandler : IMediatorHandler<Captured>
{
private readonly IHostEnvironment hostEnvironment;
public CapturedHandler(IHostEnvironment hostEnvironment)
{
this.hostEnvironment = hostEnvironment;
}
public void Handle(Captured request)
{
if (request.Photo is Bitmap bitmap)
{
using Bitmap writableBitmap = new(bitmap);
string directory = Path.Combine(hostEnvironment.ContentRootPath, "Photos");
Directory.CreateDirectory(directory);
ImageCodecInfo encoder = ImageCodecInfo.GetImageEncoders().First(x => x.FormatID == ImageFormat.Jpeg.Guid);
EncoderParameters encoderParameters = new() { Param = new[] { new EncoderParameter(Encoder.Quality, 100L) } };
writableBitmap.Save($"{directory}\\{DateTime.Now:MMddyyyy-HHmmss}.jpg", encoder, encoderParameters);
}
}
}
}
@@ -0,0 +1,9 @@
using System.Collections.Generic;
namespace WeddingBooth.LifeCycles
{
public class NavigationConfiguration : List<string>
{
}
}
@@ -0,0 +1,39 @@
using TheXamlGuy.Framework.Core;
using TheXamlGuy.Framework.WPF;
using WeddingBooth.Views;
namespace WeddingBooth.LifeCycles
{
public class NavigationNavigatedHandler : IMediatorHandler<Navigated<NavigationView, NavigationViewModel>>
{
private readonly NavigationConfiguration configuration;
public NavigationNavigatedHandler(NavigationConfiguration configuration)
{
this.configuration = configuration;
}
public void Handle(Navigated<NavigationView, NavigationViewModel> request)
{
foreach (string navigation in configuration)
{
switch (navigation)
{
case "Welcome":
request.DataContext?.Add<WelcomeViewModel>();
break;
case "SeatingChart":
request.DataContext?.Add<SeatingChartViewModel>();
break;
case "Camera":
request.DataContext?.Add<CameraViewModel>();
break;
case "Gallery":
request.DataContext?.Add<GalleryViewModel>();
break;
}
}
}
}
}
@@ -0,0 +1,47 @@
using System.Linq;
using System.Windows;
using TheXamlGuy.Framework.Core;
using WeddingBooth.Views;
using WpfScreenHelper;
namespace WeddingBooth.LifeCycles
{
public class StartedHandler : IMediatorHandler<Started>
{
private readonly StartupConfiguration configuration;
private readonly MainWindow window;
private readonly MainWindowViewModel viewModel;
public StartedHandler(StartupConfiguration configuration,
MainWindow window,
MainWindowViewModel viewModel)
{
this.configuration = configuration;
this.window = window;
this.viewModel = viewModel;
}
public void Handle(Started request)
{
window.DataContext = viewModel;
window.Show();
if (configuration.Display is string display)
{
Screen? screen = Screen.AllScreens.FirstOrDefault(x => x.DeviceName.Contains(display, System.StringComparison.InvariantCultureIgnoreCase)) ?? Screen.AllScreens.FirstOrDefault();
if (screen is not null)
{
window.Left = screen.Bounds.Left;
window.Top = screen.Bounds.Top;
window.Width = screen.Bounds.Width;
window.Height = screen.Bounds.Height;
}
if (configuration.FullScreen)
{
window.WindowState = WindowState.Maximized;
}
}
}
}
}
@@ -0,0 +1,10 @@
namespace WeddingBooth.LifeCycles
{
public class StartupConfiguration
{
public bool FullScreen { get; set; }
public string? Display { get; set; }
}
}
+11
View File
@@ -0,0 +1,11 @@
using System.Collections.Generic;
namespace WeddingBooth.LifeCycles
{
public class Table
{
public string? Name { get; set; }
public List<string> Guests { get; set; } = new List<string>();
}
}
@@ -0,0 +1,32 @@
using System;
using System.Drawing;
using System.Globalization;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Interop;
using System.Windows.Media.Imaging;
using TheXamlGuy.Framework.Camera;
using TheXamlGuy.UI.WPF;
namespace WeddingBooth.Markups
{
public class CapturedConverter : ValueConverter<Captured, BitmapSource>
{
[DllImport("gdi32.dll")]
private static extern bool DeleteObject(IntPtr hObject);
protected override BitmapSource? ConvertTo(Captured value, Type? targetType, object? parameter, CultureInfo? culture)
{
if (value.Photo is Bitmap bitmap)
{
IntPtr handle = bitmap.GetHbitmap();
BitmapSource image = Imaging.CreateBitmapSourceFromHBitmap(handle, IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromWidthAndHeight(value.Width, value.Height));
DeleteObject(handle);
return image;
}
return default;
}
}
}
@@ -0,0 +1,3 @@
using System.Windows;
[assembly: ThemeInfo(ResourceDictionaryLocation.None, ResourceDictionaryLocation.SourceAssembly)]
+140
View File
@@ -0,0 +1,140 @@
{
"Startup": {
"Display": "DISPLAY2",
"FullScreen": true
},
"Navigation": [
"Welcome",
"Camera"
],
"Microcontroller": {
"PortName": "COM7",
"BaudRate": 9600
},
"RemoteCamera": {
"Name": "Test"
},
"SeatingChart": [
{
"Name": "one",
"Guests": [
"Lynne Lamb",
"Peter Lamb",
"Liam Lamb",
"Ryan Lamb",
"Mabel Lamb",
"Hayley Lamb",
"Nikki Rushton",
"John Clark",
"Rebecca Days"
]
},
{
"Name": "two",
"Guests": [
"Pauline Clough",
"John Clough",
"Ava Lamb-Clark",
"Nathan Clark",
"Emma Cunnington",
"George Clough",
"Vera Clough",
"Margaret Clayton"
]
},
{
"Name": "three",
"Guests": [
"Alex Clark",
"Anita Chan",
"Trevor Million",
"Lisa Iveson",
"Brian Clark",
"Brian Clark",
"Emma Lee",
"Lisa Clark",
"Siân Laura Davies"
]
},
{
"Name": "four",
"Guests": [
"Michael Lamb",
"Lesley Lamb",
"Ken Clough",
"Kathryn Dodds",
"Patricia Clough",
"Ann Peck",
"Greg Peck"
]
},
{
"Name": "five",
"Guests": [
"Olive Shorten",
"Lynne Shorten",
"Joyce Clark",
"Alison Clarke",
"Jim Clarke",
"Scott Thirlaway",
"Kevin McVittie",
"Katharyn Church",
"Eve Clark",
"Grace Clark"
]
},
{
"Name": "six",
"Guests": [
"Tom Parker",
"Amy Parker",
"Stephen Coates",
"Ashley Coates",
"Callie Coates",
"Ellie Coates",
"Colin Armstrong",
"Kelly Shearsmith",
"Jay Evans"
]
},
{
"Name": "seven",
"Guests": [
"Kelly Taylor",
"Phillip Taylor",
"Lucas Taylor",
"Lana Taylor",
"Christopher Lamb",
"Emma Hunter",
"Tommy",
"Livinya"
]
},
{
"Name": "eight",
"Guests": [
"Harry Clough",
"Jack Clough",
"Corey Derbyshire",
"Shauna Gallon",
"Lora Johnstone",
"Steven Clark",
"Michael Clarke",
"Nicole Wright"
]
},
{
"Name": "nine",
"Guests": [
"Vikki Finnigan",
"Logan Finnigan",
"Gemma Carr",
"Alysha Carr",
"Ross Finnigan",
"Jemma Clark",
"Lily-Rose Goddard",
"David Ford"
]
}
]
}
+143
View File
@@ -0,0 +1,143 @@
<UserControl
x:Class="WeddingBooth.Views.CameraView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:camera="clr-namespace:TheXamlGuy.Framework.Camera;assembly=Camera"
xmlns:markup="clr-namespace:WeddingBooth.Markups"
x:Name="Camera"
VisualStateExtension.IsStateTriggersAttached="True">
<UserControl.Resources>
<BindingProxy x:Key="BindingProxy" DataContext="{Binding}" />
<BindingProxy x:Key="CountdownProxy" DataContext="{Binding ElementName=Countdown}" />
<BindingProxy x:Key="CameraProxy" DataContext="{Binding ElementName=Camera}" />
<BindingProxy x:Key="ImageProxy" DataContext="{Binding ElementName=Image}" />
</UserControl.Resources>
<Grid>
<CameraPreview x:Name="CameraPreview">
<CameraPreview.LayoutTransform>
<RotateTransform Angle="90" />
</CameraPreview.LayoutTransform>
</CameraPreview>
<ProgressRing
x:Name="ProgressRing"
Width="500"
Height="500"
HorizontalAlignment="Center"
VerticalAlignment="Center"
IsActive="True"
IsIndeterminate="True"
Opacity="0"
Thickness="12" />
<Countdown
x:Name="Countdown"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Completed="{Composite {State {Binding Source={StaticResource CameraProxy}, Path=DataContext},
Completed},
{ChangeProperty {Binding},
CanCapture,
false},
{Invoke Capture}}"
CountdownIdentifier="FiveSecond"
FontFamily="{StaticResource ContentControlFontFamily}"
FontSize="300"
Foreground="White"
TextBlock.FontWeight="Thin" />
<Image
x:Name="Image"
Opacity="0"
Stretch="Fill">
<Image.LayoutTransform>
<RotateTransform Angle="90" />
</Image.LayoutTransform>
</Image>
<Border
x:Name="FlashOverlay"
Background="White"
Opacity="0"
RenderTransformOrigin="0.5,0.5">
<TextBlock
HorizontalAlignment="Center"
VerticalAlignment="Center"
FontFamily="{StaticResource AccentFontFamily}"
FontSize="288"
Text="Smile!" />
<Border.RenderTransform>
<ScaleTransform x:Name="ScaleTransform" />
</Border.RenderTransform>
</Border>
</Grid>
<Interaction.XamlEventAggregator>
<XamlEventAggregator EventAggregator="{Binding Source={StaticResource BindingProxy}, Path=DataContext.EventAggregator}">
<EventSubscriber Invoked="{Composite {ChangeProperty {Binding Source={StaticResource ImageProxy}, Path=DataContext}, Source, {EventParameter Invoked, {markup:CapturedConverter}}}, {State {Binding Source={StaticResource CameraProxy}, Path=DataContext}, Captured}, {ChangeProperty {Binding}, CanCapture, true}}" Type="{x:Type camera:Captured}" />
</XamlEventAggregator>
</Interaction.XamlEventAggregator>
<Interaction.InteractiveFrame>
<InteractiveFrame EventAggregator="{Binding Source={StaticResource BindingProxy}, Path=DataContext.EventAggregator}">
<InteractiveFrameButton Invoked="{Composite {Condition {Binding CanCapture}, {Invoke Start, BindingTarget={Binding Source={StaticResource CountdownProxy}, Path=DataContext}}, {State {Binding Source={StaticResource CameraProxy}, Path=DataContext}, Started}}}" Placement="Top" />
</InteractiveFrame>
</Interaction.InteractiveFrame>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="PhotoStates">
<VisualState x:Name="Started">
<Storyboard>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="ProgressRing" Storyboard.TargetProperty="(UIElement.Opacity)">
<DiscreteDoubleKeyFrame KeyTime="00:00:00" Value="1" />
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="Completed">
<Storyboard>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="ScaleTransform" Storyboard.TargetProperty="ScaleX">
<DiscreteDoubleKeyFrame KeyTime="0:0:0" Value="2.05" />
<SplineDoubleKeyFrame
KeySpline="0,0,0,1"
KeyTime="00:00:00.250"
Value="1.0" />
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="ScaleTransform" Storyboard.TargetProperty="ScaleY">
<DiscreteDoubleKeyFrame KeyTime="0:0:0" Value="2.05" />
<SplineDoubleKeyFrame
KeySpline="0,0,0,1"
KeyTime="00:00:00.250"
Value="1.0" />
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="FlashOverlay" Storyboard.TargetProperty="(UIElement.Opacity)">
<DiscreteDoubleKeyFrame KeyTime="0:0:0" Value="0.0" />
<LinearDoubleKeyFrame KeyTime="00:00:00.167" Value="1.0" />
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="ProgressRing" Storyboard.TargetProperty="(UIElement.Opacity)">
<DiscreteDoubleKeyFrame KeyTime="00:00:00" Value="0" />
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="Captured">
<Storyboard>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="Image" Storyboard.TargetProperty="(UIElement.Opacity)">
<SplineDoubleKeyFrame KeyTime="00:00:00" Value="1" />
<SplineDoubleKeyFrame KeyTime="00:00:04" Value="1" />
<SplineDoubleKeyFrame KeyTime="00:00:04.168" Value="0" />
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="ScaleTransform" Storyboard.TargetProperty="ScaleX">
<DiscreteDoubleKeyFrame KeyTime="0:0:0" Value="1.0" />
<SplineDoubleKeyFrame
KeySpline="0,0,0,1"
KeyTime="00:00:00.167"
Value="1.05" />
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="ScaleTransform" Storyboard.TargetProperty="ScaleY">
<DiscreteDoubleKeyFrame KeyTime="0:0:0" Value="1.0" />
<SplineDoubleKeyFrame
KeySpline="0,0,0,1"
KeyTime="00:00:00.167"
Value="1.05" />
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="FlashOverlay" Storyboard.TargetProperty="(UIElement.Opacity)">
<DiscreteDoubleKeyFrame KeyTime="0:0:0" Value="1.0" />
<LinearDoubleKeyFrame KeyTime="00:00:00.083" Value="0.0" />
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</UserControl>
+16
View File
@@ -0,0 +1,16 @@
namespace WeddingBooth.Views;
public partial class CameraView
{
public CameraView()
{
InitializeComponent();
Loaded += CameraView_Loaded;
}
private void CameraView_Loaded(object sender, System.Windows.RoutedEventArgs e)
{
CameraPreview.StartAsync();
}
}
+22
View File
@@ -0,0 +1,22 @@
using System;
using TheXamlGuy.Framework.Camera;
using TheXamlGuy.Framework.Core;
namespace WeddingBooth.Views;
public class CameraViewModel : ObservableViewModel
{
public CameraViewModel(IPropertyBuilder propertyBuilder,
IEventAggregator eventAggregator,
IServiceFactory serviceFactory,
IDisposer disposer) : base(propertyBuilder, eventAggregator, serviceFactory, disposer)
{
}
public bool CanCapture { get; set; } = true;
public void Capture()
{
EventAggregator.Publish<Capture>();
}
}
+14
View File
@@ -0,0 +1,14 @@
<UserControl x:Class="WeddingBooth.Views.GalleryView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:WeddingBooth.Views"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<TextBlock
HorizontalAlignment="Center"
VerticalAlignment="Center"
FontSize="100"
Text="GALLERY VIEW" />
</UserControl>
@@ -0,0 +1,28 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace WeddingBooth.Views
{
/// <summary>
/// Interaction logic for GalleryView.xaml
/// </summary>
public partial class GalleryView : UserControl
{
public GalleryView()
{
InitializeComponent();
}
}
}
@@ -0,0 +1,14 @@
using TheXamlGuy.Framework.Core;
namespace WeddingBooth.Views;
public class GalleryViewModel : ObservableViewModel
{
public GalleryViewModel(IPropertyBuilder propertyBuilder,
IEventAggregator eventAggregator,
IServiceFactory serviceFactory,
IDisposer disposer) : base(propertyBuilder, eventAggregator, serviceFactory, disposer)
{
}
}
+17
View File
@@ -0,0 +1,17 @@
using TheXamlGuy.Framework.Core;
namespace WeddingBooth.Views;
public class GuestViewModel : ObservableViewModel
{
public GuestViewModel(IPropertyBuilder propertyBuilder,
IEventAggregator eventAggregator,
IServiceFactory serviceFactory,
IDisposer disposer,
string name) : base(propertyBuilder, eventAggregator, serviceFactory, disposer)
{
Name = name;
}
public string Name { get; }
}
+10
View File
@@ -0,0 +1,10 @@
<Window
x:Class="WeddingBooth.Views.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Content="{Route {Binding Route},
Root}"
Loaded="{Navigate {Binding EventAggregator},
Root,
Navigation}"
WindowStyle="None" />
+23
View File
@@ -0,0 +1,23 @@
using System.Linq;
namespace WeddingBooth.Views;
public partial class MainWindow
{
public MainWindow()
{
InitializeComponent();
//var DeviceManager = new CameraDeviceManager();
//DeviceManager.ConnectToCamera();
//DeviceManager.AddDevice(d[3].Connect("192.168.1.1"));
//DeviceManager.CameraConnected += DeviceManager_CameraConnected;
//DeviceManager.SelectedCameraDevice.PhotoCaptured += SelectedCameraDevice_PhotoCaptured;
//DeviceManager.SelectedCameraDevice.CapturePhoto();
}
}
@@ -0,0 +1,18 @@
using TheXamlGuy.Framework.Core;
using TheXamlGuy.Framework.WPF;
namespace WeddingBooth.Views;
public class MainWindowViewModel : ObservableViewModel
{
public MainWindowViewModel(IPropertyBuilder propertyBuilder,
IEventAggregator eventAggregator,
IServiceFactory serviceFactory,
IDisposer disposer,
IRoute route) : base(propertyBuilder, eventAggregator, serviceFactory, disposer)
{
Route = route;
}
public IRoute Route { get; }
}
@@ -0,0 +1,20 @@
<UserControl
x:Class="WeddingBooth.Views.NavigationView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<UserControl.Resources>
<BindingProxy x:Key="BindingProxy" DataContext="{Binding}" />
<BindingProxy x:Key="FlipViewProxy" DataContext="{Binding ElementName=FlipView}" />
</UserControl.Resources>
<FlipView
x:Name="FlipView"
ItemContainerTemplateSelector="{Binding TemplateSelector}"
ItemsSource="{Binding}"
UsesItemContainerTemplateSelector="True" />
<Interaction.InteractiveFrame>
<InteractiveFrame EventAggregator="{Binding Source={StaticResource BindingProxy}, Path=DataContext.EventAggregator}">
<InteractiveFrameButton Invoked="{Invoke Previous, BindingTarget={Binding Source={StaticResource FlipViewProxy}, Path=DataContext}}" Placement="Left" />
<InteractiveFrameButton Invoked="{Invoke Next, BindingTarget={Binding Source={StaticResource FlipViewProxy}, Path=DataContext}}" Placement="Right" />
</InteractiveFrame>
</Interaction.InteractiveFrame>
</UserControl>
@@ -0,0 +1,9 @@
namespace WeddingBooth.Views;
public partial class NavigationView
{
public NavigationView()
{
InitializeComponent();
}
}
@@ -0,0 +1,17 @@
using TheXamlGuy.Framework.Core;
namespace WeddingBooth.Views;
public class NavigationViewModel : ObservableViewModelCollection<IObservableViewModel>
{
public NavigationViewModel(IPropertyBuilder propertyBuilder,
IEventAggregator eventAggregator,
IServiceFactory serviceFactory,
IDisposer disposer,
ITemplateSelector templateSelector) : base(propertyBuilder, eventAggregator, serviceFactory, disposer)
{
TemplateSelector = templateSelector;
}
public ITemplateSelector TemplateSelector { get; }
}
@@ -0,0 +1,9 @@
using System.Collections.Generic;
namespace WeddingBooth.LifeCycles
{
public class SeatingChartConfiguration : List<Table>
{
}
}
@@ -0,0 +1,30 @@
using TheXamlGuy.Framework.Core;
using TheXamlGuy.Framework.WPF;
using WeddingBooth.Views;
namespace WeddingBooth.LifeCycles
{
public class SeatingChartNavigatedHandler : IMediatorHandler<Navigated<SeatingChartView, SeatingChartViewModel>>
{
private readonly SeatingChartConfiguration configuration;
public SeatingChartNavigatedHandler(SeatingChartConfiguration configuration)
{
this.configuration = configuration;
}
public void Handle(Navigated<SeatingChartView, SeatingChartViewModel> request)
{
foreach (Table table in configuration)
{
if(request.DataContext?.Add(table.Name) is TableViewModel tableViewModel)
{
foreach (string guest in table.Guests)
{
tableViewModel.Add(guest);
}
}
}
}
}
}
@@ -0,0 +1,30 @@
<UserControl
x:Class="WeddingBooth.Views.SeatingChartView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Margin="40,40,16,16">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="18" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<TextBlock
Grid.Row="0"
HorizontalAlignment="Center"
FontFamily="{StaticResource AccentFontFamily}"
FontWeight="Normal"
Style="{StaticResource LargeDisplayTextBlockStyle}"
Text="find your seat" />
<ItemsControl
Grid.Row="2"
ItemTemplateSelector="{Binding TemplateSelector}"
ItemsSource="{Binding}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Columns="3" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</Grid>
</UserControl>
@@ -0,0 +1,11 @@
using System.Windows.Controls;
namespace WeddingBooth.Views;
public partial class SeatingChartView : UserControl
{
public SeatingChartView()
{
InitializeComponent();
}
}
@@ -0,0 +1,17 @@
using TheXamlGuy.Framework.Core;
namespace WeddingBooth.Views;
public class SeatingChartViewModel : ObservableViewModelCollection<TableViewModel>
{
public SeatingChartViewModel(IPropertyBuilder propertyBuilder,
IEventAggregator eventAggregator,
IServiceFactory serviceFactory,
IDisposer disposer,
ITemplateSelector templateSelector) : base(propertyBuilder, eventAggregator, serviceFactory, disposer)
{
TemplateSelector = templateSelector;
}
public ITemplateSelector TemplateSelector { get; }
}
+43
View File
@@ -0,0 +1,43 @@
<UserControl
x:Class="WeddingBooth.Views.TableView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<UserControl.Resources>
<SolidColorBrush x:Key="BorderBrush" Color="#FF8C8C8C" />
</UserControl.Resources>
<Border
Margin="0,0,24,24"
BorderBrush="{StaticResource BorderBrush}"
BorderThickness="1">
<Grid Margin="24">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<TextBlock
Grid.Row="0"
HorizontalAlignment="Center"
FontFamily="{StaticResource AccentFontFamily}"
FontWeight="Normal"
FontSize="92"
Margin="0 0 0 -28"
Text="{Binding Name}" />
<ItemsControl
Grid.Row="2"
HorizontalAlignment="Center"
ItemsSource="{Binding}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock
Margin="0,0,0,2"
FontWeight="Thin"
Style="{StaticResource SubtitleTextBlockStyle}"
Text="{Binding Name}"
TextAlignment="Center" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
</Border>
</UserControl>
+9
View File
@@ -0,0 +1,9 @@
namespace WeddingBooth.Views;
public partial class TableView
{
public TableView()
{
InitializeComponent();
}
}
+17
View File
@@ -0,0 +1,17 @@
using TheXamlGuy.Framework.Core;
namespace WeddingBooth.Views;
public class TableViewModel : ObservableViewModelCollection<GuestViewModel>
{
public TableViewModel(IPropertyBuilder propertyBuilder,
IEventAggregator eventAggregator,
IServiceFactory serviceFactory,
IDisposer disposer,
string name) : base(propertyBuilder, eventAggregator, serviceFactory, disposer)
{
Name = name;
}
public string Name { get; }
}
+40
View File
@@ -0,0 +1,40 @@
<UserControl
x:Class="WeddingBooth.Views.WelcomeView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
<TextBlock
Margin="0,-0,0,-60"
HorizontalAlignment="Center"
FontFamily="{StaticResource AccentFontFamily}"
FontSize="288"
FontWeight="Light"
Text="Welcome" />
<TextBlock
HorizontalAlignment="Center"
FontStretch="ExtraExpanded"
FontWeight="Thin"
Style="{StaticResource TitleTextBlockStyle}"
Text="TO OUR WEDDING" />
<TextBlock
HorizontalAlignment="Center"
FontStretch="ExtraExpanded"
FontWeight="Thin"
Style="{StaticResource DisplayTextBlockStyle}"
Text="LAURA &amp; DANIEL" />
<TextBlock
Margin="0,0,0,12"
HorizontalAlignment="Center"
FontStretch="ExtraExpanded"
FontWeight="Thin"
Style="{StaticResource TitleTextBlockStyle}"
Text="OCTOBER 6ᵗʰ, 2022" />
<TextBlock
HorizontalAlignment="Center"
FontStretch="ExtraExpanded"
FontWeight="Thin"
Style="{StaticResource TitleTextBlockStyle}"
Text="LET US MAKE MEMORIES OF OUR SPECIAL EVENING"
TextAlignment="Center" />
</StackPanel>
</UserControl>
@@ -0,0 +1,28 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace WeddingBooth.Views
{
/// <summary>
/// Interaction logic for WelcomeView.xaml
/// </summary>
public partial class WelcomeView : UserControl
{
public WelcomeView()
{
InitializeComponent();
}
}
}
@@ -0,0 +1,15 @@
using TheXamlGuy.Framework.Core;
namespace WeddingBooth.Views;
public class WelcomeViewModel : ObservableViewModel
{
public WelcomeViewModel(IPropertyBuilder propertyBuilder,
IEventAggregator eventAggregator,
IServiceFactory serviceFactory,
IDisposer disposer) : base(propertyBuilder, eventAggregator, serviceFactory, disposer)
{
}
}
+29
View File
@@ -0,0 +1,29 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net6.0-windows10.0.18362.0</TargetFramework>
<Nullable>enable</Nullable>
<UseWPF>true</UseWPF>
<Platforms>AnyCPU;x64</Platforms>
</PropertyGroup>
<ItemGroup>
<None Remove="Settings.json" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Settings.json" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Hosting" Version="7.0.0-rc.2.22472.3" />
<PackageReference Include="WpfScreenHelper" Version="2.1.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\Framework\Camera\Camera.csproj" />
<ProjectReference Include="..\..\Framework\Core\Core.csproj" />
<ProjectReference Include="..\..\Framework\Microcontroller\Microcontroller.csproj" />
<ProjectReference Include="..\..\Framework\Serial\Serial.csproj" />
<ProjectReference Include="..\..\Framework\WPF\WPF.csproj" />
<ProjectReference Include="..\..\Media\Capture\Capture.csproj" />
<ProjectReference Include="..\..\UI\WPF.Controls\WPF.Controls.csproj" />
<ProjectReference Include="..\..\UI\WPF\WPF.csproj" />
</ItemGroup>
</Project>
+454
View File
@@ -0,0 +1,454 @@
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
##
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
# User-specific files
*.rsuser
*.suo
*.user
*.userosscache
*.sln.docstates
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
# Mono auto generated files
mono_crash.*
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
[Ww][Ii][Nn]32/
[Aa][Rr][Mm]/
[Aa][Rr][Mm]64/
bld/
[Bb]in/
[Oo]bj/
[Ll]og/
[Ll]ogs/
# Visual Studio 2015/2017 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/
# Visual Studio 2017 auto generated files
Generated\ Files/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
# NUnit
*.VisualState.xml
TestResult.xml
nunit-*.xml
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c
# Benchmark Results
BenchmarkDotNet.Artifacts/
# .NET Core
project.lock.json
project.fragment.lock.json
artifacts/
# Tye
.tye/
# ASP.NET Scaffolding
ScaffoldingReadMe.txt
# StyleCop
StyleCopReport.xml
# Files built by Visual Studio
*_i.c
*_p.c
*_h.h
*.ilk
*.meta
*.obj
*.iobj
*.pch
*.pdb
*.ipdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*_wpftmp.csproj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc
# Chutzpah Test files
_Chutzpah*
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
*.VC.db
*.VC.VC.opendb
# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap
# Visual Studio Trace Files
*.e2e
# TFS 2012 Local Workspace
$tf/
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# AxoCover is a Code Coverage Tool
.axoCover/*
!.axoCover/settings.json
# Coverlet is a free, cross platform Code Coverage Tool
coverage*.json
coverage*.xml
coverage*.info
# Visual Studio code coverage results
*.coverage
*.coveragexml
# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*
# MightyMoose
*.mm.*
AutoTest.Net/
# Web workbench (sass)
.sass-cache/
# Installshield output folder
[Ee]xpress/
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish/
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# Note: Comment the next line if you want to checkin your web deploy settings,
# but database connection strings (with potential passwords) will be unencrypted
*.pubxml
*.publishproj
# Microsoft Azure Web App publish settings. Comment the next line if you want to
# checkin your Azure Web App publish settings, but sensitive information contained
# in these scripts will be unencrypted
PublishScripts/
# NuGet Packages
*.nupkg
# NuGet Symbol Packages
*.snupkg
# The packages folder can be ignored because of Package Restore
**/[Pp]ackages/*
# except build/, which is used as an MSBuild target.
!**/[Pp]ackages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/[Pp]ackages/repositories.config
# NuGet v3's project.json files produces more ignorable files
*.nuget.props
*.nuget.targets
# Microsoft Azure Build Output
csx/
*.build.csdef
# Microsoft Azure Emulator
ecf/
rcf/
# Windows Store app package directories and files
AppPackages/
BundleArtifacts/
Package.StoreAssociation.xml
_pkginfo.txt
*.appx
*.appxbundle
*.appxupload
# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!?*.[Cc]ache/
# Others
ClientBin/
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.jfm
*.pfx
*.publishsettings
orleans.codegen.cs
# Including strong name files can present a security risk
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
#*.snk
# Since there are multiple workflows, uncomment next line to ignore bower_components
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
#bower_components/
# RIA/Silverlight projects
Generated_Code/
# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
ServiceFabricBackup/
*.rptproj.bak
# SQL Server files
*.mdf
*.ldf
*.ndf
# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
*.rptproj.rsuser
*- [Bb]ackup.rdl
*- [Bb]ackup ([0-9]).rdl
*- [Bb]ackup ([0-9][0-9]).rdl
# Microsoft Fakes
FakesAssemblies/
# GhostDoc plugin setting file
*.GhostDoc.xml
# Node.js Tools for Visual Studio
.ntvs_analysis.dat
node_modules/
# Visual Studio 6 build log
*.plg
# Visual Studio 6 workspace options file
*.opt
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
*.vbw
# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions
# Paket dependency manager
.paket/paket.exe
paket-files/
# FAKE - F# Make
.fake/
# CodeRush personal settings
.cr/personal
# Python Tools for Visual Studio (PTVS)
__pycache__/
*.pyc
# Cake - Uncomment if you are using it
# tools/**
# !tools/packages.config
# Tabs Studio
*.tss
# Telerik's JustMock configuration file
*.jmconfig
# BizTalk build output
*.btp.cs
*.btm.cs
*.odx.cs
*.xsd.cs
# OpenCover UI analysis results
OpenCover/
# Azure Stream Analytics local run output
ASALocalRun/
# MSBuild Binary and Structured Log
*.binlog
# NVidia Nsight GPU debugger configuration file
*.nvuser
# MFractors (Xamarin productivity tool) working folder
.mfractor/
# Local History for Visual Studio
.localhistory/
# BeatPulse healthcheck temp database
healthchecksdb
# Backup folder for Package Reference Convert tool in Visual Studio 2017
MigrationBackup/
# Ionide (cross platform F# VS Code tools) working folder
.ionide/
# Fody - auto-generated XML schema
FodyWeavers.xsd
##
## Visual studio for Mac
##
# globs
Makefile.in
*.userprefs
*.usertasks
config.make
config.status
aclocal.m4
install-sh
autom4te.cache/
*.tar.gz
tarballs/
test-results/
# Mac bundle stuff
*.dmg
*.app
# content below from: https://github.com/github/gitignore/blob/master/Global/macOS.gitignore
# General
.DS_Store
.AppleDouble
.LSOverride
# Icon must end with two \r
Icon
# Thumbnails
._*
# Files that might appear in the root of a volume
.DocumentRevisions-V100
.fseventsd
.Spotlight-V100
.TemporaryItems
.Trashes
.VolumeIcon.icns
.com.apple.timemachine.donotpresent
# Directories potentially created on remote AFP share
.AppleDB
.AppleDesktop
Network Trash Folder
Temporary Items
.apdisk
# content below from: https://github.com/github/gitignore/blob/master/Global/Windows.gitignore
# Windows thumbnail cache files
Thumbs.db
ehthumbs.db
ehthumbs_vista.db
# Dump file
*.stackdump
# Folder config file
[Dd]esktop.ini
# Recycle Bin used on file shares
$RECYCLE.BIN/
# Windows Installer files
*.cab
*.msi
*.msix
*.msm
*.msp
# Windows shortcuts
*.lnk
# JetBrains Rider
.idea/
*.sln.iml
##
## Visual Studio Code
##
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
+75
View File
@@ -0,0 +1,75 @@
<Application
x:Class="Builder.App"
xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:style="using:FluentAvalonia.Styling">
<Application.Styles>
<style:FluentAvaloniaTheme />
<Style Selector="Button.Icon">
<Setter Property="FontSize" Value="16" />
<Setter Property="FontFamily" Value="{StaticResource SymbolThemeFontFamily}" />
<Setter Property="MinHeight" Value="{StaticResource PaneToggleButtonHeight}" />
<Setter Property="MinWidth" Value="{StaticResource PaneToggleButtonWidth}" />
<Setter Property="Padding" Value="4,2" />
<Setter Property="HorizontalAlignment" Value="Center" />
<Setter Property="VerticalAlignment" Value="Top" />
<Setter Property="HorizontalContentAlignment" Value="Center" />
<Setter Property="VerticalContentAlignment" Value="Center" />
<Setter Property="Background" Value="{DynamicResource NavigationViewItemBackground}" />
<Setter Property="Foreground" Value="{DynamicResource NavigationViewItemForeground}" />
<Setter Property="BorderThickness" Value="{DynamicResource NavigationViewToggleBorderThickness}" />
<Setter Property="Template">
<ControlTemplate>
<Border
Name="LayoutRoot"
Height="{TemplateBinding MinHeight}"
Margin="{TemplateBinding Padding}"
HorizontalAlignment="Stretch"
Background="{TemplateBinding Background}"
CornerRadius="{DynamicResource ControlCornerRadius}">
<Grid Name="ContentRoot" ColumnDefinitions="Auto,*">
<Border Width="{TemplateBinding MinWidth}">
<Viewbox
Name="IconHost"
Width="16"
Height="16"
HorizontalAlignment="Center"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}">
<ContentPresenter
Name="ContentPresenter"
VerticalContentAlignment="Center"
Content="{TemplateBinding Content}"
FontSize="{TemplateBinding FontSize}" />
</Viewbox>
</Border>
</Grid>
</Border>
</ControlTemplate>
</Setter>
<Style Selector="^:pointerover">
<Style Selector="^ /template/ Border#LayoutRoot">
<Setter Property="Background" Value="{DynamicResource NavigationViewButtonBackgroundPointerOver}" />
</Style>
<Style Selector="^ /template/ ContentPresenter#ContentPresenter">
<Setter Property="Foreground" Value="{DynamicResource NavigationViewButtonForegroundPointerOver}" />
</Style>
</Style>
<Style Selector="^:pressed">
<Style Selector="^ /template/ Border#LayoutRoot">
<Setter Property="Background" Value="{DynamicResource NavigationViewButtonBackgroundPressed}" />
</Style>
<Style Selector="^ /template/ ContentPresenter#ContentPresenter">
<Setter Property="Foreground" Value="{DynamicResource NavigationViewButtonForegroundPressed}" />
</Style>
</Style>
<Style Selector="^:disabled">
<Style Selector="^ /template/ Border#LayoutRoot">
<Setter Property="Background" Value="{DynamicResource NavigationViewButtonBackgroundDisabled}" />
</Style>
<Style Selector="^ /template/ ContentPresenter#ContentPresenter">
<Setter Property="Foreground" Value="{DynamicResource NavigationViewButtonForegroundDisabled}" />
</Style>
</Style>
</Style>
</Application.Styles>
</Application>
+53
View File
@@ -0,0 +1,53 @@
using Avalonia;
using Avalonia.Markup.Xaml;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using PropertyChanged;
using System;
using System.IO;
using TheXamlGuy.Framework.Avalonia;
using TheXamlGuy.Framework.Core;
namespace Builder
{
[DoNotNotify]
public partial class App : Application
{
public override void Initialize()
{
AvaloniaXamlLoader.Load(this);
}
public override async void OnFrameworkInitializationCompleted()
{
IHost? host = new HostBuilder()
.UseContentRoot(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), "Builder"), true)
.ConfigureTemplates(configuration =>
{
configuration.Add<MainWindowViewModel, MainWindow>();
configuration.Add<MainViewModel, MainView>("Main");
configuration.Add<ProjectConfigurationViewModel, ProjectConfigurationView>("ProjectConfiguration");
configuration.Add<StartProjectConfigurationViewModel, StartProjectConfigurationView>("StartProjectConfiguration");
configuration.Add<CreateProjectConfigurationViewModel, CreateProjectConfigurationView>("CreateProjectConfiguration");
configuration.Add<ExistingProjectConfigurationViewModel, ExistingProjectConfigurationView>("ExistingProjectConfiguration");
configuration.Add<ProjectViewModel, ProjectView>("Project");
configuration.Add<PageDesignerViewModel, PageDesignerView>("PageDesigner");
configuration.Add<PageCollectionViewModel, PageCollectionView>("Pages");
configuration.Add<AddPageViewModel, AddPageView>("AddPage");
})
.ConfigureServices(ConfigureServices)
.Build();
await host.RunAsync();
base.OnFrameworkInitializationCompleted();
}
private void ConfigureServices(HostBuilderContext context, IServiceCollection services)
{
services.AddReqiredCore()
.AddRequiredAvalonia()
.AddHostedService<AppServices>()
.RegisterHandlers();
}
}
}
+43
View File
@@ -0,0 +1,43 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<Nullable>enable</Nullable>
<TrimMode>copyused</TrimMode>
<BuiltInComInteropSupport>true</BuiltInComInteropSupport>
</PropertyGroup>
<ItemGroup>
<None Remove=".gitignore" />
</ItemGroup>
<ItemGroup>
<TrimmableAssembly Include="Avalonia.Themes.Fluent" />
<TrimmableAssembly Include="Avalonia.Themes.Default" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Avalonia" Version="11.0.0-preview3" />
<PackageReference Include="Avalonia.Desktop" Version="11.0.0-preview3" />
<PackageReference Condition="'$(Configuration)' == 'Debug'" Include="Avalonia.Diagnostics" Version="11.0.0-preview3" />
<PackageReference Include="Avalonia.Themes.Fluent" Version="11.0.0-preview3" />
<PackageReference Include="PropertyChanged.Fody" Version="4.0.5" />
<PackageReference Include="XamlNameReferenceGenerator" Version="1.3.4" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\Framework\Avalonia\Avalonia.csproj" />
<ProjectReference Include="..\..\UI\Avalonia.Controls\Avalonia.Controls.csproj" />
<ProjectReference Include="..\..\UI\Avalonia\Avalonia.csproj" />
<ProjectReference Include="..\..\UI\UI\UI.csproj" />
</ItemGroup>
<ItemGroup>
<Reference Include="FluentAvalonia">
<HintPath>..\..\Framework\Avalonia\References\FluentAvalonia.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Update="Views\StartProjectConfigurationView.axaml.cs">
<DependentUpon>StartProjectConfigurationView.axaml</DependentUpon>
</Compile>
<Compile Update="Views\ProjectView.axaml.cs">
<DependentUpon>ProjectView.axaml</DependentUpon>
</Compile>
</ItemGroup>
</Project>
+3
View File
@@ -0,0 +1,3 @@
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
<PropertyChanged />
</Weavers>
+3
View File
@@ -0,0 +1,3 @@
namespace Builder.LifeCycles;
public record AddPage(string Name);
@@ -0,0 +1,18 @@
using TheXamlGuy.Framework.Core;
namespace Builder.LifeCycles;
public class AddPageHandler : IMediatorHandler<AddPage>
{
private readonly IProjectContext context;
public AddPageHandler(IProjectContext context)
{
this.context = context;
}
public void Handle(AddPage request)
{
context.Pages.Add(new Page(request.Name));
}
}
@@ -0,0 +1,9 @@
using System.Collections.Generic;
namespace Builder.LifeCycles
{
public interface IProjectContext
{
ICollection<Page> Pages { get; }
}
}
+4
View File
@@ -0,0 +1,4 @@
namespace Builder.LifeCycles
{
public record Page(string Name);
}
@@ -0,0 +1,7 @@
namespace Builder.LifeCycles
{
public class ProjectConfiguration
{
}
}
@@ -0,0 +1,14 @@
using System.Collections.Generic;
namespace Builder.LifeCycles
{
public class ProjectContext : IProjectContext
{
public ICollection<Page> Pages => new List<Page>();
}
public interface IProjectScope
{
}
}
@@ -0,0 +1,27 @@
using Avalonia;
using Avalonia.Controls.ApplicationLifetimes;
using TheXamlGuy.Framework.Core;
namespace Builder;
public class StartedHandler : IMediatorHandler<Started>
{
private readonly MainWindow window;
private readonly MainWindowViewModel viewModel;
public StartedHandler(MainWindow window,
MainWindowViewModel viewModel)
{
this.window = window;
this.viewModel = viewModel;
}
public void Handle(Started request)
{
window.DataContext = viewModel;
if (Application.Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
{
desktop.MainWindow = window;
}
}
}
+20
View File
@@ -0,0 +1,20 @@
using Avalonia;
using System;
namespace Builder;
internal class Program
{
[STAThread]
public static void Main(string[] args) => BuildAvaloniaApp()
.StartWithClassicDesktopLifetime(args);
public static AppBuilder BuildAvaloniaApp()
=> AppBuilder.Configure<App>()
.UsePlatformDetect()
.With(new Win32PlatformOptions
{
UseCompositor = false
})
.LogToTrace();
}
@@ -0,0 +1,3 @@
using Avalonia.Metadata;
[assembly: XmlnsDefinition("https://github.com/avaloniaui", "FluentAvalonia.UI.Controls")]
@@ -0,0 +1,16 @@
<fluent:ContentDialog
x:Class="Builder.AddPageView"
xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:fluent="using:FluentAvalonia.UI.Controls"
xmlns:ui="clr-namespace:TheXamlGuy.UI.Avalonia;assembly=TheXamlGuy.UI.Avalonia"
Title="Add Page"
CloseButtonText="Cancel"
DefaultButton="Primary"
PrimaryButtonClick="{ui:Invoke Add}"
PrimaryButtonText="Add">
<TextBox
Width="500"
Text="{Binding Name}"
Watermark="Enter page name" />
</fluent:ContentDialog>
@@ -0,0 +1,17 @@
using Avalonia.Styling;
using FluentAvalonia.UI.Controls;
using PropertyChanged;
using System;
namespace Builder;
[DoNotNotify]
public partial class AddPageView : ContentDialog, IStyleable
{
public AddPageView()
{
InitializeComponent();
}
Type IStyleable.StyleKey => typeof(ContentDialog);
}
@@ -0,0 +1,22 @@
using Builder.LifeCycles;
using TheXamlGuy.Framework.Core;
namespace Builder;
public class AddPageViewModel : ObservableViewModel
{
public AddPageViewModel(IPropertyBuilder propertyBuilder,
IEventAggregator eventAggregator,
IServiceFactory serviceFactory,
IDisposer disposer) : base(propertyBuilder, eventAggregator, serviceFactory, disposer)
{
}
public string? Name { get; set; }
public void Add()
{
EventAggregator.Publish(new AddPage(Name));
}
}
@@ -0,0 +1,24 @@
<UserControl
x:Class="Builder.CreateProjectConfigurationView"
xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="clr-namespace:TheXamlGuy.UI.Avalonia.Controls;assembly=TheXamlGuy.UI.Avalonia.Controls"
xmlns:fluent="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
xmlns:views="using:Builder"
Loaded="{Composite {ChangeProperty {Binding $parent[fluent:ContentDialog]},
Classes,
Create}}">
<Grid>
<controls:FilePicker x:Name="FilePicker" />
<StackPanel Spacing="18">
<TextBox Watermark="Project name" />
<Grid ColumnDefinitions="*, 4, Auto">
<TextBox Grid.Column="0" Watermark="Project location" />
<Button
Grid.Column="2"
Click="{Invoke {Binding #FilePicker.Open}}"
Content="..." />
</Grid>
</StackPanel>
</Grid>
</UserControl>
@@ -0,0 +1,14 @@
using Avalonia.Controls;
using Avalonia.Platform.Storage;
using PropertyChanged;
namespace Builder;
[DoNotNotify]
public partial class CreateProjectConfigurationView : UserControl
{
public CreateProjectConfigurationView()
{
InitializeComponent();
}
}
@@ -0,0 +1,14 @@
using TheXamlGuy.Framework.Core;
namespace Builder;
public class CreateProjectConfigurationViewModel : ObservableViewModel
{
public CreateProjectConfigurationViewModel(IPropertyBuilder propertyBuilder,
IEventAggregator eventAggregator,
IServiceFactory serviceFactory,
IDisposer disposer) : base(propertyBuilder, eventAggregator, serviceFactory, disposer)
{
}
}
@@ -0,0 +1,8 @@
<UserControl
x:Class="Builder.ExistingProjectConfigurationView"
xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:fluent="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
Loaded="{Composite {ChangeProperty {Binding $parent[fluent:ContentDialog]},
Classes,
Open}}" />
@@ -0,0 +1,15 @@
using Avalonia.Controls;
using Avalonia.Data;
using PropertyChanged;
namespace Builder;
[DoNotNotify]
public partial class ExistingProjectConfigurationView : UserControl
{
public ExistingProjectConfigurationView()
{
InitializeComponent();
}
}
@@ -0,0 +1,14 @@
using TheXamlGuy.Framework.Core;
namespace Builder;
public class ExistingProjectConfigurationViewModel : ObservableViewModel
{
public ExistingProjectConfigurationViewModel(IPropertyBuilder propertyBuilder,
IEventAggregator eventAggregator,
IServiceFactory serviceFactory,
IDisposer disposer) : base(propertyBuilder, eventAggregator, serviceFactory, disposer)
{
}
}
+9
View File
@@ -0,0 +1,9 @@
<UserControl
x:Class="Builder.MainView"
xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Content="{Route {Binding Route},
Main}"
Loaded="{Navigate {Binding EventAggregator},
Project,
Route=Main}" />
@@ -0,0 +1,14 @@
using Avalonia.Controls;
using PropertyChanged;
namespace Builder
{
[DoNotNotify]
public partial class MainView : UserControl
{
public MainView()
{
InitializeComponent();
}
}
}
+18
View File
@@ -0,0 +1,18 @@
using TheXamlGuy.Framework.Avalonia;
using TheXamlGuy.Framework.Core;
namespace Builder;
public class MainViewModel : ObservableViewModel
{
public MainViewModel(IPropertyBuilder propertyBuilder,
IEventAggregator eventAggregator,
IServiceFactory serviceFactory,
IDisposer disposer,
IRouter route) : base(propertyBuilder, eventAggregator, serviceFactory, disposer)
{
Route = route;
}
public IRouter Route { get; }
}
@@ -0,0 +1,9 @@
<Window
x:Class="Builder.MainWindow"
xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Content="{Route {Binding Route},
Window}"
Loaded="{Navigate {Binding EventAggregator},
Main,
Route=Window}" />
@@ -0,0 +1,75 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Media;
using Avalonia.Media.Immutable;
using FluentAvalonia.Styling;
using FluentAvalonia.UI.Controls;
using FluentAvalonia.UI.Media;
using PropertyChanged;
using System;
using System.Runtime.InteropServices;
namespace Builder;
[DoNotNotify]
public partial class MainWindow : CoreWindow
{
public MainWindow()
{
InitializeComponent();
}
protected override void OnOpened(EventArgs args)
{
if (AvaloniaLocator.Current.GetService<FluentAvaloniaTheme>() is FluentAvaloniaTheme theme)
{
theme.RequestedThemeChanged += OnRequestedThemeChanged;
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
if (IsWindows11 && theme.RequestedTheme != FluentAvaloniaTheme.HighContrastModeString)
{
TransparencyBackgroundFallback = Brushes.Transparent;
TransparencyLevelHint = WindowTransparencyLevel.Mica;
TryEnableMicaEffect(theme);
}
}
}
base.OnOpened(args);
}
private void OnRequestedThemeChanged(FluentAvaloniaTheme sender, RequestedThemeChangedEventArgs args)
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
if (IsWindows11 && args.NewTheme != FluentAvaloniaTheme.HighContrastModeString)
{
TryEnableMicaEffect(sender);
}
else if (args.NewTheme == FluentAvaloniaTheme.HighContrastModeString)
{
SetValue(BackgroundProperty, AvaloniaProperty.UnsetValue);
}
}
}
private void TryEnableMicaEffect(FluentAvaloniaTheme theme)
{
if (theme.RequestedTheme == FluentAvaloniaTheme.DarkModeString)
{
Color2 color = this.TryFindResource("SolidBackgroundFillColorBase", out object? value) ? (Color2)(Color)value! : new Color2(32, 32, 32);
color = color.LightenPercent(-0.5f);
Background = new ImmutableSolidColorBrush(color, 0.78);
}
else if (theme.RequestedTheme == FluentAvaloniaTheme.LightModeString)
{
Color2 color = this.TryFindResource("SolidBackgroundFillColorBase", out object? value) ? (Color2)(Color)value! : new Color2(243, 243, 243);
color = color.LightenPercent(0.5f);
Background = new ImmutableSolidColorBrush(color, 0.9);
}
}
}
@@ -0,0 +1,18 @@
using TheXamlGuy.Framework.Avalonia;
using TheXamlGuy.Framework.Core;
namespace Builder;
public class MainWindowViewModel : ObservableViewModel
{
public MainWindowViewModel(IPropertyBuilder propertyBuilder,
IEventAggregator eventAggregator,
IServiceFactory serviceFactory,
IDisposer disposer,
IRouter route) : base(propertyBuilder, eventAggregator, serviceFactory, disposer)
{
Route = route;
}
public IRouter Route { get; }
}
@@ -0,0 +1,31 @@
<UserControl
x:Class="Builder.PageCollectionView"
xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:fluent="using:FluentAvalonia.UI.Controls"
xmlns:view="clr-namespace:Builder;assembly=Builder">
<fluent:NavigationView
IsPaneToggleButtonVisible="False"
IsSettingsVisible="False"
MenuItems="{Binding}">
<fluent:NavigationView.PaneHeader>
<Button
HorizontalAlignment="Left"
Classes="Icon"
Click="{Navigate {Binding EventAggregator},
AddPage}"
Content="&#xE109;">
<fluent:FAPathIcon Data="F1 M 10.52 4.559999 C 10.519999 4.346666 10.446666 4.166668 10.3 4.02 C 10.153333 3.873333 9.973333 3.799999 9.76 3.799999 C 9.546666 3.799999 9.366666 3.873333 9.22 4.02 C 9.073333 4.166668 9 4.346666 9 4.559999 L 9 10.799999 L 2.76 10.799999 C 2.546667 10.799999 2.366667 10.873333 2.22 11.02 C 2.073333 11.166667 2 11.346666 2 11.559999 C 2 11.773333 2.073333 11.953333 2.22 12.099999 C 2.366667 12.246667 2.546667 12.32 2.76 12.32 L 9 12.32 L 9 18.559999 C 9 18.773333 9.073333 18.953333 9.22 19.099998 C 9.366666 19.246666 9.546666 19.313332 9.76 19.299999 C 9.973333 19.286667 10.153333 19.213333 10.3 19.08 C 10.446666 18.946667 10.519999 18.773333 10.52 18.559999 L 10.52 12.28 L 16.76 12.28 C 16.973333 12.306667 17.153332 12.246667 17.299999 12.099999 C 17.446667 11.953333 17.513332 11.773333 17.5 11.559999 C 17.486666 11.346666 17.413332 11.166667 17.279999 11.02 C 17.146666 10.873333 16.973333 10.799999 16.76 10.799999 L 10.52 10.799999 Z " />
</Button>
</fluent:NavigationView.PaneHeader>
<fluent:NavigationView.MenuItemTemplate>
<DataTemplate x:DataType="view:PageItemViewModel">
<fluent:NavigationViewItem Content="{Binding Name}">
<fluent:NavigationViewItem.Icon>
<fluent:FAPathIcon Data="F1 M 7.08 11.24 C 7.053333 11.373333 7.08 11.5 7.16 11.62 C 7.24 11.74 7.346666 11.806666 7.48 11.82 C 7.613333 11.833333 7.739999 11.799999 7.86 11.719999 C 7.98 11.639999 8.053333 11.533333 8.08 11.4 L 8.16 10.799999 L 9.4 10.799999 L 9.32 11.24 C 9.293333 11.373333 9.32 11.5 9.4 11.62 C 9.48 11.74 9.593332 11.806666 9.74 11.82 C 9.886666 11.833333 10.013333 11.799999 10.12 11.719999 C 10.226665 11.639999 10.293333 11.533333 10.32 11.4 L 10.4 10.799999 L 11 10.799999 C 11.133333 10.799999 11.253333 10.753333 11.36 10.66 C 11.466666 10.566667 11.52 10.446667 11.52 10.299999 C 11.52 10.153334 11.466666 10.033333 11.36 9.94 C 11.253333 9.846666 11.133333 9.799999 11 9.799999 L 10.559999 9.799999 L 10.76 8.32 L 11.52 8.32 C 11.653333 8.32 11.766666 8.266666 11.86 8.16 C 11.953333 8.053333 12 7.933333 12 7.799999 C 12 7.666666 11.953333 7.553333 11.86 7.459999 C 11.766666 7.366667 11.653333 7.32 11.52 7.32 L 10.92 7.32 L 11.04 6.36 C 11.066667 6.226667 11.04 6.106668 10.96 6 C 10.88 5.893333 10.766666 5.826666 10.62 5.799999 C 10.473332 5.773335 10.346666 5.806667 10.24 5.9 C 10.133333 5.993334 10.066666 6.106668 10.04 6.24 L 9.92 7.32 L 8.679999 7.32 L 8.8 6.36 C 8.826666 6.226667 8.793333 6.106668 8.7 6 C 8.606667 5.893333 8.493333 5.826666 8.36 5.799999 C 8.226666 5.773335 8.106667 5.806667 8 5.9 C 7.893332 5.993334 7.826666 6.106668 7.8 6.24 L 7.64 7.32 L 7 7.32 C 6.866666 7.32 6.746666 7.366667 6.64 7.459999 C 6.533333 7.553333 6.486667 7.666666 6.5 7.799999 C 6.513333 7.933333 6.566667 8.053333 6.66 8.16 C 6.753333 8.266666 6.866666 8.32 7 8.32 L 7.52 8.32 L 7.28 9.799999 L 6.52 9.799999 C 6.36 9.799999 6.233333 9.846666 6.14 9.94 C 6.046666 10.033333 6 10.153334 6 10.299999 C 6 10.446667 6.046666 10.566667 6.14 10.66 C 6.233333 10.753333 6.346666 10.799999 6.48 10.799999 L 7.12 10.799999 Z M 9.76 8.32 L 9.52 9.799999 L 8.28 9.799999 L 8.52 8.32 Z M 6 3.799999 C 5.44 3.799999 4.966666 3.993334 4.58 4.379999 C 4.193333 4.766666 4 5.24 4 5.799999 L 4 17.799999 C 4 18.360001 4.193333 18.833332 4.58 19.219999 C 4.966666 19.606667 5.44 19.799999 6 19.799999 L 14 19.799999 C 14.559999 19.799999 15.033333 19.606667 15.42 19.219999 C 15.806666 18.833332 16 18.360001 16 17.799999 L 16 5.799999 C 16 5.24 15.806666 4.766666 15.42 4.379999 C 15.033333 3.993334 14.559999 3.799999 14 3.799999 Z M 6 4.799999 L 14 4.799999 C 14.266666 4.799999 14.5 4.9 14.7 5.1 C 14.9 5.299999 14.999999 5.533333 15 5.799999 L 15 17.799999 C 14.999999 18.066666 14.9 18.299999 14.7 18.5 C 14.5 18.699999 14.266666 18.799999 14 18.799999 L 6 18.799999 C 5.733333 18.799999 5.5 18.699999 5.3 18.5 C 5.099999 18.299999 5 18.066666 5 17.799999 L 5 5.799999 C 5 5.533333 5.099999 5.299999 5.3 5.1 C 5.5 4.9 5.733333 4.799999 6 4.799999 Z " />
</fluent:NavigationViewItem.Icon>
</fluent:NavigationViewItem>
</DataTemplate>
</fluent:NavigationView.MenuItemTemplate>
</fluent:NavigationView>
</UserControl>
@@ -0,0 +1,13 @@
using Avalonia.Controls;
using PropertyChanged;
namespace Builder;
[DoNotNotify]
public partial class PageCollectionView : UserControl
{
public PageCollectionView()
{
InitializeComponent();
}
}
@@ -0,0 +1,22 @@
using TheXamlGuy.Framework.Avalonia;
using TheXamlGuy.Framework.Core;
namespace Builder;
public class PageCollectionViewModel : ObservableViewModelCollection<PageItemViewModel>
{
public PageCollectionViewModel(IPropertyBuilder propertyBuilder,
IEventAggregator eventAggregator,
IServiceFactory serviceFactory,
IDisposer disposer,
ITemplateSelector templateSelector,
IRouter route) : base(propertyBuilder, eventAggregator, serviceFactory, disposer)
{
TemplateSelector = templateSelector;
Route = route;
}
public ITemplateSelector TemplateSelector { get; }
public IRouter Route { get; }
}
@@ -0,0 +1,9 @@
<UserControl
x:Class="Builder.PageDesignerView"
xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<SplitView
IsPaneOpen="True"
PaneBackground="Red"
PanePlacement="Right" />
</UserControl>
@@ -0,0 +1,13 @@
using Avalonia.Controls;
using PropertyChanged;
namespace Builder;
[DoNotNotify]
public partial class PageDesignerView : UserControl
{
public PageDesignerView()
{
InitializeComponent();
}
}
@@ -0,0 +1,18 @@
using TheXamlGuy.Framework.Avalonia;
using TheXamlGuy.Framework.Core;
namespace Builder;
public class PageDesignerViewModel : ObservableViewModel
{
public PageDesignerViewModel(IPropertyBuilder propertyBuilder,
IEventAggregator eventAggregator,
IServiceFactory serviceFactory,
IDisposer disposer,
IRouter route) : base(propertyBuilder, eventAggregator, serviceFactory, disposer)
{
Route = route;
}
public IRouter Route { get; }
}
@@ -0,0 +1,22 @@
using TheXamlGuy.Framework.Avalonia;
using TheXamlGuy.Framework.Core;
namespace Builder;
public class PageItemViewModel : ObservableViewModel
{
public PageItemViewModel(IPropertyBuilder propertyBuilder,
IEventAggregator eventAggregator,
IServiceFactory serviceFactory,
IDisposer disposer,
IRouter route,
string name) : base(propertyBuilder, eventAggregator, serviceFactory, disposer)
{
Route = route;
Name = name;
}
public IRouter Route { get; }
public string Name { get; }
}
@@ -0,0 +1,70 @@
<fluent:ContentDialog
x:Class="Builder.ProjectConfigurationView"
xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:fluent="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
CloseButtonText="Cancel">
<fluent:ContentDialog.Title>
<Grid Height="40" ColumnDefinitions="Auto, *">
<Button
x:Name="BackButton"
Grid.Column="0"
Classes="Icon"
Click="{Invoke {Binding #Frame.GoBack}}">
<fluent:FAPathIcon Data="F1 M 12.28 17.599998 C 12.119999 17.733334 11.939999 17.799999 11.74 17.799999 C 11.539999 17.799999 11.36 17.719999 11.2 17.559999 L 6.2 12.32 C 6.066667 12.186666 6 12.02 6 11.82 C 6 11.62 6.066667 11.440001 6.2 11.28 L 11.2 6.04 C 11.413333 5.826667 11.66 5.753334 11.94 5.82 C 12.219999 5.886666 12.399999 6.059999 12.48 6.339999 C 12.559999 6.62 12.493332 6.866667 12.28 7.08 L 7.8 11.799999 L 12.28 16.52 C 12.439999 16.68 12.513332 16.860001 12.5 17.059999 C 12.486666 17.259998 12.413332 17.439999 12.28 17.599998 Z " />
</Button>
<TextBlock
x:Name="Title"
Grid.Column="1"
VerticalAlignment="Center" />
</Grid>
</fluent:ContentDialog.Title>
<fluent:Frame
x:Name="Frame"
Width="500"
Height="350"
Content="{Route {Binding Route},
ProjectConfiguration}"
Loaded="{Navigate {Binding EventAggregator},
StartProjectConfiguration,
Route=ProjectConfiguration}" />
<fluent:ContentDialog.Styles>
<Style Selector="fluent|ContentDialog.Project">
<Style Selector="^fluent|ContentDialog.Project /template/ Button#PrimaryButton">
<Setter Property="IsVisible" Value="False" />
</Style>
<Style Selector="^fluent|ContentDialog.Project Button#BackButton">
<Setter Property="IsVisible" Value="False" />
</Style>
<Style Selector="^fluent|ContentDialog.Project TextBlock#Title">
<Setter Property="Text" Value="Let's get started" />
</Style>
</Style>
<Style Selector="fluent|ContentDialog.Create">
<Style Selector="^fluent|ContentDialog.Create /template/ Button#PrimaryButton">
<Setter Property="Content" Value="Create" />
<Setter Property="IsVisible" Value="True" />
<Setter Property="Grid.Column" Value="0" />
<Setter Property="Grid.ColumnSpan" Value="2" />
<Setter Property="Margin" Value="0 0 4 0" />
</Style>
<Style Selector="^fluent|ContentDialog.Create Button#BackButton">
<Setter Property="IsVisible" Value="True" />
</Style>
<Style Selector="^fluent|ContentDialog.Create TextBlock#Title">
<Setter Property="Text" Value="Create a new project" />
</Style>
</Style>
<Style Selector="fluent|ContentDialog.Open">
<Style Selector="^fluent|ContentDialog.Open /template/ Button#PrimaryButton">
<Setter Property="IsVisible" Value="False" />
</Style>
<Style Selector="^fluent|ContentDialog.Open Button#BackButton">
<Setter Property="IsVisible" Value="True" />
</Style>
<Style Selector="^fluent|ContentDialog.Open TextBlock#Title">
<Setter Property="Text" Value="Open a project" />
</Style>
</Style>
</fluent:ContentDialog.Styles>
</fluent:ContentDialog>
@@ -0,0 +1,17 @@
using Avalonia.Styling;
using FluentAvalonia.UI.Controls;
using PropertyChanged;
using System;
namespace Builder;
[DoNotNotify]
public partial class ProjectConfigurationView : ContentDialog, IStyleable
{
public ProjectConfigurationView()
{
InitializeComponent();
}
Type IStyleable.StyleKey => typeof(ContentDialog);
}
@@ -0,0 +1,18 @@
using TheXamlGuy.Framework.Avalonia;
using TheXamlGuy.Framework.Core;
namespace Builder;
public class ProjectConfigurationViewModel : ObservableViewModel
{
public ProjectConfigurationViewModel(IPropertyBuilder propertyBuilder,
IEventAggregator eventAggregator,
IServiceFactory serviceFactory,
IDisposer disposer,
IRouter route) : base(propertyBuilder, eventAggregator, serviceFactory, disposer)
{
Route = route;
}
public IRouter Route { get; }
}
@@ -0,0 +1,23 @@
<UserControl
x:Class="Builder.ProjectView"
xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:fluent="using:FluentAvalonia.UI.Controls"
Loaded="{Navigate {Binding EventAggregator},
ProjectConfiguration}">
<Grid RowDefinitions="Auto,*">
<Button
Grid.Row="0"
Margin="6,6,12,6"
HorizontalAlignment="Right"
Classes="accent"
Content="New project" />
<fluent:Frame
Grid.Row="1"
Content="{Route {Binding Route},
Navigation}"
Loaded="{Navigate {Binding EventAggregator},
Pages,
Route=Navigation}" />
</Grid>
</UserControl>
@@ -0,0 +1,13 @@
using Avalonia.Controls;
using PropertyChanged;
namespace Builder;
[DoNotNotify]
public partial class ProjectView : UserControl
{
public ProjectView()
{
InitializeComponent();
}
}
@@ -0,0 +1,18 @@
using TheXamlGuy.Framework.Avalonia;
using TheXamlGuy.Framework.Core;
namespace Builder;
public class ProjectViewModel : ObservableViewModel
{
public ProjectViewModel(IPropertyBuilder propertyBuilder,
IEventAggregator eventAggregator,
IServiceFactory serviceFactory,
IDisposer disposer,
IRouter route) : base(propertyBuilder, eventAggregator, serviceFactory, disposer)
{
Route = route;
}
public IRouter Route { get; }
}
@@ -0,0 +1,39 @@
<UserControl
x:Class="Builder.StartProjectConfigurationView"
xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:fluent="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
Loaded="{Composite {ChangeProperty {Binding $parent[fluent:ContentDialog]},
Classes,
Project}}">
<StackPanel Spacing="4">
<fluent:SettingsExpander
Click="{Navigate {Binding EventAggregator},
CreateProjectConfiguration,
Route=ProjectConfiguration}"
Description="Let's started with a new blank builder proejct"
Header="Create a new project"
IsClickEnabled="True">
<fluent:SettingsExpander.IconSource>
<fluent:PathIconSource Data="F1 M 3.056641 18.75 C 2.646484 18.75 2.255859 18.666992 1.884766 18.500977 C 1.513672 18.334961 1.189779 18.113607 0.913086 17.836914 C 0.636393 17.560221 0.415039 17.236328 0.249023 16.865234 C 0.083008 16.494141 0 16.103516 0 15.693359 L 0 4.306641 C 0 3.896484 0.083008 3.505859 0.249023 3.134766 C 0.415039 2.763672 0.636393 2.439779 0.913086 2.163086 C 1.189779 1.886395 1.513672 1.665039 1.884766 1.499023 C 2.255859 1.333008 2.646484 1.25 3.056641 1.25 L 6.875 1.25 C 7.324219 1.25 7.709961 1.319988 8.032227 1.459961 C 8.354492 1.599936 8.644205 1.785482 8.901367 2.016602 C 9.158528 2.247723 9.397786 2.513021 9.619141 2.8125 C 9.840494 3.11198 10.071614 3.42448 10.3125 3.75 L 16.943359 3.75 C 17.353516 3.75 17.744141 3.833008 18.115234 3.999023 C 18.486328 4.165039 18.810221 4.386394 19.086914 4.663086 C 19.363605 4.939779 19.584961 5.263672 19.750977 5.634766 C 19.916992 6.005859 20 6.396484 20 6.806641 L 20 9.902344 C 19.817707 9.674479 19.622395 9.456381 19.414062 9.248047 C 19.205729 9.039714 18.984375 8.847656 18.75 8.671875 L 18.75 6.875 C 18.75 6.621095 18.701172 6.380209 18.603516 6.152344 C 18.505859 5.924479 18.370768 5.724284 18.198242 5.551758 C 18.025715 5.379232 17.82552 5.244142 17.597656 5.146484 C 17.369791 5.048829 17.128906 5.000001 16.875 5 L 10.185547 5 C 9.957682 5.156251 9.736328 5.309246 9.521484 5.458984 C 9.306641 5.608725 9.088541 5.742188 8.867188 5.859375 C 8.645833 5.976562 8.413086 6.070964 8.168945 6.142578 C 7.924805 6.214193 7.65625 6.25 7.363281 6.25 L 1.25 6.25 L 1.25 15.625 C 1.25 15.878906 1.298828 16.119791 1.396484 16.347656 C 1.494141 16.575521 1.629232 16.775717 1.801758 16.948242 C 1.974284 17.120768 2.174479 17.255859 2.402344 17.353516 C 2.630208 17.451172 2.871094 17.5 3.125 17.5 L 7.900391 17.5 C 8.011067 17.721354 8.129883 17.936197 8.256836 18.144531 C 8.383789 18.352865 8.522135 18.554688 8.671875 18.75 Z M 7.363281 5 C 7.539062 5.000001 7.70345 4.977215 7.856445 4.931641 C 8.009439 4.886068 8.154297 4.825847 8.291016 4.750977 C 8.427734 4.676107 8.562825 4.5931 8.696289 4.501953 C 8.829752 4.410808 8.964844 4.316406 9.101562 4.21875 C 8.951822 4.016928 8.805338 3.813477 8.662109 3.608398 C 8.51888 3.40332 8.36263 3.219402 8.193359 3.056641 C 8.024088 2.893881 7.833658 2.760418 7.62207 2.65625 C 7.410481 2.552084 7.161458 2.5 6.875 2.5 L 3.125 2.5 C 2.871094 2.5 2.630208 2.548828 2.402344 2.646484 C 2.174479 2.744141 1.974284 2.879232 1.801758 3.051758 C 1.629232 3.224285 1.494141 3.42448 1.396484 3.652344 C 1.298828 3.880209 1.25 4.121094 1.25 4.375 L 1.25 5 Z M 8.75 14.375 C 8.75 13.600261 8.898111 12.871094 9.194336 12.1875 C 9.49056 11.503906 9.892578 10.908203 10.400391 10.400391 C 10.908203 9.892578 11.503906 9.490561 12.1875 9.194336 C 12.871093 8.898112 13.60026 8.75 14.375 8.75 C 14.889322 8.75 15.385741 8.816732 15.864258 8.950195 C 16.342773 9.083659 16.790363 9.272461 17.207031 9.516602 C 17.623697 9.760742 18.004557 10.055339 18.349609 10.400391 C 18.69466 10.745443 18.989258 11.126303 19.233398 11.542969 C 19.477539 11.959636 19.66634 12.407227 19.799805 12.885742 C 19.933268 13.364258 20 13.860678 20 14.375 C 20 15.14974 19.851887 15.878906 19.555664 16.5625 C 19.259439 17.246094 18.857422 17.841797 18.349609 18.349609 C 17.841797 18.857422 17.246094 19.259439 16.5625 19.555664 C 15.878906 19.851889 15.149739 20 14.375 20 C 13.59375 20 12.861328 19.853516 12.177734 19.560547 C 11.494141 19.267578 10.898438 18.867188 10.390625 18.359375 C 9.882812 17.851562 9.482422 17.255859 9.189453 16.572266 C 8.896484 15.888672 8.75 15.15625 8.75 14.375 Z M 15 15 L 16.875 15 C 17.04427 15 17.190754 14.938151 17.314453 14.814453 C 17.43815 14.690756 17.5 14.544271 17.5 14.375 C 17.5 14.205729 17.43815 14.059245 17.314453 13.935547 C 17.190754 13.81185 17.04427 13.75 16.875 13.75 L 15 13.75 L 15 11.875 C 14.999999 11.705729 14.93815 11.559245 14.814453 11.435547 C 14.690755 11.31185 14.544271 11.25 14.375 11.25 C 14.205729 11.25 14.059244 11.31185 13.935547 11.435547 C 13.811849 11.559245 13.75 11.705729 13.75 11.875 L 13.75 13.75 L 11.875 13.75 C 11.705729 13.75 11.559244 13.81185 11.435547 13.935547 C 11.311849 14.059245 11.25 14.205729 11.25 14.375 C 11.25 14.544271 11.311849 14.690756 11.435547 14.814453 C 11.559244 14.938151 11.705729 15 11.875 15 L 13.75 15 L 13.75 16.875 C 13.75 17.044271 13.811849 17.190756 13.935547 17.314453 C 14.059244 17.43815 14.205729 17.5 14.375 17.5 C 14.544271 17.5 14.690755 17.43815 14.814453 17.314453 C 14.93815 17.190756 14.999999 17.044271 15 16.875 Z " />
</fluent:SettingsExpander.IconSource>
<fluent:SettingsExpander.ActionIconSource>
<fluent:PathIconSource Data="F1 M 6.25 16.875 C 6.25 16.705729 6.311849 16.559244 6.435547 16.435547 L 12.861328 10 L 6.435547 3.564453 C 6.311849 3.440756 6.25 3.294271 6.25 3.125 C 6.25 2.95573 6.311849 2.809246 6.435547 2.685547 C 6.559244 2.56185 6.705729 2.5 6.875 2.5 C 7.044271 2.5 7.190755 2.56185 7.314453 2.685547 L 14.189453 9.560547 C 14.31315 9.684245 14.375 9.830729 14.375 10 C 14.375 10.169271 14.31315 10.315756 14.189453 10.439453 L 7.314453 17.314453 C 7.190755 17.43815 7.044271 17.5 6.875 17.5 C 6.705729 17.5 6.559244 17.43815 6.435547 17.314453 C 6.311849 17.190756 6.25 17.044271 6.25 16.875 Z " />
</fluent:SettingsExpander.ActionIconSource>
</fluent:SettingsExpander>
<fluent:SettingsExpander
Click="{Navigate {Binding EventAggregator},
ExistingProjectConfiguration,
Route=ProjectConfiguration}"
Description="Open an existing builder project"
Header="Open a project"
IsClickEnabled="True">
<fluent:SettingsExpander.IconSource>
<fluent:PathIconSource Data="F1 M 3.056641 18.75 C 2.646484 18.75 2.255859 18.666992 1.884766 18.500977 C 1.513672 18.334961 1.189779 18.113607 0.913086 17.836914 C 0.636393 17.560221 0.415039 17.236328 0.249023 16.865234 C 0.083008 16.494141 0 16.103516 0 15.693359 L 0 4.306641 C 0 3.896484 0.083008 3.505859 0.249023 3.134766 C 0.415039 2.763672 0.636393 2.439779 0.913086 2.163086 C 1.189779 1.886395 1.513672 1.665039 1.884766 1.499023 C 2.255859 1.333008 2.646484 1.25 3.056641 1.25 L 6.875 1.25 C 7.324219 1.25 7.709961 1.319988 8.032227 1.459961 C 8.354492 1.599936 8.644205 1.785482 8.901367 2.016602 C 9.158528 2.247723 9.397786 2.513021 9.619141 2.8125 C 9.840494 3.11198 10.071614 3.42448 10.3125 3.75 L 16.943359 3.75 C 17.353516 3.75 17.744141 3.833008 18.115234 3.999023 C 18.486328 4.165039 18.810221 4.386394 19.086914 4.663086 C 19.363605 4.939779 19.584961 5.263672 19.750977 5.634766 C 19.916992 6.005859 20 6.396484 20 6.806641 L 20 9.902344 C 19.817707 9.674479 19.622395 9.456381 19.414062 9.248047 C 19.205729 9.039714 18.984375 8.847656 18.75 8.671875 L 18.75 6.875 C 18.75 6.621095 18.701172 6.380209 18.603516 6.152344 C 18.505859 5.924479 18.370768 5.724284 18.198242 5.551758 C 18.025715 5.379232 17.82552 5.244142 17.597656 5.146484 C 17.369791 5.048829 17.128906 5.000001 16.875 5 L 10.185547 5 C 9.957682 5.156251 9.736328 5.309246 9.521484 5.458984 C 9.306641 5.608725 9.088541 5.742188 8.867188 5.859375 C 8.645833 5.976562 8.413086 6.070964 8.168945 6.142578 C 7.924805 6.214193 7.65625 6.25 7.363281 6.25 L 1.25 6.25 L 1.25 15.625 C 1.25 15.878906 1.298828 16.119791 1.396484 16.347656 C 1.494141 16.575521 1.629232 16.775717 1.801758 16.948242 C 1.974284 17.120768 2.174479 17.255859 2.402344 17.353516 C 2.630208 17.451172 2.871094 17.5 3.125 17.5 L 7.900391 17.5 C 8.011067 17.721354 8.129883 17.936197 8.256836 18.144531 C 8.383789 18.352865 8.522135 18.554688 8.671875 18.75 Z M 7.363281 5 C 7.539062 5.000001 7.70345 4.977215 7.856445 4.931641 C 8.009439 4.886068 8.154297 4.825847 8.291016 4.750977 C 8.427734 4.676107 8.562825 4.5931 8.696289 4.501953 C 8.829752 4.410808 8.964844 4.316406 9.101562 4.21875 C 8.951822 4.016928 8.805338 3.813477 8.662109 3.608398 C 8.51888 3.40332 8.36263 3.219402 8.193359 3.056641 C 8.024088 2.893881 7.833658 2.760418 7.62207 2.65625 C 7.410481 2.552084 7.161458 2.5 6.875 2.5 L 3.125 2.5 C 2.871094 2.5 2.630208 2.548828 2.402344 2.646484 C 2.174479 2.744141 1.974284 2.879232 1.801758 3.051758 C 1.629232 3.224285 1.494141 3.42448 1.396484 3.652344 C 1.298828 3.880209 1.25 4.121094 1.25 4.375 L 1.25 5 Z M 8.75 14.375 C 8.75 13.600261 8.898111 12.871094 9.194336 12.1875 C 9.49056 11.503906 9.892578 10.908203 10.400391 10.400391 C 10.908203 9.892578 11.503906 9.490561 12.1875 9.194336 C 12.871093 8.898112 13.60026 8.75 14.375 8.75 C 14.889322 8.75 15.385741 8.816732 15.864258 8.950195 C 16.342773 9.083659 16.790363 9.272461 17.207031 9.516602 C 17.623697 9.760742 18.004557 10.055339 18.349609 10.400391 C 18.69466 10.745443 18.989258 11.126303 19.233398 11.542969 C 19.477539 11.959636 19.66634 12.407227 19.799805 12.885742 C 19.933268 13.364258 20 13.860678 20 14.375 C 20 15.14974 19.851887 15.878906 19.555664 16.5625 C 19.259439 17.246094 18.857422 17.841797 18.349609 18.349609 C 17.841797 18.857422 17.246094 19.259439 16.5625 19.555664 C 15.878906 19.851889 15.149739 20 14.375 20 C 13.59375 20 12.861328 19.853516 12.177734 19.560547 C 11.494141 19.267578 10.898438 18.867188 10.390625 18.359375 C 9.882812 17.851562 9.482422 17.255859 9.189453 16.572266 C 8.896484 15.888672 8.75 15.15625 8.75 14.375 Z M 12.5 16.923828 C 12.688802 16.923828 12.848307 16.858725 12.978516 16.728516 L 16.25 13.457031 L 16.25 15.625 C 16.25 15.794271 16.311848 15.940756 16.435547 16.064453 C 16.559244 16.188152 16.705729 16.25 16.875 16.25 C 17.04427 16.25 17.190754 16.188152 17.314453 16.064453 C 17.43815 15.940756 17.5 15.794271 17.5 15.625 L 17.5 11.875 C 17.5 11.705729 17.43815 11.559245 17.314453 11.435547 C 17.190754 11.31185 17.04427 11.25 16.875 11.25 L 13.125 11.25 C 12.955729 11.25 12.809244 11.31185 12.685547 11.435547 C 12.561849 11.559245 12.5 11.705729 12.5 11.875 C 12.5 12.044271 12.561849 12.190756 12.685547 12.314453 C 12.809244 12.438151 12.955729 12.5 13.125 12.5 L 15.292969 12.5 L 12.021484 15.771484 C 11.891275 15.901693 11.826172 16.061197 11.826172 16.25 C 11.826172 16.438803 11.891275 16.598307 12.021484 16.728516 C 12.151691 16.858725 12.311197 16.923828 12.5 16.923828 Z " />
</fluent:SettingsExpander.IconSource>
<fluent:SettingsExpander.ActionIconSource>
<fluent:PathIconSource Data="F1 M 6.25 16.875 C 6.25 16.705729 6.311849 16.559244 6.435547 16.435547 L 12.861328 10 L 6.435547 3.564453 C 6.311849 3.440756 6.25 3.294271 6.25 3.125 C 6.25 2.95573 6.311849 2.809246 6.435547 2.685547 C 6.559244 2.56185 6.705729 2.5 6.875 2.5 C 7.044271 2.5 7.190755 2.56185 7.314453 2.685547 L 14.189453 9.560547 C 14.31315 9.684245 14.375 9.830729 14.375 10 C 14.375 10.169271 14.31315 10.315756 14.189453 10.439453 L 7.314453 17.314453 C 7.190755 17.43815 7.044271 17.5 6.875 17.5 C 6.705729 17.5 6.559244 17.43815 6.435547 17.314453 C 6.311849 17.190756 6.25 17.044271 6.25 16.875 Z " />
</fluent:SettingsExpander.ActionIconSource>
</fluent:SettingsExpander>
</StackPanel>
</UserControl>
@@ -0,0 +1,13 @@
using Avalonia.Controls;
using PropertyChanged;
namespace Builder;
[DoNotNotify]
public partial class StartProjectConfigurationView : UserControl
{
public StartProjectConfigurationView()
{
InitializeComponent();
}
}
@@ -0,0 +1,14 @@
using TheXamlGuy.Framework.Core;
namespace Builder;
public class StartProjectConfigurationViewModel : ObservableViewModel
{
public StartProjectConfigurationViewModel(IPropertyBuilder propertyBuilder,
IEventAggregator eventAggregator,
IServiceFactory serviceFactory,
IDisposer disposer) : base(propertyBuilder, eventAggregator, serviceFactory, disposer)
{
}
}