This commit is contained in:
lincube
2026-02-27 13:43:27 +08:00
parent 9c42ada69a
commit e8f942b0f6
7 changed files with 266 additions and 9 deletions

View File

@@ -0,0 +1,23 @@
<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="220"
d:DesignHeight="70"
x:Class="LanMontainDesktop.Views.Components.ClockWidget">
<Border Padding="8"
CornerRadius="8"
BorderBrush="#80A5B4FC"
BorderThickness="1"
Background="#CC0F172A">
<TextBlock x:Name="TimeTextBlock"
HorizontalAlignment="Center"
VerticalAlignment="Center"
FontSize="26"
FontWeight="SemiBold"
Foreground="White" />
</Border>
</UserControl>

View File

@@ -0,0 +1,47 @@
using System;
using System.Globalization;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Threading;
namespace LanMontainDesktop.Views.Components;
public partial class ClockWidget : UserControl
{
private readonly DispatcherTimer _timer = new()
{
Interval = TimeSpan.FromSeconds(1)
};
public ClockWidget()
{
InitializeComponent();
_timer.Tick += OnTimerTick;
AttachedToVisualTree += OnAttachedToVisualTree;
DetachedFromVisualTree += OnDetachedFromVisualTree;
UpdateClock();
}
private void OnAttachedToVisualTree(object? sender, VisualTreeAttachmentEventArgs e)
{
UpdateClock();
_timer.Start();
}
private void OnDetachedFromVisualTree(object? sender, VisualTreeAttachmentEventArgs e)
{
_timer.Stop();
}
private void OnTimerTick(object? sender, EventArgs e)
{
UpdateClock();
}
private void UpdateClock()
{
var now = DateTime.Now;
TimeTextBlock.Text = now.ToString("HH:mm:ss", CultureInfo.CurrentCulture);
}
}

View File

@@ -1,20 +1,91 @@
<Window xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="using:LanMontainDesktop.ViewModels"
xmlns:ui="using:FluentAvalonia.UI.Controls"
xmlns:comp="using:LanMontainDesktop.Views.Components"
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"
mc:Ignorable="d"
d:DesignWidth="1280"
d:DesignHeight="720"
x:Class="LanMontainDesktop.Views.MainWindow"
x:DataType="vm:MainWindowViewModel"
Icon="/Assets/avalonia-logo.ico"
WindowState="FullScreen"
SystemDecorations="None"
CanResize="False"
Background="#FF020617"
Title="LanMontainDesktop">
<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:MainWindowViewModel/>
<vm:MainWindowViewModel />
</Design.DataContext>
<TextBlock Text="{Binding Greeting}" HorizontalAlignment="Center" VerticalAlignment="Center"/>
<Grid>
<Border x:Name="DesktopHost"
ClipToBounds="True"
Background="#FF020617">
<Grid x:Name="DesktopGrid"
HorizontalAlignment="Left"
VerticalAlignment="Top"
ShowGridLines="False">
<comp:ClockWidget x:Name="ClockWidget"
Grid.Row="0"
Grid.Column="0"
Grid.ColumnSpan="3"
Margin="4" />
<Button x:Name="BackToWindowsButton"
Grid.Row="0"
Grid.Column="0"
Grid.ColumnSpan="4"
Margin="4"
Padding="8"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Click="OnMinimizeClick"
Content="回到Windows" />
</Grid>
</Border>
<Border HorizontalAlignment="Right"
VerticalAlignment="Top"
Margin="10"
Padding="10"
CornerRadius="10"
Background="#BF111827"
BorderBrush="#80334155"
BorderThickness="1">
<Grid ColumnDefinitions="Auto,Auto,Auto"
RowDefinitions="Auto,Auto"
ColumnSpacing="8"
RowSpacing="6">
<TextBlock Grid.Row="0"
Grid.Column="0"
VerticalAlignment="Center"
Foreground="#FFE5E7EB"
Text="短边格数" />
<ui:NumberBox x:Name="GridSizeNumberBox"
Grid.Row="0"
Grid.Column="1"
Width="100"
Minimum="6"
Maximum="96"
Value="12" />
<Button Grid.Row="0"
Grid.Column="2"
Padding="12,6"
Click="OnApplyGridSizeClick"
Content="应用" />
<TextBlock x:Name="GridInfoTextBlock"
Grid.Row="1"
Grid.Column="0"
Grid.ColumnSpan="3"
Foreground="#FF93C5FD"
Text="Grid: - cols x - rows (1:1)" />
</Grid>
</Border>
</Grid>
</Window>

View File

@@ -1,11 +1,125 @@
using System;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Interactivity;
namespace LanMontainDesktop.Views;
public partial class MainWindow : Window
{
private const int MinShortSideCells = 6;
private const int MaxShortSideCells = 96;
private int _targetShortSideCells;
public MainWindow()
{
InitializeComponent();
}
}
protected override void OnOpened(EventArgs e)
{
base.OnOpened(e);
_targetShortSideCells = CalculateDefaultShortSideCellCountFromDpi();
GridSizeNumberBox.Value = _targetShortSideCells;
DesktopHost.SizeChanged += OnDesktopHostSizeChanged;
RebuildDesktopGrid();
}
protected override void OnClosed(EventArgs e)
{
DesktopHost.SizeChanged -= OnDesktopHostSizeChanged;
base.OnClosed(e);
}
private int CalculateDefaultShortSideCellCountFromDpi()
{
var dpi = 96d * RenderScaling;
var count = (int)Math.Round(dpi / 8d);
return Math.Clamp(count, MinShortSideCells, MaxShortSideCells);
}
private void OnDesktopHostSizeChanged(object? sender, SizeChangedEventArgs e)
{
RebuildDesktopGrid();
}
private void OnApplyGridSizeClick(object? sender, RoutedEventArgs e)
{
var requested = (int)Math.Round(GridSizeNumberBox.Value);
if (requested <= 0)
{
requested = _targetShortSideCells;
}
_targetShortSideCells = Math.Clamp(requested, MinShortSideCells, MaxShortSideCells);
if (Math.Abs(GridSizeNumberBox.Value - _targetShortSideCells) > double.Epsilon)
{
GridSizeNumberBox.Value = _targetShortSideCells;
}
RebuildDesktopGrid();
}
private void RebuildDesktopGrid()
{
var hostWidth = DesktopHost.Bounds.Width;
var hostHeight = DesktopHost.Bounds.Height;
if (hostWidth <= 1 || hostHeight <= 1)
{
return;
}
var shortSideCells = Math.Max(1, _targetShortSideCells);
double cellSize;
int columnCount;
int rowCount;
if (hostWidth >= hostHeight)
{
rowCount = shortSideCells;
cellSize = hostHeight / rowCount;
columnCount = Math.Max(1, (int)Math.Ceiling(hostWidth / cellSize));
}
else
{
columnCount = shortSideCells;
cellSize = hostWidth / columnCount;
rowCount = Math.Max(1, (int)Math.Ceiling(hostHeight / cellSize));
}
DesktopGrid.RowDefinitions.Clear();
DesktopGrid.ColumnDefinitions.Clear();
DesktopGrid.Width = columnCount * cellSize;
DesktopGrid.Height = rowCount * cellSize;
for (var row = 0; row < rowCount; row++)
{
DesktopGrid.RowDefinitions.Add(new RowDefinition(new GridLength(cellSize, GridUnitType.Pixel)));
}
for (var col = 0; col < columnCount; col++)
{
DesktopGrid.ColumnDefinitions.Add(new ColumnDefinition(new GridLength(cellSize, GridUnitType.Pixel)));
}
Grid.SetRow(ClockWidget, 0);
Grid.SetColumn(ClockWidget, 0);
Grid.SetRowSpan(ClockWidget, 1);
Grid.SetColumnSpan(ClockWidget, Math.Min(3, columnCount));
Grid.SetRow(BackToWindowsButton, rowCount - 1);
Grid.SetColumn(BackToWindowsButton, 0);
Grid.SetRowSpan(BackToWindowsButton, 1);
Grid.SetColumnSpan(BackToWindowsButton, Math.Min(4, columnCount));
GridInfoTextBlock.Text =
$"Grid: {columnCount} cols x {rowCount} rows | cell {cellSize:F1}px (1:1)";
}
private void OnMinimizeClick(object? sender, RoutedEventArgs e)
{
WindowState = WindowState.Minimized;
}
}