This commit is contained in:
Thomas Peterson 2024-11-06 10:46:02 +01:00
parent 1ec07564e8
commit 9b5b71d46f
18 changed files with 229 additions and 63 deletions

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="LocationsWithSilentDeleteHolder">
<option name="locations">
<list>
<option value="$PROJECT_DIR$/PSCHelpdesk/PSCHelpdesk.Desktop/bin/Debug/net9.0/plugins" />
</list>
</option>
</component>
</project>

View File

@ -11,17 +11,21 @@
</component>
<component name="ChangeListManager">
<list default="true" id="95257dc5-08bd-4c50-8726-85956b3c2c92" name="Changes" comment="">
<change beforePath="$PROJECT_DIR$/.idea/.idea.PSCHelpdesk/.idea/avalonia.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/.idea.PSCHelpdesk/.idea/avalonia.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/.idea.PSCHelpdesk/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/.idea.PSCHelpdesk/.idea/workspace.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/HetznerServer/HetznerServer.cs" beforeDir="false" afterPath="$PROJECT_DIR$/HetznerServer/HetznerServer.cs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/HetznerServer/HetznerServer.csproj" beforeDir="false" afterPath="$PROJECT_DIR$/HetznerServer/HetznerServer.csproj" afterDir="false" />
<change beforePath="$PROJECT_DIR$/HetznerServer/ViewModels/ServerViewModel.cs" beforeDir="false" afterPath="$PROJECT_DIR$/HetznerServer/ViewModels/ServerViewModel.cs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/PSCHelpdesk.sln.DotSettings.user" beforeDir="false" afterPath="$PROJECT_DIR$/PSCHelpdesk.sln.DotSettings.user" afterDir="false" />
<change beforePath="$PROJECT_DIR$/PSCHelpdesk/PSCHelpdesk/Services/MenuService.cs" beforeDir="false" afterPath="$PROJECT_DIR$/PSCHelpdesk/PSCHelpdesk/Services/MenuService.cs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/PSCHelpdesk/PSCHelpdesk/PSCHelpdesk.csproj" beforeDir="false" afterPath="$PROJECT_DIR$/PSCHelpdesk/PSCHelpdesk/PSCHelpdesk.csproj" afterDir="false" />
<change beforePath="$PROJECT_DIR$/PSCHelpdesk/PSCHelpdesk/Services/PluginService.cs" beforeDir="false" afterPath="$PROJECT_DIR$/PSCHelpdesk/PSCHelpdesk/Services/PluginService.cs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/PSCHelpdesk/PSCHelpdesk/Startup.cs" beforeDir="false" afterPath="$PROJECT_DIR$/PSCHelpdesk/PSCHelpdesk/Startup.cs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/PSCHelpdesk/PSCHelpdesk/ViewLocator.cs" beforeDir="false" afterPath="$PROJECT_DIR$/PSCHelpdesk/PSCHelpdesk/ViewLocator.cs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/PSCHelpdesk/PSCHelpdesk/ViewModels/MainWindowViewModel.cs" beforeDir="false" afterPath="$PROJECT_DIR$/PSCHelpdesk/PSCHelpdesk/ViewModels/MainWindowViewModel.cs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/PSCHelpdesk/PSCHelpdesk/ViewModels/TestViewModel.cs" beforeDir="false" afterPath="$PROJECT_DIR$/PSCHelpdesk/PSCHelpdesk/ViewModels/TestViewModel.cs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/PSCHelpdesk/PSCHelpdesk/Views/ContentDisplay.axaml.cs" beforeDir="false" afterPath="$PROJECT_DIR$/PSCHelpdesk/PSCHelpdesk/Views/ContentDisplay.axaml.cs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/PSCHelpdesk/PSCHelpdesk/Views/MainWindow.axaml" beforeDir="false" afterPath="$PROJECT_DIR$/PSCHelpdesk/PSCHelpdesk/Views/MainWindow.axaml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/Shared/Menu/Item.cs" beforeDir="false" afterPath="$PROJECT_DIR$/Shared/Menu/Item.cs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise/Infrastructure/JsonSerializerParameterConverter.cs" beforeDir="false" afterPath="$PROJECT_DIR$/Vendor/Prise/Infrastructure/JsonSerializerParameterConverter.cs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/Shared/Plugin/Contract.cs" beforeDir="false" afterPath="$PROJECT_DIR$/Shared/Plugin/Contract.cs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/Shared/ViewModels/ViewModelBase.cs" beforeDir="false" afterPath="$PROJECT_DIR$/Shared/ViewModels/ViewModelBase.cs" afterDir="false" />
</list>
<option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" />
@ -35,20 +39,26 @@
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
</component>
<component name="HighlightingSettingsPerFile">
<setting file="file://$APPLICATION_CONFIG_DIR$/resharper-host/SourcesCache/1b81cb3be224213a6a73519b6e340a628d9a1fb8629c351a186a26f6376669/List.cs" root0="FORCE_HIGHLIGHTING" />
<setting file="file://$APPLICATION_CONFIG_DIR$/resharper-host/SourcesCache/1c9517d527f614396dfa453346e69acfefb958c4c59d7fbef256bbab3538d/ArgumentNullException.cs" root0="FORCE_HIGHLIGHTING" />
<setting file="file://$APPLICATION_CONFIG_DIR$/resharper-host/SourcesCache/1eb3d84af5e656ecdf75c8c4df55d5f931ced552db5e04c6fc85b4ecf45288/ConcurrentDictionary.cs" root0="FORCE_HIGHLIGHTING" />
<setting file="file://$APPLICATION_CONFIG_DIR$/resharper-host/SourcesCache/2e6883f773fb7c69a15db509adac9a0c068e4ca54fa119e835fd2324311c3b/Ioc.cs" root0="FORCE_HIGHLIGHTING" />
<setting file="file://$APPLICATION_CONFIG_DIR$/resharper-host/SourcesCache/5cde391207de75962d7bacb899ca2bd3985c86911b152d185b58999a422bf0/Type.CoreCLR.cs" root0="FORCE_HIGHLIGHTING" />
<setting file="file://$APPLICATION_CONFIG_DIR$/resharper-host/SourcesCache/87c584767b46b5fd42769be76547105558e6690f785614efddca134b2d682/Type.cs" root0="FORCE_HIGHLIGHTING" />
<setting file="file://$APPLICATION_CONFIG_DIR$/resharper-host/SourcesCache/3136d46cb2145ae4698247cf0e3184f3890aa4e35a1642b3de4ed83203721fd/Type.Helpers.cs" root0="FORCE_HIGHLIGHTING" />
<setting file="file://$APPLICATION_CONFIG_DIR$/resharper-host/SourcesCache/473d97221b573ab97e6e745d8adae8b9e95a666539d6ed3cc8566b245d93a/ArgumentNullException.cs" root0="FORCE_HIGHLIGHTING" />
<setting file="file://$APPLICATION_CONFIG_DIR$/resharper-host/SourcesCache/5094e71058416d72278f32a6913f67a9c664bd46c296c5cce3ee63993dde3f/Type.cs" root0="FORCE_HIGHLIGHTING" />
<setting file="file://$APPLICATION_CONFIG_DIR$/resharper-host/SourcesCache/5ef9e37e2f99ef2688a1586afed1cff6eef912a11aa9b20a56943a255a6e6b/RuntimeHelpers.CoreCLR.cs" root0="FORCE_HIGHLIGHTING" />
<setting file="file://$APPLICATION_CONFIG_DIR$/resharper-host/SourcesCache/733ec677d6c51f97541ef76ab82bf19a08e02c42b0f78d439f4b3b24dfdbb/Attribute.CoreCLR.cs" root0="FORCE_HIGHLIGHTING" />
<setting file="file://$APPLICATION_CONFIG_DIR$/resharper-host/SourcesCache/7e333a9f3297ba553cccfd3b7c3f1f96125b23d09f883e4d6e66d531559a4c/Type.CoreCLR.cs" root0="FORCE_HIGHLIGHTING" />
<setting file="file://$APPLICATION_CONFIG_DIR$/resharper-host/SourcesCache/8874fa6fbc50b05ba8332188d36141eb4bba81fb1f92189ba9d7a25f545/ThrowHelper.cs" root0="FORCE_HIGHLIGHTING" />
<setting file="file://$APPLICATION_CONFIG_DIR$/resharper-host/SourcesCache/9d4f4ac7db6d2c5d183ab2d92602280ed4349fd6e6a1b6313546b3d01fdab5/ServiceProvider.cs" root0="FORCE_HIGHLIGHTING" />
<setting file="file://$APPLICATION_CONFIG_DIR$/resharper-host/SourcesCache/ad1d58b8dd22123dfae3f2cf5d8b199992465c9c344d032f93a826d8e5539ff/RuntimeType.CoreCLR.cs" root0="FORCE_HIGHLIGHTING" />
<setting file="file://$APPLICATION_CONFIG_DIR$/resharper-host/SourcesCache/bc57ab3db8ad1c2d647f4171d82a80762571212ac42bb1eac4ed63162acdc4ed/RuntimeType.cs" root0="FORCE_HIGHLIGHTING" />
<setting file="file://$APPLICATION_CONFIG_DIR$/resharper-host/SourcesCache/bd1d5c50194fea68ff3559c160230b0ab50f5acf4ce3061bffd6d62958e2182/ExceptionDispatchInfo.cs" root0="FORCE_HIGHLIGHTING" />
<setting file="file://$APPLICATION_CONFIG_DIR$/resharper-host/SourcesCache/baf2eef7c7bbea3742b74ee71fe7168c3a8c2269a1ce22d51333175656840/RuntimeType.CoreCLR.cs" root0="FORCE_HIGHLIGHTING" />
<setting file="file://$APPLICATION_CONFIG_DIR$/resharper-host/SourcesCache/bf9021a960b74107a7e141aa06bc9d8a0a53c929178c2fb95b1597be8af8dc/ExceptionDispatchInfo.cs" root0="FORCE_HIGHLIGHTING" />
<setting file="file://$APPLICATION_CONFIG_DIR$/resharper-host/SourcesCache/c05785bcebd2c944852db620e6681c606cd57f85b59fc5ddfcfbe9a68d634f/MemoryMarshal.CoreCLR.cs" root0="FORCE_HIGHLIGHTING" />
<setting file="file://$APPLICATION_CONFIG_DIR$/resharper-host/SourcesCache/e2e3d26278e439d44964729238a685ad58d3189abf8fb84cdfe34b893a290a2/JsonSerializerInternalWriter.cs" root0="FORCE_HIGHLIGHTING" />
<setting file="file://$APPLICATION_CONFIG_DIR$/resharper-host/SourcesCache/f3981d658666ec9cc1e6958fe22f8614bfe02ccb6625b056c3ece3729c9262/JsonConvert.cs" root0="FORCE_HIGHLIGHTING" />
<setting file="file://$APPLICATION_CONFIG_DIR$/resharper-host/SourcesCache/f91e6f22e2c4f30c4c01c74733e2bd93a2a62d298dd2793a59d01ea2134d/TypeNameResolver.CoreCLR.cs" root0="FORCE_HIGHLIGHTING" />
<setting file="file://$PROJECT_DIR$/HetznerServer/ViewModels/ServerViewModel.cs" root0="FORCE_HIGHLIGHTING" />
<setting file="file://$PROJECT_DIR$/HetznerServer/Views/ServerView.axaml" root0="FORCE_HIGHLIGHTING" />
<setting file="file://$PROJECT_DIR$/HetznerServer/Views/ServerView.axaml.cs" root0="FORCE_HIGHLIGHTING" />
<setting file="file://$PROJECT_DIR$/Vendor/Prise/AssemblyScanning/DefaultAssemblyResolver.cs" root0="FORCE_HIGHLIGHTING" />
<setting file="file://$PROJECT_DIR$/Vendor/Prise/DefaultPluginLoader.cs" root0="SKIP_HIGHLIGHTING" />
<setting file="file://$PROJECT_DIR$/Vendor/Prise/DependencyInjection/ServiceCollectionExtensions.cs" root0="FORCE_HIGHLIGHTING" />
</component>
<component name="InvalidFacetManager">
@ -74,6 +84,7 @@
</component>
<component name="PropertiesComponent"><![CDATA[{
"keyToString": {
".NET Project.PSCHelpdesk.Desktop ohne plugin.executor": "Run",
".NET Project.PSCHelpdesk.Desktop.executor": "Debug",
"Publish to folder.Build HetznerServer Plugin Debug.executor": "Run",
"Publish to folder.Publish HetznerServer to folder.executor": "Run",
@ -92,7 +103,7 @@
}]]></component>
<component name="RunManager" selected=".NET Project.PSCHelpdesk.Desktop">
<configuration name="Publish HetznerServer to folder" type="DotNetFolderPublish" factoryName="Publish to folder">
<riderPublish configuration="Debug" platform="Any CPU" runtime="Portable" target_folder="$PROJECT_DIR$/PSCHelpdesk/PSCHelpdesk.Desktop/bin/Debug/net9.0/plugins" target_framework="net9.0" uuid_high="6134591891200954270" uuid_low="-7110083162272853959" />
<riderPublish configuration="Debug" delete_existing_files="true" platform="Any CPU" runtime="Portable" target_folder="$PROJECT_DIR$/PSCHelpdesk/PSCHelpdesk.Desktop/bin/Debug/net9.0/plugins" target_framework="net9.0" uuid_high="6134591891200954270" uuid_low="-7110083162272853959" />
<method v="2" />
</configuration>
<configuration name="PSCHelpdesk.Browser" type="DotNetProject" factoryName=".NET Project">
@ -113,6 +124,24 @@
<option name="Build" />
</method>
</configuration>
<configuration name="PSCHelpdesk.Desktop ohne plugin" type="DotNetProject" factoryName=".NET Project">
<option name="EXE_PATH" value="$PROJECT_DIR$/PSCHelpdesk/PSCHelpdesk.Desktop/bin/Debug/net9.0/PSCHelpdesk.Desktop" />
<option name="PROGRAM_PARAMETERS" value="" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/PSCHelpdesk/PSCHelpdesk.Desktop/bin/Debug/net9.0" />
<option name="PASS_PARENT_ENVS" value="1" />
<option name="USE_EXTERNAL_CONSOLE" value="0" />
<option name="USE_MONO" value="0" />
<option name="RUNTIME_ARGUMENTS" value="" />
<option name="PROJECT_PATH" value="$PROJECT_DIR$/PSCHelpdesk/PSCHelpdesk.Desktop/PSCHelpdesk.Desktop.csproj" />
<option name="PROJECT_EXE_PATH_TRACKING" value="1" />
<option name="PROJECT_ARGUMENTS_TRACKING" value="1" />
<option name="PROJECT_WORKING_DIRECTORY_TRACKING" value="1" />
<option name="PROJECT_KIND" value="DotNetCore" />
<option name="PROJECT_TFM" value="net9.0" />
<method v="2">
<option name="Build" />
</method>
</configuration>
<configuration name="PSCHelpdesk.Desktop" type="DotNetProject" factoryName=".NET Project">
<option name="EXE_PATH" value="$PROJECT_DIR$/PSCHelpdesk/PSCHelpdesk.Desktop/bin/Debug/net9.0/PSCHelpdesk.Desktop" />
<option name="PROGRAM_PARAMETERS" value="" />
@ -151,6 +180,7 @@
<list>
<item itemvalue=".NET Project.PSCHelpdesk.Browser" />
<item itemvalue=".NET Project.PSCHelpdesk.Desktop" />
<item itemvalue=".NET Project.PSCHelpdesk.Desktop ohne plugin" />
<item itemvalue="Android.PSCHelpdesk.Android" />
<item itemvalue="iOS.PSCHelpdesk.iOS" />
<item itemvalue="Publish to folder.Publish HetznerServer to folder" />
@ -194,31 +224,102 @@
<component name="XDebuggerManager">
<breakpoint-manager>
<breakpoints>
<line-breakpoint enabled="true" type="DotNet Breakpoints">
<url>file://$PROJECT_DIR$/PSCHelpdesk/PSCHelpdesk/Views/ContentDisplay.axaml.cs</url>
<line>39</line>
<properties documentPath="$PROJECT_DIR$/PSCHelpdesk/PSCHelpdesk/Views/ContentDisplay.axaml.cs" containingFunctionPresentation="Property 'SelectedItem'">
<startOffsets>
<option value="1331" />
</startOffsets>
<endOffsets>
<option value="1374" />
</endOffsets>
</properties>
<option name="timeStamp" value="82" />
</line-breakpoint>
<line-breakpoint enabled="true" type="DotNet Breakpoints">
<url>file://$PROJECT_DIR$/HetznerServer/Menu/MainMenu.cs</url>
<line>13</line>
<properties documentPath="C:\Users\info\RiderProjects\pschelpdesk\HetznerServer\Menu\MainMenu.cs" containingFunctionPresentation="Method 'addMenu'">
<properties documentPath="C:\Users\info\RiderProjects\pschelpdesk\HetznerServer\Menu\MainMenu.cs" containingFunctionPresentation="Method 'addMenu'" />
<option name="timeStamp" value="92" />
</line-breakpoint>
<line-breakpoint enabled="true" type="DotNet Breakpoints">
<url>file://$PROJECT_DIR$/PSCHelpdesk/PSCHelpdesk/ViewModels/MainWindowViewModel.cs</url>
<line>93</line>
<properties documentPath="$PROJECT_DIR$/PSCHelpdesk/PSCHelpdesk/ViewModels/MainWindowViewModel.cs" containingFunctionPresentation="Property 'SelectedContent'">
<startOffsets>
<option value="335" />
<option value="2635" />
</startOffsets>
<endOffsets>
<option value="428" />
<option value="2667" />
</endOffsets>
</properties>
<option name="timeStamp" value="92" />
<option name="timeStamp" value="128" />
</line-breakpoint>
<line-breakpoint enabled="true" type="DotNet Breakpoints">
<url>file://$PROJECT_DIR$/PSCHelpdesk/PSCHelpdesk/ViewModels/MainWindowViewModel.cs</url>
<line>94</line>
<properties documentPath="$PROJECT_DIR$/PSCHelpdesk/PSCHelpdesk/ViewModels/MainWindowViewModel.cs" containingFunctionPresentation="Property 'SelectedContent'">
<startOffsets>
<option value="2684" />
</startOffsets>
<endOffsets>
<option value="2694" />
</endOffsets>
</properties>
<option name="timeStamp" value="129" />
</line-breakpoint>
<line-breakpoint enabled="true" type="DotNet Breakpoints">
<url>file://$PROJECT_DIR$/PSCHelpdesk/PSCHelpdesk/ViewLocator.cs</url>
<line>25</line>
<properties documentPath="$PROJECT_DIR$/PSCHelpdesk/PSCHelpdesk/ViewLocator.cs" containingFunctionPresentation="Method 'Build'">
<startOffsets>
<option value="661" />
</startOffsets>
<endOffsets>
<option value="691" />
</endOffsets>
</properties>
<option name="timeStamp" value="131" />
</line-breakpoint>
<line-breakpoint enabled="true" type="DotNet Breakpoints">
<url>file://$PROJECT_DIR$/PSCHelpdesk/PSCHelpdesk/ViewLocator.cs</url>
<line>27</line>
<properties documentPath="$PROJECT_DIR$/PSCHelpdesk/PSCHelpdesk/ViewLocator.cs" containingFunctionPresentation="Method 'Build'">
<startOffsets>
<option value="709" />
</startOffsets>
<endOffsets>
<option value="726" />
</endOffsets>
</properties>
<option name="timeStamp" value="132" />
</line-breakpoint>
<line-breakpoint enabled="true" type="DotNet Breakpoints">
<url>file://$PROJECT_DIR$/PSCHelpdesk/PSCHelpdesk/ViewModels/MainWindowViewModel.cs</url>
<line>113</line>
<properties documentPath="$PROJECT_DIR$/PSCHelpdesk/PSCHelpdesk/ViewModels/MainWindowViewModel.cs" containingFunctionPresentation="Method 'SelectMenu'">
<startOffsets>
<option value="3273" />
</startOffsets>
<endOffsets>
<option value="3309" />
</endOffsets>
</properties>
<option name="timeStamp" value="136" />
</line-breakpoint>
<line-breakpoint enabled="true" type="DotNet Breakpoints">
<url>file://$PROJECT_DIR$/PSCHelpdesk/PSCHelpdesk/ViewModels/MainWindowViewModel.cs</url>
<line>86</line>
<properties documentPath="$PROJECT_DIR$/PSCHelpdesk/PSCHelpdesk/ViewModels/MainWindowViewModel.cs" containingFunctionPresentation="Property 'SelectedContent'">
<startOffsets>
<option value="2421" />
</startOffsets>
<endOffsets>
<option value="2454" />
</endOffsets>
</properties>
<option name="timeStamp" value="137" />
</line-breakpoint>
<line-breakpoint enabled="true" type="DotNet Breakpoints">
<url>file://$PROJECT_DIR$/PSCHelpdesk/PSCHelpdesk/ViewModels/MainWindowViewModel.cs</url>
<line>107</line>
<properties documentPath="$PROJECT_DIR$/PSCHelpdesk/PSCHelpdesk/ViewModels/MainWindowViewModel.cs" containingFunctionPresentation="Method 'SelectMenu'">
<startOffsets>
<option value="3082" />
</startOffsets>
<endOffsets>
<option value="3115" />
</endOffsets>
</properties>
<option name="timeStamp" value="138" />
</line-breakpoint>
</breakpoints>
</breakpoint-manager>

View File

@ -18,20 +18,24 @@ public class HetznerServer : Contract
return "HetznerServerPlugin";
}
public void addMenu()
public Item addMenu()
{
var menuService = Ioc.Default.GetService<IMenuService>();
//var menuService = Ioc.Default.GetService<IMenuService>();
var serverTab = new Item()
{
Header = "Server",
ViewModel = typeof(ServerViewModel)
};
menuService.AddMenuItem(serverTab);
//return serverTab;
//menuService.AddMenuItem(serverTab);
return serverTab;
}
public UserControl load()
public UserControl LoadView()
{
return new ServerView();
}
public object LoadViewModel()
{
return new ServerViewModel();
}
}

View File

@ -19,10 +19,7 @@
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Shared\Shared.csproj" />
<ProjectReference Include="..\Vendor\Prise.Plugin\Prise.Plugin.csproj" />
<ProjectReference Include="..\Vendor\Prise.Proxy\Prise.Proxy.csproj" />
<ProjectReference Include="..\Vendor\Prise.ReverseProxy\Prise.ReverseProxy.csproj" />
<ProjectReference Include="..\Shared\Shared.csproj" Private="false" />
</ItemGroup>
<ItemGroup>
@ -44,6 +41,8 @@
<PackageReference Include="Avalonia.Xaml.Interactions" Version="11.2.0" />
<PackageReference Include="HetznerCloud.API" Version="1.1.9" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="8.0.1" />
<PackageReference Include="Prise.Plugin" Version="6.0.0" />
<PackageReference Include="Prise.ReverseProxy" Version="6.1.0" />
</ItemGroup>
</Project>

View File

@ -1,9 +1,5 @@
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Threading.Tasks;
using System.Collections.ObjectModel;
using Avalonia.Controls;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using HetznerCloudApi;
using PSCHelpdesk.Plugins.HetznerServer.Models;
@ -12,7 +8,7 @@ using PSCHelpdesk.Shared.ViewModels;
namespace PSCHelpdesk.Plugins.HetznerServer.ViewModels;
public partial class ServerViewModel : ViewModelBase
public partial class ServerViewModel : ViewModelBase, IViewModelBase
{
public ServerViewModel()
{

View File

@ -26,12 +26,14 @@
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AJsonSerializerInternalWriter_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FSourcesCache_003Fe2e3d26278e439d44964729238a685ad58d3189abf8fb84cdfe34b893a290a2_003FJsonSerializerInternalWriter_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AList_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FSourcesCache_003F1b81cb3be224213a6a73519b6e340a628d9a1fb8629c351a186a26f6376669_003FList_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AMemoryExtensions_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FSourcesCache_003Fd7bc48c79f70bd7a187cf86258b2815e2deb22274953837f735bbfe18f6c69e2_003FMemoryExtensions_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AMemoryMarshal_002ECoreCLR_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FSourcesCache_003Fc05785bcebd2c944852db620e6681c606cd57f85b59fc5ddfcfbe9a68d634f_003FMemoryMarshal_002ECoreCLR_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AMethodBaseInvoker_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FSourcesCache_003Fd6b757e154dd7f8c23e0e785431c97a76e4b9c6bdae38b978238421dbab55d_003FMethodBaseInvoker_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003APath_002EUnix_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FSourcesCache_003Fad21a37fb9c62642a9445c29321d3d136d19fa60425b26806692bbfee3523c_003FPath_002EUnix_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003APublicNet_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F95e899f2b13d4189874af98ec00443321e400_003F0d_003F00fcbad0_003FPublicNet_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AReactiveCommandBase_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FSourcesCache_003F9d493cae194a42808b62a282d8d797b4ef18a9435baa6da7a73bee8e66ca1_003FReactiveCommandBase_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AReadOnlySpan_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FSourcesCache_003Fd0d96f40fdd9bc395fad59e4a8a6539e4eecce4865809ef4be1a473f911eceaa_003FReadOnlySpan_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AReplaySubject_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FSourcesCache_003F27be5d106a789638721745a2a46f9cb0f7a39905117d644638b6e0d56261be_003FReplaySubject_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ARuntimeHelpers_002ECoreCLR_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FSourcesCache_003F5ef9e37e2f99ef2688a1586afed1cff6eef912a11aa9b20a56943a255a6e6b_003FRuntimeHelpers_002ECoreCLR_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ARuntimeType_002ECoreCLR_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FSourcesCache_003Fad1d58b8dd22123dfae3f2cf5d8b199992465c9c344d032f93a826d8e5539ff_003FRuntimeType_002ECoreCLR_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ARuntimeType_002ECoreCLR_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FSourcesCache_003Fbaf2eef7c7bbea3742b74ee71fe7168c3a8c2269a1ce22d51333175656840_003FRuntimeType_002ECoreCLR_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ARuntimeType_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FSourcesCache_003Fbc57ab3db8ad1c2d647f4171d82a80762571212ac42bb1eac4ed63162acdc4ed_003FRuntimeType_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
@ -46,10 +48,12 @@
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AThrowHelper_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FSourcesCache_003F4743f513c7ddc8411223a46f0ca426ed929391acebcff993721dff2f0c6b34_003FThrowHelper_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AThrowHelper_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FSourcesCache_003F8874fa6fbc50b05ba8332188d36141eb4bba81fb1f92189ba9d7a25f545_003FThrowHelper_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AThrowHelper_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FSourcesCache_003F8874fa6fbc50b05ba8332188d36141eb4bba81fb1f92189ba9d7a25f545_003FThrowHelper_002Ecs_002Fz_003A2_002D1/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ATypeNameResolver_002ECoreCLR_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FSourcesCache_003Ff91e6f22e2c4f30c4c01c74733e2bd93a2a62d298dd2793a59d01ea2134d_003FTypeNameResolver_002ECoreCLR_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AType_002ECoreCLR_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FSourcesCache_003F5cde391207de75962d7bacb899ca2bd3985c86911b152d185b58999a422bf0_003FType_002ECoreCLR_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AType_002ECoreCLR_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FSourcesCache_003F7e333a9f3297ba553cccfd3b7c3f1f96125b23d09f883e4d6e66d531559a4c_003FType_002ECoreCLR_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AType_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FSourcesCache_003F87c584767b46b5fd42769be76547105558e6690f785614efddca134b2d682_003FType_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AType_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FSourcesCache_003F5094e71058416d72278f32a6913f67a9c664bd46c296c5cce3ee63993dde3f_003FType_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AType_002EHelpers_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FSourcesCache_003F3136d46cb2145ae4698247cf0e3184f3890aa4e35a1642b3de4ed83203721fd_003FType_002EHelpers_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AUserControl_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FSourcesCache_003Fe6b66c6b133847f9a2c8b591fb074f9d100400_003F_005F4277f_003FUserControl_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/UserRules/=a0b4bc4d_002Dd13b_002D4a37_002Db37e_002Dc9c6864e4302/@EntryIndexedValue"></s:String>
<s:Boolean x:Key="/Default/CodeStyle/Naming/CSharpNaming/UserRules/=a0b4bc4d_002Dd13b_002D4a37_002Db37e_002Dc9c6864e4302/@EntryIndexRemoved">True</s:Boolean>
@ -60,7 +64,11 @@
&lt;/AssemblyExplorer&gt;</s:String>
<s:Boolean x:Key="/Default/UnloadedProject/UnloadedProjects/=1868ceb9_002D4dab_002D4196_002D91ae_002D60765bdd9820_0023PSCHelpdesk_002EiOS/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UnloadedProject/UnloadedProjects/=1c4ca302_002Da031_002D439a_002Dbfcb_002D42c4bac467f2_0023PSCHelpdesk_002EAndroid/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UnloadedProject/UnloadedProjects/=52efdd1b_002Db775_002D49a1_002Dbd3d_002De7b7f6a989ea_0023Prise_002EReverseProxy/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UnloadedProject/UnloadedProjects/=79029f78_002D5113_002D46e4_002D8896_002D436707a7251f_0023Prise_002EProxy/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UnloadedProject/UnloadedProjects/=a910fef2_002D046b_002D4956_002Dbc0a_002Daa57ec9a6b27_0023PSCHelpdesk_002EBrowser/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UnloadedProject/UnloadedProjects/=ad222f87_002Deac5_002D4120_002Daa33_002Deb32df2ddcd5_0023Prise/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UnloadedProject/UnloadedProjects/=f4ef7157_002Dc5f0_002D4444_002D9e49_002D28f6bd56295f_0023Prise_002EPlugin/@EntryIndexedValue">True</s:Boolean>

View File

@ -0,0 +1,14 @@
using System;
using Prise.Proxy;
namespace PSCHelpdesk.Converter;
public class AvaloniaPluginResultConverter : ResultConverter
{
public override object Deserialize(Type localType, Type remoteType, object value)
{
// No conversion, no backwards compatibility
// When the host upgrades any Avalonia dependency, it will break
return value;
}
}

View File

@ -19,16 +19,15 @@
<PackageReference Condition="'$(Configuration)' == 'Debug'" Include="Avalonia.Diagnostics" Version="11.2.0" />
<PackageReference Include="Avalonia.Xaml.Behaviors" Version="11.2.0" />
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.3.2" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="8.0.1" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="Nucs.JsonSettings2" Version="2.0.3" />
<PackageReference Include="Prise" Version="6.0.0" />
<PackageReference Include="Prise.Proxy" Version="6.1.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\HetznerServer\HetznerServer.csproj" />
<ProjectReference Include="..\..\Nextcloud\Nextcloud.csproj" />
<ProjectReference Include="..\..\Shared\Shared.csproj" />
<ProjectReference Include="..\..\Vendor\Prise.Plugin\Prise.Plugin.csproj" />
<ProjectReference Include="..\..\Vendor\Prise\Prise.csproj" />
</ItemGroup>
<ItemGroup>

View File

@ -1,6 +1,7 @@
using System.Linq;
using CommunityToolkit.Mvvm.DependencyInjection;
using Microsoft.Extensions.DependencyInjection;
using PSCHelpdesk.Shared.Menu;
using PSCHelpdesk.Shared.Plugin;
using PSCHelpdesk.Shared.Service;
@ -71,7 +72,8 @@ public class PluginService
var plugin = await pluginLoader.LoadPlugin<Contract>(pluginToEnable, configure: (context) =>
{
context
.AddHostTypes(new[] {typeof(Application), typeof(Item)})
.AddRemoteTypes(new []{typeof(Item)})
.AddHostService<IMenuService>(menuService)
.AddHostService<ITestService>(testService)
//.AddHostService<SettingsManager>(settingsService)
@ -83,7 +85,10 @@ public class PluginService
if (!this.loadedPlugins.ContainsKey(pluginName))
{
loadedPlugins.Add(plugin.GetName(), plugin);
plugin.addMenu();
var item = plugin.addMenu();
item.GetView = plugin.LoadView();
item.ViewModel = plugin.LoadViewModel();
menuService.AddMenuItem(item);
appService.AppIsStarted();
}
}

View File

@ -1,6 +1,8 @@
using CommunityToolkit.Mvvm.DependencyInjection;
using Microsoft.Extensions.DependencyInjection;
using Prise.DependencyInjection;
using Prise.Proxy;
using PSCHelpdesk.Converter;
using PSCHelpdesk.Services;
using PSCHelpdesk.Shared.Service;
using PSCHelpdesk.ViewModels;
@ -15,6 +17,7 @@ class Startup
var te = new ServiceCollection()
.AddPrise()
.AddFactory<IResultConverter>(()=> new AvaloniaPluginResultConverter())
.AddSingleton<AppService>()
.AddSingleton<IMenuService>(menuService)
.AddSingleton<ITestService>(new TestService())

View File

@ -1,15 +1,24 @@
using System;
using System.Reflection;
using Avalonia.Controls;
using Avalonia.Controls.Templates;
using CommunityToolkit.Mvvm.DependencyInjection;
using PSCHelpdesk.Services;
using PSCHelpdesk.Shared.ViewModels;
using PSCHelpdesk.ViewModels;
namespace PSCHelpdesk;
public class ViewLocator : IDataTemplate
{
private PluginService _pluginService;
public Control? Build(object? data)
{
if (_pluginService == null)
{
_pluginService = Ioc.Default.GetService<PluginService>();
}
if (data is null)
return null;
@ -24,8 +33,10 @@ public class ViewLocator : IDataTemplate
return new TextBlock { Text = "Not Found: " + name };
}
public bool Match(object? data)
public bool Match(object data)
{
return data is ViewModelBase;
var l = data is IViewModelBase;
Console.WriteLine($"[{l}:{data}]");
return l;
}
}

View File

@ -84,9 +84,14 @@ public class MainWindowViewModel : ViewModelBase
{
get
{
if (SelectedItem.GetView != null)
{
var vm = SelectedItem.GetView;
return vm;
}
if (SelectedItem.ViewModel != null)
{
var vm = SelectedItem.ViewModel.CreateInstance();
var vm = SelectedItem.ViewModel;
return vm;
}
return this.SelectedItem?.CommandParameter;
@ -100,9 +105,13 @@ public class MainWindowViewModel : ViewModelBase
if (obj != null)
{
this.SelectedItem = obj;
if (SelectedItem.GetView != null)
{
this.ContentDisplay = SelectedItem.GetView;
}
if (obj.ViewModel != null)
{
this.ContentDisplay = obj.ViewModel.CreateInstance();
this.ContentDisplay = obj.ViewModel;
}
else
{

View File

@ -2,7 +2,7 @@
namespace PSCHelpdesk.ViewModels;
public partial class TestViewModel: ViewModelBase
public partial class TestViewModel: ViewModelBase, IViewModelBase
{
public TestViewModel()
{

View File

@ -75,7 +75,7 @@ public class ContentDisplay : TemplatedControl
{
if (SelectedItem.ViewModel != null)
{
var vm = SelectedItem.ViewModel.CreateInstance();
var vm = SelectedItem.ViewModel;
return vm;
}
return this.SelectedItem?.CommandParameter ?? this.SelectedOption?.CommandParameter;

View File

@ -13,7 +13,7 @@ public class Item
public object CommandParameter { get; set; }
public Type ViewModel { get; set; }
public object ViewModel { get; set; }
public UserControl GetView { get; set; }
public IList<Item> Items { get; set; }

View File

@ -8,8 +8,9 @@ public interface Contract
{
string GetName();
void addMenu();
Item addMenu();
UserControl load();
UserControl LoadView();
object LoadViewModel();
}

View File

@ -0,0 +1,6 @@
namespace PSCHelpdesk.Shared.ViewModels;
public interface IViewModelBase
{
}

View File

@ -4,7 +4,7 @@ using System.Runtime.CompilerServices;
namespace PSCHelpdesk.Shared.ViewModels;
public abstract class ViewModelBase : INotifyPropertyChanged
public class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;