O CÓDIGO
O sgcUI em uma janela Avalonia 12
Cada trecho é copiado do exemplo AvaloniaProAlternative, uma aplicação Avalonia 12 em net8.0 com bindings compilados e FluentTheme, que compila em Release para as edições Registrada e Community com 0 avisos na demo e passa no seu autoteste. Não há código do Avalonia Pro aqui: esta página mostra apenas código que foi compilado.
Um prefixo XAML para todos os produtos
Cada assembly Avalonia do sgcUI mapeia os seus controles para um único URI de namespace, então um só prefixo sgc cobre todos eles, ao lado do namespace padrão do Avalonia:
MainWindow.axaml<Window xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sgc="https://www.esegece.com/sgcui"
xmlns:vm="using:sgcUIAvaloniaPro"
x:Class="sgcUIAvaloniaPro.MainWindow"
x:DataType="vm:TMainViewModel"
Title="sgcUI next to Avalonia 12: the controls Avalonia Pro does not ship" Width="1240" Height="820">
Não consta no Avalonia Pro: agendador e Kanban sobre uma lista de tarefas
As duas visões se ligam à mesma coleção Tasks do view model. O TsgcAvaloniaPlannerItemFields mapeia os membros da sua própria classe de tarefa, e um arrasto em qualquer das visões grava Begin, End ou Stage de volta na tarefa:
MainWindow.axaml<sgc:TsgcAvaloniaScheduler x:Name="scheduler" ItemsSource="{Binding Tasks}"
ResourcesSource="{Binding People}" SelectedItem="{Binding Selected}">
<sgc:TsgcAvaloniaScheduler.ItemFields>
<sgc:TsgcAvaloniaPlannerItemFields IdField="Key" TitleField="Name" StartField="Begin"
FinishField="End" ResourcesField="Owner" StatusField="Stage"/>
</sgc:TsgcAvaloniaScheduler.ItemFields>
<sgc:TsgcAvaloniaScheduler.ResourceFields>
<sgc:TsgcAvaloniaPlannerResourceFields IdField="Code" NameField="Label"/>
</sgc:TsgcAvaloniaScheduler.ResourceFields>
</sgc:TsgcAvaloniaScheduler>
<sgc:TsgcAvaloniaKanban x:Name="kanban" Grid.Row="1" Margin="0,8,0,0" ColumnSource="pkcList"
ItemsSource="{Binding Tasks}" ResourcesSource="{Binding People}"
SelectedItem="{Binding Selected}">
<sgc:TsgcAvaloniaKanban.ItemFields>
<sgc:TsgcAvaloniaPlannerItemFields IdField="Key" TitleField="Name" StartField="Begin"
FinishField="End" ResourcesField="Owner" StatusField="Stage"/>
</sgc:TsgcAvaloniaKanban.ItemFields>
<sgc:TsgcAvaloniaKanban.ResourceFields>
<sgc:TsgcAvaloniaPlannerResourceFields IdField="Code" NameField="Label"/>
</sgc:TsgcAvaloniaKanban.ResourceFields>
<sgc:TsgcAvaloniaKanban.Columns>
<sgc:TsgcAvaloniaKanbanColumn StatusId="todo" Caption="To do"/>
<sgc:TsgcAvaloniaKanbanColumn StatusId="doing" Caption="In progress"/>
<sgc:TsgcAvaloniaKanbanColumn StatusId="done" Caption="Done"/>
</sgc:TsgcAvaloniaKanban.Columns>
</sgc:TsgcAvaloniaKanban>
Não consta: um dashboard de cartões KPI e um gráfico
Blocos em uma grade de 12 colunas, cada um hospedando um cartão KPI ou qualquer controle, ligados ao view model:
MainWindow.axaml<sgc:TsgcAvaloniaDashboard x:Name="dashboard" Columns="12" RowHeight="110">
<sgc:TsgcAvaloniaDashboardTile Title="Revenue" Col="0" Row="0" ColSpan="4" RowSpan="2">
<sgc:TsgcAvaloniaKPICard x:Name="kpiRevenue" Title="Revenue this month" Value="{Binding Revenue}"
Trend="ktUp" FooterText="all channels"/>
</sgc:TsgcAvaloniaDashboardTile>
<sgc:TsgcAvaloniaDashboardTile Title="Orders" Col="4" Row="0" ColSpan="4" RowSpan="2">
<sgc:TsgcAvaloniaKPICard x:Name="kpiOrders" Title="Orders" Value="{Binding Orders}"
Trend="ktUp" FooterText="this month"/>
</sgc:TsgcAvaloniaDashboardTile>
<sgc:TsgcAvaloniaDashboardTile Title="Support" Col="8" Row="0" ColSpan="4" RowSpan="2">
<sgc:TsgcAvaloniaKPICard x:Name="kpiTickets" Title="Open tickets" Value="{Binding Tickets}"
Trend="ktDown" FooterText="help desk"/>
</sgc:TsgcAvaloniaDashboardTile>
<sgc:TsgcAvaloniaDashboardTile Title="Visits per day" Col="0" Row="2" ColSpan="12" RowSpan="3">
<sgc:TsgcAvaloniaChart x:Name="chartVisits">
<sgc:TsgcAvaloniaChartSeries ItemsSource="{Binding Visits}" XMember="Time" YMember="Value"
Title="Visits" Color="#FF16A34A"/>
<sgc:TsgcAvaloniaChart.Axes>
<sgc:TsgcAvaloniaChartAxis Name="X" AxisType="catDateTime"/>
<sgc:TsgcAvaloniaChartAxis Name="Y" Title="Visits"/>
</sgc:TsgcAvaloniaChart.Axes>
</sgc:TsgcAvaloniaChart>
</sgc:TsgcAvaloniaDashboardTile>
</sgc:TsgcAvaloniaDashboard>
Também no Avalonia Pro: grade, gráfico, visualizador de PDF e texto rico
Quando você troca um controle que se sobrepõe, a visão muda e o view model permanece. A grade com colunas declaradas e um SelectedItem de duas vias:
MainWindow.axaml<sgc:TsgcAvaloniaGrid x:Name="grid" x:DataType="vm:TGridViewModel" Margin="8"
ItemsSource="{Binding Customers}" SelectedItem="{Binding Selected}"
KeyMember="Id" AutoGenerateColumns="False">
<sgc:TsgcAvaloniaGridColumn FieldName="Id" Caption="Id" Width="60" DataType="gdtInteger"/>
<sgc:TsgcAvaloniaGridColumn FieldName="Name" Caption="Customer" Width="220"/>
<sgc:TsgcAvaloniaGridColumn FieldName="City" Caption="City" Width="140"/>
<sgc:TsgcAvaloniaGridColumn FieldName="Balance" Caption="Balance" Width="130" DataType="gdtFloat"
DisplayFormat="#,##0.00" Alignment="gaRight"/>
</sgc:TsgcAvaloniaGrid>
Um gráfico de linhas sobre um eixo de data e hora:
MainWindow.axaml<sgc:TsgcAvaloniaChart x:Name="chartPrice" x:DataType="vm:TChartViewModel" Margin="8">
<sgc:TsgcAvaloniaChartSeries ItemsSource="{Binding Prices}" XMember="Time" YMember="Value"
Title="Price" Color="#FF2563EB"/>
<sgc:TsgcAvaloniaChart.Axes>
<sgc:TsgcAvaloniaChartAxis Name="X" AxisType="catDateTime" Title="Time"/>
<sgc:TsgcAvaloniaChartAxis Name="Y" Title="Price"/>
</sgc:TsgcAvaloniaChart.Axes>
</sgc:TsgcAvaloniaChart>
Um visualizador de PDF com miniaturas, ligado a um TsgcPDFDocument do view model:
MainWindow.axaml<sgc:TsgcAvaloniaPDFThumbnailView x:Name="pdfThumbs" Viewer="{Binding #pdfViewer}"/>
<sgc:TsgcAvaloniaPDFViewer x:Name="pdfViewer" Grid.Column="1" Margin="8,0,0,0"
Document="{Binding Document}" ZoomMode="zmFitWidth"/>
O view model constrói o documento com o sgcPDF, o salva na memória e o lê de volta, da maneira como um documento lido de um arquivo chega ao visualizador:
ViewModels\TOverlapViewModels.cs// a three page A4 report written with sgcPDF, saved to memory and parsed back,
// the way a document read from a file or a stream reaches the viewer
private static TsgcPDFDocument DoBuild()
{
byte[] vBytes;
using (TsgcPDFDocument oWriter = new TsgcPDFDocument())
{
for (int i = 1; i <= CS_PAGES; i++)
{
TsgcPDFPage oPage = oWriter.AddPage(595, 842);
oPage.DrawRectangleFill(0, 772, 595, 70, 0.12, 0.23, 0.54);
oPage.DrawTextColor("Quarterly report, page " + i + " of " + CS_PAGES, 50, 800,
TsgcPDFStandardFont.sfHelveticaBold, 20, 1, 1, 1);
oPage.DrawText("Built in code with sgcPDF (TsgcPDFDocument) and shown by TsgcAvaloniaPDFViewer.", 50,
730, TsgcPDFStandardFont.sfHelvetica, 12);
oPage.DrawText("Search, zoom, thumbnails and text selection work on it like on any PDF file.", 50,
710, TsgcPDFStandardFont.sfHelvetica, 12);
for (int k = 0; k < 6; k++)
oPage.DrawRectangleFill(60 + k * 80, 420, 50, 40 + ((i * 3 + k * 5) % 9) * 25, 0.15, 0.39, 0.92);
oPage.DrawRectangle(40, 40, 515, 712, 1.0);
}
using (MemoryStream oStream = new MemoryStream())
{
oWriter.SaveToStream(oStream);
vBytes = oStream.ToArray();
}
}
TsgcPDFDocument vResult = new TsgcPDFDocument();
vResult.LoadFromBytes(vBytes);
return vResult;
}
O editor de texto rico, ligado como texto Markdown (o sgcRichEdit é exclusivo da edição Registrada):
Views\RichEditTab.axaml<sgc:TsgcAvaloniaRichEdit x:Name="richEdit" Margin="8" DocumentFormat="refMarkdown"
DocumentText="{Binding Text}"/>
ViewModels\TOverlapViewModels.cspublic sealed class TRichTextViewModel : TViewModelBase
{
private string FText =
"# Release notes\n\nThe **sgcRichEdit** control is bound to this view model through " +
"*DocumentText* in Markdown.\n\n- Styles, lists and tables\n- Links such as " +
"[www.esegece.com](https://www.esegece.com)\n- HTML, RTF, Markdown and JSON in and out\n";
/// <summary>The document as Markdown (DocumentFormat="refMarkdown"), written back on focus loss.</summary>
public string Text
{
get { return FText; }
set { DoSet(ref FText, value, "Text"); }
}
}
O tema continua onde está
A aplicação mantém o FluentTheme. Os controles do sgcUI seguem a sua variante de tema, clara, escura ou a configuração do sistema operacional, e mudam ao vivo junto com os controles Fluent:
Program.cspublic override void Initialize()
{
// the existing host theme stays: the sgcUI controls follow its theme variant
Styles.Add(new FluentTheme());
RequestedThemeVariant = ThemeVariant.Default;
}
ViewModels\TOverlapViewModels.cs/// <summary>0 Follow host (RequestedThemeVariant Default), 1 Light, 2 Dark. The sgcUI controls
/// follow the Avalonia theme variant of the FluentTheme host (ThemeFollow utfHost).</summary>
public int ModeIndex
{
get { return FModeIndex; }
set
{
if (value < 0 || value > 2 || !DoSet(ref FModeIndex, value, "ModeIndex"))
return;
sgcUIApplication.ThemeFollow = TsgcUIThemeFollow.utfHost;
sgcUIApplication.SetTheme(TsgcUITheme.utDefault);
if (Application.Current != null)
Application.Current.RequestedThemeVariant = value == 1 ? ThemeVariant.Light :
value == 2 ? ThemeVariant.Dark : ThemeVariant.Default;
}
}