- Opening new window to edit

- Two views staying in sync when the color of connection is changed
This commit is contained in:
eelke 2024-11-17 13:55:14 +01:00
parent 5e81a76966
commit b846a60f25
17 changed files with 271 additions and 45 deletions

View file

@ -17,6 +17,7 @@
<PackageVersion Include="Avalonia.ReactiveUI" Version="11.2.1" /> <PackageVersion Include="Avalonia.ReactiveUI" Version="11.2.1" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.Sqlite" Version="9.0.0" /> <PackageVersion Include="Microsoft.EntityFrameworkCore.Sqlite" Version="9.0.0" />
<PackageVersion Include="Npgsql" Version="8.0.5" /> <PackageVersion Include="Npgsql" Version="8.0.5" />
<PackageVersion Include="Pure.DI" Version="2.1.38" />
<PackageVersion Include="Xamarin.AndroidX.Core.SplashScreen" Version="1.0.1.1" /> <PackageVersion Include="Xamarin.AndroidX.Core.SplashScreen" Version="1.0.1.1" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View file

@ -16,6 +16,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
Directory.Packages.props = Directory.Packages.props Directory.Packages.props = Directory.Packages.props
EndProjectSection EndProjectSection
EndProject EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "UI", "UI", "{EBBC2081-5061-4843-B420-AB4C48A5C283}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU Debug|Any CPU = Debug|Any CPU
@ -43,6 +45,11 @@ Global
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE
EndGlobalSection EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{ABC31E74-02FF-46EB-B3B2-4E6AE43B456C} = {EBBC2081-5061-4843-B420-AB4C48A5C283}
{EBD9022F-BC83-4846-9A11-6F7F3772DC64} = {EBBC2081-5061-4843-B420-AB4C48A5C283}
{7AD1DAC8-7FBE-49D5-8614-7321233DB82E} = {EBBC2081-5061-4843-B420-AB4C48A5C283}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {83CB65B8-011F-4ED7-BCD3-A6CFA935EF7E} SolutionGuid = {83CB65B8-011F-4ED7-BCD3-A6CFA935EF7E}
EndGlobalSection EndGlobalSection

View file

@ -2,6 +2,7 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:pgLabII" xmlns:local="using:pgLabII"
x:Class="pgLabII.App" x:Class="pgLabII.App"
xmlns:app="using:pgLabII"
RequestedThemeVariant="Default"> RequestedThemeVariant="Default">
<!-- "Default" ThemeVariant follows system theme variant. "Dark" or "Light" are other available options. --> <!-- "Default" ThemeVariant follows system theme variant. "Dark" or "Light" are other available options. -->
@ -11,5 +12,10 @@
<Application.Styles> <Application.Styles>
<FluentTheme /> <FluentTheme />
<StyleInclude Source="avares://Avalonia.Controls.ColorPicker/Themes/Fluent/Fluent.xaml" />
</Application.Styles> </Application.Styles>
<Application.Resources>
<app:Composition x:Key="Composition" />
</Application.Resources>
</Application> </Application>

View file

@ -1,4 +1,4 @@
using Avalonia; using Avalonia;
using Avalonia.Controls.ApplicationLifetimes; using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Markup.Xaml; using Avalonia.Markup.Xaml;
using pgLabII.ViewModels; using pgLabII.ViewModels;
@ -15,22 +15,27 @@ public partial class App : Application
public override void OnFrameworkInitializationCompleted() public override void OnFrameworkInitializationCompleted()
{ {
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) if (Resources[nameof(Composition)] is Composition composition)
{ {
desktop.MainWindow = new MainWindow switch (ApplicationLifetime)
{ {
DataContext = new MainViewModel() case IClassicDesktopStyleApplicationLifetime desktop:
}; desktop.MainWindow = composition.MainWindow;
} break;
else if (ApplicationLifetime is ISingleViewApplicationLifetime singleViewPlatform)
{ case ISingleViewApplicationLifetime singleViewPlatform:
singleViewPlatform.MainView = new MainView singleViewPlatform.MainView = composition.MainWindow;
break;
}
// Handles disposables
if (ApplicationLifetime is IControlledApplicationLifetime controlledApplicationLifetime)
{ {
DataContext = new MainViewModel() //controlledApplicationLifetime.Exit += (_, _) => composition.Dispose();
}; }
} }
base.OnFrameworkInitializationCompleted(); base.OnFrameworkInitializationCompleted();
} }
} }

20
pgLabII/Composition.cs Normal file
View file

@ -0,0 +1,20 @@
using pgLabII.ViewModels;
using pgLabII.Views;
using Pure.DI;
using static Pure.DI.Lifetime;
namespace pgLabII;
internal partial class Composition
{
public void Setup() => DI.Setup()
.Root<MainWindow>(nameof(MainWindow))
// .Root<ServerListView>(nameof(ServerListView))
.Root<MainViewModel>(nameof(MainViewModel))
// .Bind().As(Singleton).To<MainViewModel>()
.Root<ServerListViewModel>(nameof(ServerListViewModel))
// .Bind().As(Singleton).To<ServerListViewModel>()
;
}

View file

@ -1,19 +0,0 @@
using Npgsql;
using System.Collections.ObjectModel;
namespace pgLabII;
public class ServerConfiguration
{
/// <summary>
/// For the user to help him identify the item
/// </summary>
public string Name { get; set; } = "";
public string Host { get; set; } = "";
public ushort Port { get; set; } = 5432;
public string InitialDatabase { get; set; } = "";
public SslMode DefaultSslMode { get; set; } = SslMode.Prefer;
public ObservableCollection<ServerUser> Users { get; } = [];
}

View file

@ -0,0 +1,54 @@
using System;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Reactive;
using Avalonia.Media;
using Npgsql;
using pgLabII.Views;
using ReactiveUI;
namespace pgLabII.ViewModels;
public class ServerConfiguration : ReactiveObject
{
private Color? _color;
public Guid Id { get; set; } = Guid.NewGuid();
/// <summary>
/// For the user to help him identify the item
/// </summary>
public string Name { get; set; } = "";
public Color? Color
{
get => _color;
set
{
if (_color != value)
{
_color = value;
this.RaisePropertyChanged();
this.RaisePropertyChanged(propertyName: nameof(BackgroundBrush));
}
}
}
public string Host { get; set; } = "";
public ushort Port { get; set; } = 5432;
public string InitialDatabase { get; set; } = "";
public SslMode DefaultSslMode { get; set; } = SslMode.Prefer;
public IBrush? BackgroundBrush => Color.HasValue ? new SolidColorBrush(Color.Value) : null;
public ObservableCollection<ServerUser> Users { get; } = [];
public ReactiveCommand<Unit, Unit> EditCommand { get; }
public ServerConfiguration()
{
EditCommand = ReactiveCommand.Create(() =>
{
EditServerConfigurationWindow window = new() { DataContext = this };
window.Show();
});
}
}

View file

@ -1,13 +1,39 @@
using System; using System;
using System.Collections.Generic;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using System.Linq; using System.Linq;
using System.Text; using ReactiveUI;
using System.Threading.Tasks; using System.Reactive;
using Avalonia.Media;
using DynamicData;
namespace pgLabII.ViewModels; namespace pgLabII.ViewModels;
public class ServerListViewModel : ViewModelBase public class ServerListViewModel : ViewModelBase
{ {
public ObservableCollection<ServerConfiguration> ServerConfigurations { get; } = []; public ObservableCollection<ServerConfiguration> ServerConfigurations { get; } =
[
new ServerConfiguration()
{
Name = "Foo",
Color = Colors.Aquamarine,
Host = "db.host.nl"
},
new ServerConfiguration()
{
Name = "Bar",
Color = Colors.Bisque,
Host = "db.host.nl"
}
];
public ReactiveCommand<ServerConfiguration, Unit> RemoveServerCommand { get; }
public ServerListViewModel()
{
RemoveServerCommand = ReactiveCommand.Create<ServerConfiguration, Unit>((sc) =>
{
ServerConfigurations.Remove(sc);
return Unit.Default;
});
}
} }

View file

@ -1,7 +1,7 @@
using Npgsql; using Npgsql;
using pgLabII.ViewModels; using pgLabII.ViewModels;
namespace pgLabII; namespace pgLabII.ViewModels;
public class ServerUser : ViewModelBase public class ServerUser : ViewModelBase
{ {

View file

@ -1,6 +1,6 @@
using ReactiveUI; using ReactiveUI;
namespace pgLabII.ViewModels; namespace pgLabII;
public abstract class ViewModelBase : ReactiveObject public abstract class ViewModelBase : ReactiveObject
{ {

View file

@ -0,0 +1,29 @@
<Window xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
xmlns:vm="clr-namespace:pgLabII.ViewModels"
x:DataType="vm:ServerConfiguration"
x:Class="pgLabII.Views.EditServerConfigurationWindow"
Title="EditServerConfiguration">
<Design.DataContext>
<!-- This only sets the DataContext for the previewer in an IDE,
to set the actual DataContext for runtime, set the DataContext property in code (look at App.axaml.cs) -->
<vm:ServerConfiguration />
</Design.DataContext>
<StackPanel HorizontalAlignment="Stretch" VerticalAlignment="Top">
<TextBlock>Name:</TextBlock>
<TextBox Text="{Binding Name}"/>
<TextBlock>Color:</TextBlock>
<StackPanel Orientation="Horizontal">
<ColorPicker Color="{Binding Color}"/>
</StackPanel>
<TextBlock>Host:</TextBlock>
<TextBox Text="{Binding Host}"/>
</StackPanel>
</Window>

View file

@ -0,0 +1,14 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
namespace pgLabII.Views;
public partial class EditServerConfigurationWindow : Window
{
public EditServerConfigurationWindow()
{
InitializeComponent();
}
}

View file

@ -4,13 +4,12 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:vm="clr-namespace:pgLabII.ViewModels" xmlns:vm="clr-namespace:pgLabII.ViewModels"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
xmlns:app="clr-namespace:pgLabII"
DataContext="{StaticResource Composition}"
x:Class="pgLabII.Views.MainView" x:Class="pgLabII.Views.MainView"
x:DataType="vm:MainViewModel"> x:DataType="app:Composition">
<Design.DataContext>
<!-- This only sets the DataContext for the previewer in an IDE,
to set the actual DataContext for runtime, set the DataContext property in code (look at App.axaml.cs) -->
<vm:MainViewModel />
</Design.DataContext>
<TextBlock Text="{Binding Greeting}" HorizontalAlignment="Center" VerticalAlignment="Center"/> <StackPanel HorizontalAlignment="Center" VerticalAlignment="Center" DataContext="{Binding MainViewModel}">
<TextBlock Text="{Binding Greeting}" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</StackPanel>
</UserControl> </UserControl>

View file

@ -8,5 +8,5 @@
x:Class="pgLabII.Views.MainWindow" x:Class="pgLabII.Views.MainWindow"
Icon="/Assets/avalonia-logo.ico" Icon="/Assets/avalonia-logo.ico"
Title="pgLabII"> Title="pgLabII">
<views:MainView /> <views:ServerListView />
</Window> </Window>

View file

@ -0,0 +1,60 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
xmlns:vm="clr-namespace:pgLabII.ViewModels"
xmlns:app="clr-namespace:pgLabII"
DataContext="{StaticResource Composition}"
x:DataType="app:Composition"
x:Class="pgLabII.Views.ServerListView">
<StackPanel x:Name="ServerList" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" DataContext="{Binding ServerListViewModel}">
<ListBox x:Name="Servers" ItemsSource="{Binding ServerConfigurations}">
<ListBox.ItemTemplate >
<DataTemplate>
<Border BorderBrush="{Binding BackgroundBrush}" BorderThickness="2">
<Grid ColumnDefinitions="*,*">
<StackPanel
Orientation="Vertical"
HorizontalAlignment="Stretch"
Grid.Row="0"
Grid.Column="0"
>
<TextBlock Text="{Binding Name}" FontSize="18"/>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Host}" />
<TextBlock Text=":" />
<TextBlock Text="{Binding Port}" />
</StackPanel>
</StackPanel>
<StackPanel
Orientation="Horizontal"
HorizontalAlignment="Right"
Grid.Row="0"
Grid.Column="1"
>
<Button>DB</Button>
<Button>Server</Button>
<Button Content="...">
<Button.Flyout>
<MenuFlyout>
<MenuItem Header="Edit" Command="{Binding EditCommand}"/>
<Separator/>
<MenuItem Header="Remove"
Command="{Binding #ServerList.((vm:ServerListViewModel)DataContext).RemoveServerCommand}"
CommandParameter="{Binding .}"
Foreground="Crimson"
/>
</MenuFlyout>
</Button.Flyout>
</Button>
</StackPanel>
</Grid>
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</StackPanel>
</UserControl>

View file

@ -0,0 +1,13 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
namespace pgLabII.Views;
public partial class ServerListView : UserControl
{
public ServerListView()
{
InitializeComponent();
}
}

View file

@ -20,5 +20,16 @@
<PrivateAssets Condition="'$(Configuration)' != 'Debug'">All</PrivateAssets> <PrivateAssets Condition="'$(Configuration)' != 'Debug'">All</PrivateAssets>
</PackageReference> </PackageReference>
<PackageReference Include="Avalonia.ReactiveUI" /> <PackageReference Include="Avalonia.ReactiveUI" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" />
<PackageReference Include="Npgsql" />
<PackageReference Include="Pure.DI">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>
<Folder Include="ConnectionManager\" />
<Folder Include="Contracts\" />
</ItemGroup> </ItemGroup>
</Project> </Project>