Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add MsExtensionsHostingSample sample project #64

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions README.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,10 @@ Each sample is tagged with it's difficulty. The degree of difficulty describes h
| 🐥 Easy
| MVVM, Data-Validation, Exception, Error, Error-Message, Binding

| link:src/Avalonia.Samples/MVVM/MsExtensionsHostingSample[Avalonia and .NET Generic Host]
| 🐥 Easy
| .NET Generic Host, DI, Configuration, Logging, MVVM

|===

=== ✒️ Drawing-Samples
Expand Down
7 changes: 7 additions & 0 deletions src/Avalonia.Samples/Avalonia.Samples.sln
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestableApp.Headless.XUnit"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestableApp.Appium", "Testing\TestableApp.Appium\TestableApp.Appium.csproj", "{F5CB3DA2-EB59-4792-A1B3-49F600F7C130}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MsExtensionsHostingSample", "MVVM\MsExtensionsHostingSample\MsExtensionsHostingSample.csproj", "{062E5397-CB68-4B3B-9707-4A9B59BDCC1D}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -110,6 +112,10 @@ Global
{F5CB3DA2-EB59-4792-A1B3-49F600F7C130}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F5CB3DA2-EB59-4792-A1B3-49F600F7C130}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F5CB3DA2-EB59-4792-A1B3-49F600F7C130}.Release|Any CPU.Build.0 = Release|Any CPU
{062E5397-CB68-4B3B-9707-4A9B59BDCC1D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{062E5397-CB68-4B3B-9707-4A9B59BDCC1D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{062E5397-CB68-4B3B-9707-4A9B59BDCC1D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{062E5397-CB68-4B3B-9707-4A9B59BDCC1D}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand All @@ -129,6 +135,7 @@ Global
{B8CB5C57-07ED-4BC6-ACE8-F05E428E3EB5} = {85B157B3-F701-4F75-B4F1-EC2287729480}
{BDA7536E-26FD-436F-AAC8-F8A2B500548E} = {85B157B3-F701-4F75-B4F1-EC2287729480}
{F5CB3DA2-EB59-4792-A1B3-49F600F7C130} = {85B157B3-F701-4F75-B4F1-EC2287729480}
{062E5397-CB68-4B3B-9707-4A9B59BDCC1D} = {932FD4A5-FCE7-4428-A0C1-C0392D90A21A}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {C246CAB0-0837-4EE4-A22D-28B3C74930B4}
Expand Down
10 changes: 10 additions & 0 deletions src/Avalonia.Samples/MVVM/MsExtensionsHostingSample/App.axaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<Application xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="MsExtensionsHostingSample.App"
RequestedThemeVariant="Default">
<!-- "Default" ThemeVariant follows system theme variant. "Dark" or "Light" are other available options. -->

<Application.Styles>
<FluentTheme />
</Application.Styles>
</Application>
69 changes: 69 additions & 0 deletions src/Avalonia.Samples/MVVM/MsExtensionsHostingSample/App.axaml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
using System;
using Avalonia;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Markup.Xaml;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using MsExtensionsHostingSample.Models;
using MsExtensionsHostingSample.Services;
using MsExtensionsHostingSample.Services.Interfaces;
using MsExtensionsHostingSample.ViewModels;
using MsExtensionsHostingSample.Views;

namespace MsExtensionsHostingSample;

public partial class App : Application
{
public IHost? GlobalHost { get; private set; }

public override void Initialize()
{
AvaloniaXamlLoader.Load(this);
}

public override async void OnFrameworkInitializationCompleted()
{
var hostBuilder = CreateHostBuilder();
var host = hostBuilder.Build();
GlobalHost = host;

if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
{
desktop.MainWindow = new MainWindow
{
DataContext = GlobalHost.Services.GetRequiredService<MainWindowViewModel>()
};
desktop.Exit += (sender, args) =>
{
GlobalHost.StopAsync(TimeSpan.FromSeconds(5)).GetAwaiter().GetResult();
GlobalHost.Dispose();
GlobalHost = null;
};
}

DataTemplates.Add(GlobalHost.Services.GetRequiredService<ViewLocator>());

base.OnFrameworkInitializationCompleted();

// Usually, we don't want to block main UI thread.
// But if it's required to start async services before we create any window,
// then don't set any MainWindow, and simply call Show() on a new window later after async initialization.
await host.StartAsync();
}

private static HostApplicationBuilder CreateHostBuilder()
{
// Alternatively, we can use Host.CreateDefaultBuilder, but this sample focuses on HostApplicationBuilder.
var builder = Host.CreateApplicationBuilder(Environment.GetCommandLineArgs());

builder.Services.AddOptions<WeatherSettings>().Bind(builder.Configuration.GetSection("Weather"));
builder.Services.AddHostedService<HostedBackgroundService>();

builder.Services.AddTransient<IWeatherService, WeatherService>();
builder.Services.AddTransient<ViewLocator>();
builder.Services.AddTransient<MainWindowViewModel>();

builder.Services.AddView<DayReportViewModel, DayReportView>();
return builder;
}
}
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
using System;

namespace MsExtensionsHostingSample.Models;

public record DayReport(
DateOnly Date,
string WeatherCondition,
double Temperature,
string TemperatureUnit,
double RelativeHumidity,
double WindSpeed);
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace MsExtensionsHostingSample.Models;

public class WeatherSettings
{
public string Unit { get; set; } = "C";
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net7.0</TargetFramework>
<Nullable>enable</Nullable>
<BuiltInComInteropSupport>true</BuiltInComInteropSupport>
<ApplicationManifest>app.manifest</ApplicationManifest>
<AvaloniaUseCompiledBindingsByDefault>true</AvaloniaUseCompiledBindingsByDefault>
</PropertyGroup>

<ItemGroup>
<AvaloniaResource Include="Assets\**"/>
</ItemGroup>

<ItemGroup>
<PackageReference Include="Avalonia" Version="11.0.5"/>
<PackageReference Include="Avalonia.Desktop" Version="11.0.5"/>
<PackageReference Include="Avalonia.Themes.Fluent" Version="11.0.5"/>
<PackageReference Include="Avalonia.Fonts.Inter" Version="11.0.5"/>
<!--Condition below is needed to remove Avalonia.Diagnostics package from build output in Release configuration.-->
<PackageReference Condition="'$(Configuration)' == 'Debug'" Include="Avalonia.Diagnostics" Version="11.0.5"/>
<PackageReference Include="Avalonia.ReactiveUI" Version="11.0.5"/>

<PackageReference Include="Microsoft.Extensions.Hosting" Version="7.0.1" />
</ItemGroup>

<ItemGroup>
<Content Include="appsettings.json" CopyToOutputDirectory="PreserveNewest" />
</ItemGroup>
</Project>
26 changes: 26 additions & 0 deletions src/Avalonia.Samples/MVVM/MsExtensionsHostingSample/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using Avalonia;
using Avalonia.ReactiveUI;
using System;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using MsExtensionsHostingSample.Services;

namespace MsExtensionsHostingSample;

class Program
{
// Initialization code. Don't use any Avalonia, third-party APIs or any
// SynchronizationContext-reliant code before AppMain is called: things aren't initialized
// yet and stuff might break.
[STAThread]
public static void Main(string[] args) => BuildAvaloniaApp()
.StartWithClassicDesktopLifetime(args);

// Avalonia configuration, don't remove; also used by visual designer.
public static AppBuilder BuildAvaloniaApp()
=> AppBuilder.Configure<App>()
.UsePlatformDetect()
.WithInterFont()
.LogToTrace()
.UseReactiveUI();
}
Loading