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
+13
View File
@@ -0,0 +1,13 @@
# Default ignored files
/shelf/
/workspace.xml
# Rider ignored files
/modules.xml
/contentModel.xml
/projectSettingsUpdater.xml
/.idea.TheXamlGuy.iml
# Editor-based HTTP Client requests
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml
+4
View File
@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Encoding" addBOMForNewFiles="with BOM under Windows, with no BOM otherwise" />
</project>
+8
View File
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="UserContentModel">
<attachedFolders />
<explicitIncludes />
<explicitExcludes />
</component>
</project>
+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)
{
}
}
+9
View File
@@ -0,0 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>
+27
View File
@@ -0,0 +1,27 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<RootNamespace>TheXamlGuy.Framework.Avalonia</RootNamespace>
<AssemblyName>TheXamlGuy.Framework.Avalonia</AssemblyName>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Avalonia" Version="11.0.0-preview3" />
<PackageReference Include="MicroCom.Runtime" Version="0.10.5" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\UI\Avalonia\Avalonia.csproj" />
<ProjectReference Include="..\Core\Core.csproj" />
</ItemGroup>
<ItemGroup>
<Reference Include="FluentAvalonia">
<HintPath>References\FluentAvalonia.dll</HintPath>
</Reference>
</ItemGroup>
</Project>
@@ -0,0 +1,34 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using TheXamlGuy.Framework.Core;
namespace TheXamlGuy.Framework.Avalonia;
public static class IHostBuilderExtensions
{
public static IHostBuilder ConfigureTemplates(this IHostBuilder hostBuilder, Action<ITemplateBuilder> builderDelegate)
{
hostBuilder.ConfigureServices((hostBuilderContext, serviceCollection) =>
{
TemplateBuilder? builder = new();
builderDelegate?.Invoke(builder);
serviceCollection
.AddSingleton(builder.Descriptors)
.AddSingleton<ITemplateDescriptorProvider, TemplateDescriptorProvider>()
.AddSingleton<ITemplateFactory, TemplateFactory>()
.AddSingleton<INamedTemplateFactory, NamedTemplateFactory>()
.AddSingleton<ITypedDataTemplateFactory, TypedDataTemplateFactory>()
.AddSingleton<INamedDataTemplateFactory, NamedDataTemplateFactory>()
.AddSingleton<ITemplateSelector, TemplateSelector>();
foreach (ITemplateDescriptor? descriptor in builder.Descriptors)
{
serviceCollection.Add(new ServiceDescriptor(descriptor.TemplateType, descriptor.TemplateType, descriptor.Lifetime));
serviceCollection.Add(new ServiceDescriptor(descriptor.DataType, descriptor.DataType, descriptor.Lifetime));
}
});
return hostBuilder;
}
}
@@ -0,0 +1,17 @@
using Microsoft.Extensions.DependencyInjection;
using TheXamlGuy.Framework.Core;
namespace TheXamlGuy.Framework.Avalonia;
public static class IServiceCollectionExtensions
{
public static IServiceCollection AddRequiredAvalonia(this IServiceCollection serviceCollection)
{
return serviceCollection
.AddSingleton<IRouter, Router>()
.AddSingleton<IRouteDescriptorCollection, RouteDescriptorCollection>()
.AddSingleton<IRouterContext, RouterContext>()
.AddTransient<IMediatorHandler<Navigate>, NavigateHandler>()
.RegisterHandlers();
}
}
@@ -0,0 +1,453 @@
using Avalonia.Controls;
using Avalonia;
using Avalonia.Data;
using Avalonia.Markup.Xaml;
using TheXamlGuy.Framework.Core;
using TheXamlGuy.UI.Avalonia;
namespace TheXamlGuy.Framework.Avalonia;
public class NavigateExtension : TriggerExtension
{
private static readonly AttachedProperty<IEventAggregator> EventAggregatorProperty =
AvaloniaProperty.RegisterAttached<NavigateExtension, Control, IEventAggregator>("EventAggregator");
private static readonly AttachedProperty<object> ParameterProperty =
AvaloniaProperty.RegisterAttached<NavigateExtension, Control, object>("Parameter");
private static readonly AvaloniaProperty RouteProperty =
AvaloniaProperty.RegisterAttached<NavigateExtension, Control, object>("Route");
private static readonly AvaloniaProperty ToProperty =
AvaloniaProperty.RegisterAttached<NavigateExtension, Control, object>("To");
private readonly Binding eventAggregatorBinding;
private readonly List<object> parameters = new();
private readonly Binding toBinding;
private object? route;
private Binding? routeBinding;
public NavigateExtension(object eventAggregator,
object to)
{
eventAggregatorBinding = eventAggregator.ToBinding();
this.toBinding = to is Binding toBinding ? toBinding : to.ToBinding();
}
public NavigateExtension(object eventAggregator,
object to,
object args1)
{
eventAggregatorBinding = eventAggregator.ToBinding();
this.toBinding = to is Binding toBinding ? toBinding : to.ToBinding();
parameters.Add(args1 is MarkupExtension ? args1 : args1.ToBinding());
}
public NavigateExtension(object eventAggregator,
object to,
object args1,
object args2)
{
eventAggregatorBinding = eventAggregator.ToBinding();
this.toBinding = to is Binding toBinding ? toBinding : to.ToBinding();
parameters.Add(args1 is MarkupExtension ? args1 : args1.ToBinding());
parameters.Add(args2 is MarkupExtension ? args2 : args2.ToBinding());
}
public NavigateExtension(object eventAggregator,
object to,
object args1,
object args2,
object args3)
{
eventAggregatorBinding = eventAggregator.ToBinding();
this.toBinding = to is Binding toBinding ? toBinding : to.ToBinding();
parameters.Add(args1 is MarkupExtension ? args1 : args1.ToBinding());
parameters.Add(args2 is MarkupExtension ? args2 : args2.ToBinding());
parameters.Add(args3 is MarkupExtension ? args3 : args3.ToBinding());
}
public NavigateExtension(object eventAggregator,
object to,
object args1,
object args2,
object args3,
object args4)
{
eventAggregatorBinding = eventAggregator.ToBinding();
this.toBinding = to is Binding toBinding ? toBinding : to.ToBinding();
parameters.Add(args1 is MarkupExtension ? args1 : args1.ToBinding());
parameters.Add(args2 is MarkupExtension ? args2 : args2.ToBinding());
parameters.Add(args3 is MarkupExtension ? args3 : args3.ToBinding());
parameters.Add(args4 is MarkupExtension ? args4 : args4.ToBinding());
}
public NavigateExtension(object eventAggregator,
object to,
object args1,
object args2,
object args3,
object args4,
object args5)
{
eventAggregatorBinding = eventAggregator.ToBinding();
this.toBinding = to is Binding toBinding ? toBinding : to.ToBinding();
parameters.Add(args1 is MarkupExtension ? args1 : args1.ToBinding());
parameters.Add(args2 is MarkupExtension ? args2 : args2.ToBinding());
parameters.Add(args3 is MarkupExtension ? args3 : args3.ToBinding());
parameters.Add(args4 is MarkupExtension ? args4 : args4.ToBinding());
parameters.Add(args5 is MarkupExtension ? args5 : args5.ToBinding());
}
public NavigateExtension(object eventAggregator,
object to,
object args1,
object args2,
object args3,
object args4,
object args5,
object args6)
{
eventAggregatorBinding = eventAggregator.ToBinding();
this.toBinding = to is Binding toBinding ? toBinding : to.ToBinding();
parameters.Add(args1 is MarkupExtension ? args1 : args1.ToBinding());
parameters.Add(args2 is MarkupExtension ? args2 : args2.ToBinding());
parameters.Add(args3 is MarkupExtension ? args3 : args3.ToBinding());
parameters.Add(args4 is MarkupExtension ? args4 : args4.ToBinding());
parameters.Add(args5 is MarkupExtension ? args5 : args5.ToBinding());
parameters.Add(args6 is MarkupExtension ? args6 : args6.ToBinding());
}
public NavigateExtension(object eventAggregator,
object to,
object args1,
object args2,
object args3,
object args4,
object args5,
object args6,
object args7)
{
eventAggregatorBinding = eventAggregator.ToBinding();
this.toBinding = to is Binding toBinding ? toBinding : to.ToBinding();
parameters.Add(args1 is MarkupExtension ? args1 : args1.ToBinding());
parameters.Add(args2 is MarkupExtension ? args2 : args2.ToBinding());
parameters.Add(args3 is MarkupExtension ? args3 : args3.ToBinding());
parameters.Add(args4 is MarkupExtension ? args4 : args4.ToBinding());
parameters.Add(args5 is MarkupExtension ? args5 : args5.ToBinding());
parameters.Add(args6 is MarkupExtension ? args6 : args6.ToBinding());
parameters.Add(args7 is MarkupExtension ? args7 : args7.ToBinding());
}
public NavigateExtension(object eventAggregator,
object to,
object args1,
object args2,
object args3,
object args4,
object args5,
object args6,
object args7,
object args8)
{
eventAggregatorBinding = eventAggregator.ToBinding();
this.toBinding = to is Binding toBinding ? toBinding : to.ToBinding();
parameters.Add(args1 is MarkupExtension ? args1 : args1.ToBinding());
parameters.Add(args2 is MarkupExtension ? args2 : args2.ToBinding());
parameters.Add(args3 is MarkupExtension ? args3 : args3.ToBinding());
parameters.Add(args4 is MarkupExtension ? args4 : args4.ToBinding());
parameters.Add(args5 is MarkupExtension ? args5 : args5.ToBinding());
parameters.Add(args6 is MarkupExtension ? args6 : args6.ToBinding());
parameters.Add(args7 is MarkupExtension ? args7 : args7.ToBinding());
parameters.Add(args8 is MarkupExtension ? args8 : args8.ToBinding());
}
public NavigateExtension(object eventAggregator,
object to,
object args1,
object args2,
object args3,
object args4,
object args5,
object args6,
object args7,
object args8,
object args9)
{
eventAggregatorBinding = eventAggregator.ToBinding();
this.toBinding = to is Binding toBinding ? toBinding : to.ToBinding();
parameters.Add(args1 is MarkupExtension ? args1 : args1.ToBinding());
parameters.Add(args2 is MarkupExtension ? args2 : args2.ToBinding());
parameters.Add(args3 is MarkupExtension ? args3 : args3.ToBinding());
parameters.Add(args4 is MarkupExtension ? args4 : args4.ToBinding());
parameters.Add(args5 is MarkupExtension ? args5 : args5.ToBinding());
parameters.Add(args6 is MarkupExtension ? args6 : args6.ToBinding());
parameters.Add(args7 is MarkupExtension ? args7 : args7.ToBinding());
parameters.Add(args8 is MarkupExtension ? args8 : args8.ToBinding());
parameters.Add(args9 is MarkupExtension ? args9 : args9.ToBinding());
}
public NavigateExtension(object eventAggregator,
object to,
object args1,
object args2,
object args3,
object args4,
object args5,
object args6,
object args7,
object args8,
object args9,
object args10)
{
eventAggregatorBinding = eventAggregator.ToBinding();
this.toBinding = to is Binding toBinding ? toBinding : to.ToBinding();
parameters.Add(args1 is MarkupExtension ? args1 : args1.ToBinding());
parameters.Add(args2 is MarkupExtension ? args2 : args2.ToBinding());
parameters.Add(args3 is MarkupExtension ? args3 : args3.ToBinding());
parameters.Add(args4 is MarkupExtension ? args4 : args4.ToBinding());
parameters.Add(args5 is MarkupExtension ? args5 : args5.ToBinding());
parameters.Add(args6 is MarkupExtension ? args6 : args6.ToBinding());
parameters.Add(args7 is MarkupExtension ? args7 : args7.ToBinding());
parameters.Add(args8 is MarkupExtension ? args8 : args8.ToBinding());
parameters.Add(args9 is MarkupExtension ? args9 : args9.ToBinding());
parameters.Add(args10 is MarkupExtension ? args10 : args10.ToBinding());
}
public NavigateExtension(object eventAggregator,
object to,
object args1,
object args2,
object args3,
object args4,
object args5,
object args6,
object args7,
object args8,
object args9,
object args10,
object args11)
{
eventAggregatorBinding = eventAggregator.ToBinding();
this.toBinding = to is Binding toBinding ? toBinding : to.ToBinding();
parameters.Add(args1 is MarkupExtension ? args1 : args1.ToBinding());
parameters.Add(args2 is MarkupExtension ? args2 : args2.ToBinding());
parameters.Add(args3 is MarkupExtension ? args3 : args3.ToBinding());
parameters.Add(args4 is MarkupExtension ? args4 : args4.ToBinding());
parameters.Add(args5 is MarkupExtension ? args5 : args5.ToBinding());
parameters.Add(args6 is MarkupExtension ? args6 : args6.ToBinding());
parameters.Add(args7 is MarkupExtension ? args7 : args7.ToBinding());
parameters.Add(args8 is MarkupExtension ? args8 : args8.ToBinding());
parameters.Add(args9 is MarkupExtension ? args9 : args9.ToBinding());
parameters.Add(args10 is MarkupExtension ? args10 : args10.ToBinding());
parameters.Add(args11 is MarkupExtension ? args11 : args11.ToBinding());
}
public NavigateExtension(object eventAggregator,
object to,
object args1,
object args2,
object args3,
object args4,
object args5,
object args6,
object args7,
object args8,
object args9,
object args10,
object args11,
object args12)
{
eventAggregatorBinding = eventAggregator.ToBinding();
this.toBinding = to is Binding toBinding ? toBinding : to.ToBinding();
parameters.Add(args1 is MarkupExtension ? args1 : args1.ToBinding());
parameters.Add(args2 is MarkupExtension ? args2 : args2.ToBinding());
parameters.Add(args3 is MarkupExtension ? args3 : args3.ToBinding());
parameters.Add(args4 is MarkupExtension ? args4 : args4.ToBinding());
parameters.Add(args5 is MarkupExtension ? args5 : args5.ToBinding());
parameters.Add(args6 is MarkupExtension ? args6 : args6.ToBinding());
parameters.Add(args7 is MarkupExtension ? args7 : args7.ToBinding());
parameters.Add(args8 is MarkupExtension ? args8 : args8.ToBinding());
parameters.Add(args9 is MarkupExtension ? args9 : args9.ToBinding());
parameters.Add(args10 is MarkupExtension ? args10 : args10.ToBinding());
parameters.Add(args11 is MarkupExtension ? args11 : args11.ToBinding());
parameters.Add(args12 is MarkupExtension ? args12 : args12.ToBinding());
}
public NavigateExtension(object eventAggregator,
object to,
object args1,
object args2,
object args3,
object args4,
object args5,
object args6,
object args7,
object args8,
object args9,
object args10,
object args11,
object args12,
object args13)
{
eventAggregatorBinding = eventAggregator.ToBinding();
this.toBinding = to is Binding toBinding ? toBinding : to.ToBinding();
parameters.Add(args1 is MarkupExtension ? args1 : args1.ToBinding());
parameters.Add(args2 is MarkupExtension ? args2 : args2.ToBinding());
parameters.Add(args3 is MarkupExtension ? args3 : args3.ToBinding());
parameters.Add(args4 is MarkupExtension ? args4 : args4.ToBinding());
parameters.Add(args5 is MarkupExtension ? args5 : args5.ToBinding());
parameters.Add(args6 is MarkupExtension ? args6 : args6.ToBinding());
parameters.Add(args7 is MarkupExtension ? args7 : args7.ToBinding());
parameters.Add(args8 is MarkupExtension ? args8 : args8.ToBinding());
parameters.Add(args9 is MarkupExtension ? args9 : args9.ToBinding());
parameters.Add(args10 is MarkupExtension ? args10 : args10.ToBinding());
parameters.Add(args11 is MarkupExtension ? args11 : args11.ToBinding());
parameters.Add(args12 is MarkupExtension ? args12 : args12.ToBinding());
parameters.Add(args13 is MarkupExtension ? args13 : args13.ToBinding());
}
public NavigateExtension(object eventAggregator,
object to,
object args1,
object args2,
object args3,
object args4,
object args5,
object args6,
object args7,
object args8,
object args9,
object args10,
object args11,
object args12,
object args13,
object args14)
{
eventAggregatorBinding = eventAggregator.ToBinding();
this.toBinding = to is Binding toBinding ? toBinding : to.ToBinding();
parameters.Add(args1 is MarkupExtension ? args1 : args1.ToBinding());
parameters.Add(args2 is MarkupExtension ? args2 : args2.ToBinding());
parameters.Add(args3 is MarkupExtension ? args3 : args3.ToBinding());
parameters.Add(args4 is MarkupExtension ? args4 : args4.ToBinding());
parameters.Add(args5 is MarkupExtension ? args5 : args5.ToBinding());
parameters.Add(args6 is MarkupExtension ? args6 : args6.ToBinding());
parameters.Add(args7 is MarkupExtension ? args7 : args7.ToBinding());
parameters.Add(args8 is MarkupExtension ? args8 : args8.ToBinding());
parameters.Add(args9 is MarkupExtension ? args9 : args9.ToBinding());
parameters.Add(args10 is MarkupExtension ? args10 : args10.ToBinding());
parameters.Add(args11 is MarkupExtension ? args11 : args11.ToBinding());
parameters.Add(args12 is MarkupExtension ? args12 : args12.ToBinding());
parameters.Add(args13 is MarkupExtension ? args13 : args13.ToBinding());
parameters.Add(args14 is MarkupExtension ? args14 : args14.ToBinding());
}
public NavigateExtension(object eventAggregator,
object to,
object args1,
object args2,
object args3,
object args4,
object args5,
object args6,
object args7,
object args8,
object args9,
object args10,
object args11,
object args12,
object args13,
object args14,
object args15)
{
eventAggregatorBinding = eventAggregator.ToBinding();
this.toBinding = to is Binding toBinding ? toBinding : to.ToBinding();
parameters.Add(args1 is MarkupExtension ? args1 : args1.ToBinding());
parameters.Add(args2 is MarkupExtension ? args2 : args2.ToBinding());
parameters.Add(args3 is MarkupExtension ? args3 : args3.ToBinding());
parameters.Add(args4 is MarkupExtension ? args4 : args4.ToBinding());
parameters.Add(args5 is MarkupExtension ? args5 : args5.ToBinding());
parameters.Add(args6 is MarkupExtension ? args6 : args6.ToBinding());
parameters.Add(args7 is MarkupExtension ? args7 : args7.ToBinding());
parameters.Add(args8 is MarkupExtension ? args8 : args8.ToBinding());
parameters.Add(args9 is MarkupExtension ? args9 : args9.ToBinding());
parameters.Add(args10 is MarkupExtension ? args10 : args10.ToBinding());
parameters.Add(args11 is MarkupExtension ? args11 : args11.ToBinding());
parameters.Add(args12 is MarkupExtension ? args12 : args12.ToBinding());
parameters.Add(args13 is MarkupExtension ? args13 : args13.ToBinding());
parameters.Add(args14 is MarkupExtension ? args14 : args14.ToBinding());
parameters.Add(args15 is MarkupExtension ? args15 : args15.ToBinding());
}
public object? Route
{
get
{
return route;
}
set
{
route = value;
if (route is not null)
{
routeBinding = route.ToBinding();
}
}
}
protected override void OnInvoked(object sender, EventArgs args)
{
if (TargetObject is not null)
{
TargetObject.Bind(EventAggregatorProperty, eventAggregatorBinding);
if (TargetObject.GetValue(EventAggregatorProperty) is IEventAggregator eventAggregator)
{
TargetObject.Bind(ToProperty, toBinding);
if (TargetObject.GetValue(ToProperty) is { } to)
{
object? route = null;
if (routeBinding is not null)
{
TargetObject.Bind(RouteProperty, routeBinding);
route = TargetObject.GetValue(RouteProperty);
}
if (to is string name)
{
if (toBinding?.StringFormat is string format)
{
name = string.Format(format, name);
}
eventAggregator.Publish(new Navigate(name, parameters.ToArray()) { Route = route });
}
if (to is Type type)
{
eventAggregator.Publish(new Navigate(type, parameters.ToArray()) { Route = route });
}
}
}
base.OnInvoked(sender, args);
}
}
}
@@ -0,0 +1,86 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.Primitives;
using Avalonia.Data;
using Avalonia.Interactivity;
using Avalonia.Markup.Xaml;
using TheXamlGuy.UI.Avalonia;
namespace TheXamlGuy.Framework.Avalonia;
public class RouteExtension : MarkupExtension
{
private static readonly AttachedProperty<object> RouteProperty =
AvaloniaProperty.RegisterAttached<RouteExtension, Control, object>("Route");
private readonly string name;
private readonly Binding routeBinding;
public RouteExtension(object route, string name)
{
routeBinding = route.ToBinding();
this.name = name;
}
private bool TryGetBinding(AvaloniaObject sender, out object? binding)
{
binding = sender.GetValue(StyledElement.DataContextProperty);
return binding is not null;
}
public override object? ProvideValue(IServiceProvider serviceProvider)
{
if (serviceProvider.GetService(typeof(IProvideValueTarget)) is IProvideValueTarget target)
{
if (target.TargetObject is TemplatedControl control)
{
if (!TryGetBinding(control, out object? binding))
{
void HandleDataContextChanged(object? sender, EventArgs args)
{
if (TryGetBinding(control, out binding))
{
control.Loaded -= HandleLoaded;
control.Bind(RouteProperty, routeBinding);
if (control?.GetValue(RouteProperty) is IRouter route)
{
route.Add(name, control);
control.ClearValue(RouteProperty);
}
}
}
control.DataContextChanged += HandleDataContextChanged;
void HandleLoaded(object? sender, RoutedEventArgs args)
{
control.Loaded -= HandleLoaded;
if (TryGetBinding(control, out binding))
{
control.Bind(RouteProperty, routeBinding);
if (control?.GetValue(RouteProperty) is IRouter route)
{
route.Add(name, control);
control.ClearValue(RouteProperty);
}
}
}
control.Loaded += HandleLoaded;
}
else
{
control.Bind(RouteProperty, routeBinding);
if (control?.GetValue(RouteProperty) is IRouter route)
{
route.Add(name, control);
control.ClearValue(RouteProperty);
}
}
}
}
return null;
}
}
@@ -0,0 +1,3 @@
using Avalonia.Metadata;
[assembly: XmlnsDefinition("https://github.com/avaloniaui", "TheXamlGuy.Framework.Avalonia")]
Binary file not shown.
@@ -0,0 +1,30 @@
using Avalonia.Controls;
using Avalonia.Controls.Primitives;
using FluentAvalonia.UI.Controls;
namespace TheXamlGuy.Framework.Avalonia;
public class ContentDialogRouteHandler : RouteHandler<ContentDialog>
{
public override async void Handle(Route<ContentDialog> request)
{
if (request.Template is ContentDialog contentDialog)
{
contentDialog.DataContext = request.Data;
await contentDialog.ShowAsync();
}
}
}
public class ContentControlRouteHandler : RouteHandler<ContentControl>
{
public override void Handle(Route<ContentControl> request)
{
if (request.Template is TemplatedControl control)
{
control.DataContext = request.Data;
request.Target.Content = control;
}
}
}
@@ -0,0 +1,26 @@
using Avalonia.Controls.Primitives;
using FluentAvalonia.UI.Controls;
using FluentAvalonia.UI.Navigation;
namespace TheXamlGuy.Framework.Avalonia;
public class FrameRouteHandler : RouteHandler<Frame>
{
public override void Handle(Route<Frame> request)
{
if (request.Template is Type type)
{
void HandleNavigated(object sender, NavigationEventArgs args)
{
request.Target.Navigated -= HandleNavigated;
if (request.Target.Content is TemplatedControl control)
{
control.DataContext = request.Data;
}
}
request.Target.Navigated += HandleNavigated;
request.Target.Navigate(type);
}
}
}
@@ -0,0 +1,8 @@
namespace TheXamlGuy.Framework.Avalonia;
public interface IRouteDescriptor
{
object Route { get; }
string? Name { get; }
}
@@ -0,0 +1,6 @@
namespace TheXamlGuy.Framework.Avalonia;
public interface IRouteDescriptorCollection : IList<IRouteDescriptor>
{
}
+6
View File
@@ -0,0 +1,6 @@
namespace TheXamlGuy.Framework.Avalonia;
public interface IRouter
{
void Add(string name, object route);
}
@@ -0,0 +1,19 @@
using TheXamlGuy.Framework.Core;
namespace TheXamlGuy.Framework.Avalonia
{
public class NavigateHandler : IMediatorHandler<Navigate>
{
private readonly IEventAggregator eventAggregator;
public NavigateHandler(IEventAggregator eventAggregator)
{
this.eventAggregator = eventAggregator;
}
public void Handle(Navigate request)
{
eventAggregator.Publish(request);
}
}
}
+30
View File
@@ -0,0 +1,30 @@
namespace TheXamlGuy.Framework.Avalonia;
public class Navigated<TContent, TDataContext> where TContent : class where TDataContext : class
{
public Navigated()
{
}
public Navigated(TContent content, TDataContext dataContext, IDictionary<string, object>? parameters = null)
{
Content = content;
DataContext = dataContext;
Parameters = parameters;
}
public TContent? Content { get; }
public TDataContext? DataContext { get; }
public IDictionary<string, object>? Parameters { get; }
}
public class Navigated
{
public static Navigated<TContent, TDataTemplate> Create<TContent, TDataTemplate>(TContent content, TDataTemplate dataContext, IDictionary<string, object>? parameters = null) where TContent : class where TDataTemplate : class
{
return new Navigated<TContent, TDataTemplate>(content, dataContext, parameters);
}
}
+5
View File
@@ -0,0 +1,5 @@
using Avalonia.Controls.Primitives;
namespace TheXamlGuy.Framework.Avalonia;
public record Route<TTarget>(TTarget Target, object? Data, object? Template) where TTarget : TemplatedControl;

Some files were not shown because too many files have changed in this diff Show More