您现在的位置是:网站首页> .NET Core
Avalonia .NET 的跨平台 UI 框架及其他GTK学习资料收集
- .NET Core
- 2025-10-06
- 1247人已阅读
Avalonia .NET 的跨平台 UI 框架及其他GTK学习资料收集
***Avalonia.NET编译Android配置签名***
MAUI配置发布Android IOS等个平台独特的文件配置
dotnet publish 发布win-x64程序,用这个命令行设置图标,给个例子
****************************************************************************************************
Avalonia如何不采用数据绑定方式,手动更新界面,手动对组件赋值和获得值,给几个典型组件的代码例子
Avalonia常用的界面组件介绍和例子代码数据采用非绑定方式的
****************************************************************************************************
Avalonia 中,你可以通过几种方式向新窗口传递参数并获取返回值
基于Material Design风格开源的Avalonia UI控件库
Avalonia如何不采用数据绑定方式,手动更新界面,手动对组件赋值和获得值,给几个典型组件的代码例子
Avalonia常用的界面组件介绍和例子代码数据采用非绑定方式的
Avalonia .NET编译Android配置签名
对Android项目右键配置项目属性点Android项,划到包签名
Avalonia生成的程序位置
Avalonia 中,你可以通过几种方式向新窗口传递参数并获取返回值
1.首先,创建一个新的窗口类,比如 SecondWindow.axaml 和 SecondWindow.axaml.cs。
2.在 SecondWindow.axaml.cs 中,添加构造函数和属性来接收参数,并添加一个方法来返回结果:
public partial class SecondWindow : Window
{
public string InputParameter { get; set; }
public string Result { get; private set; }
public SecondWindow()
{
InitializeComponent();
}
public SecondWindow(string inputParameter) : this()
{
InputParameter = inputParameter;
}
private void OnOKButtonClick(object sender, RoutedEventArgs e)
{
Result = "处理完成";
Close();
}
}
3.在主窗口 MainWindow.axaml.cs 中,添加一个方法来打开新窗口并等待结果:
private async void OpenSecondWindowButton_Click(object sender, RoutedEventArgs e)
{
var secondWindow = new SecondWindow("这是传入的参数");
var result = await ShowDialogAsync(secondWindow);
if (result == true)
{
// 获取返回值
string returnValue = secondWindow.Result;
// 处理返回值
await MessageBoxManager.GetMessageBoxStandardWindow("结果", $"返回值: {returnValue}").ShowAsync();
}
}
private async Task<bool?> ShowDialogAsync(Window window)
{
var tcs = new TaskCompletionSource<bool?>();
window.Closed += (s, e) => tcs.TrySetResult(window.DialogResult);
await window.ShowDialog(this);
return await tcs.Task;
}
4.在 SecondWindow.axaml 中,添加一个按钮来关闭窗口并设置结果:
<Window xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="YourNamespace.SecondWindow"
Title="Second Window">
<StackPanel>
<TextBlock Text="{Binding InputParameter}" />
<Button Content="确定" Click="OnOKButtonClick" />
</StackPanel>
</Window>
5.在主窗口 MainWindow.axaml 中,添加一个按钮来打开新窗口:
<Window xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="YourNamespace.MainWindow"
Title="Main Window">
<Button Content="打开新窗口" Click="OpenSecondWindowButton_Click" />
</Window>
这个例子展示了如何:
1.创建一个新窗口并传递参数(通过构造函数)。
2.在新窗口中处理参数并设置返回值。
3.在主窗口中等待新窗口关闭并获取返回值。
4.使用 TaskCompletionSource 来异步等待窗口关闭。
通过这种方式,你可以方便地在 Avalonia 应用程序中实现窗口间的参数传递和返回值获取。
基于Material Design风格开源的Avalonia UI控件库
Avalonia .NET实现NFC的读写的详细例子
你可以在Avalonia应用中集成NFC功能,通过使用其他.NET库或原生API来实现。以下是一个概念性的例子,说明如何在Avalonia应用中集成NFC功能:
首先,你需要一个NFC库。在.NET生态系统中,没有一个广泛使用的跨平台NFC库。你可能需要根据目标平台选择不同的实现方式。
对于Windows,你可以使用Windows.Devices.Nfc命名空间。
对于Android,你可以使用Xamarin.Android的NFC API。
对于iOS,你可以使用CoreNFC框架。
下面是一个概念性的例子,展示了如何在Avalonia应用中集成NFC读取功能(以Windows平台为例):
using Avalonia;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
using Windows.Devices.Nfc;
using Windows.Devices.Enumeration;
public class MainWindow : Window
{
private NfcReader _nfcReader;
public MainWindow()
{
InitializeComponent();
InitializeNfcReader();
}
private async void InitializeNfcReader()
{
var selector = NfcReader.GetDeviceSelector();
var devices = await DeviceInformation.FindAllAsync(selector);
if (devices.Count > 0)
{
_nfcReader = await NfcReader.FromIdAsync(devices[0].Id);
_nfcReader.TagRead += OnTagRead;
}
}
private void OnTagRead(NfcReader sender, NfcTagEventArgs args)
{
var tag = args.Tag;
// 处理NFC标签数据
Dispatcher.UIThread.InvokeAsync(() =>
{
// 更新UI
});
}
// XAML初始化代码
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
}
}
这个例子展示了如何初始化NFC读取器并处理标签读取事件。你需要根据实际需求修改UI更新逻辑。
对于写入NFC标签,过程类似,但你需要使用NfcWriter类。例如:
private async Task WriteToTag(NdefMessage message)
{
var writer = new NfcWriter();
await writer.WriteNdefMessageAsync(message);
}
请注意,这只是一个概念性的例子。实际实现可能会更复杂,需要考虑错误处理、不同平台的兼容性等因素。此外,由于NFC操作涉及硬件访问,你可能需要请求适当的权限。
在跨平台场景中,你可能需要为每个平台创建单独的NFC实现,然后通过依赖注入或其他方式在Avalonia应用中使用
Avalonia UI 报错
报错:System.InvalidOperationException:“Unable to configure HTTPS endpoint. No server certificate was specified, and the default developer certificate could not be found or is out of date.
解决办法:
原因
未生成开发证书:
.NET 开发环境下默认需要 HTTPS 证书,若未生成或证书缺失,启动时会报此错误。
证书过期:
.NET 开发证书有效期为 1 年,过期后需重新生成。
项目未正确配置 HTTPS:
若项目中启用了 HTTPS 但未指定证书路径,可能导致此问题。
解决方案
1. 生成并信任开发证书
Windows/macOS/Linux
在终端执行以下命令:
# 检查证书状态
dotnet dev-certs https --check
# 清理旧证书(如有必要)
dotnet dev-certs https --clean
# 生成新证书
dotnet dev-certs https --trust
dotnet publish 发布win-x64程序,用这个命令行设置图标,给个例子
使用 dotnet publish 命令发布 Win-x64 程序时,希望通过命令行设置可执行文件的图标。虽然 dotnet publish 本身不直接支持通过命令行参数来设置图标,但您可以结合修改项目文件(.csproj)的方式来实现这一点。
下面是详细的步骤和示例:
步骤
准备图标文件: 确保你有一个 ICO 格式的图标文件(例如 appicon.ico),并将它放在你的项目目录中或其他合适的位置。
修改项目文件 (.csproj): 编辑你的 .csproj 文件,添加必要的元素来指定图标。
使用 dotnet publish 命令发布应用程序: 运行 dotnet publish 命令来发布你的应用程序。
示例
假设你有一个名为 MyApp.csproj 的控制台应用程序,并且你想将 appicon.ico 设置为其可执行文件的图标。
修改 .csproj 文件
首先,打开你的 .csproj 文件并在适当位置添加以下内容:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net7.0-windows</TargetFramework>
<!-- 添加这些行来指定图标 -->
<ApplicationIcon>path/to/appicon.ico</ApplicationIcon>
<WinExeIconFromBuildAsResource>false</WinExeIconFromBuildAsResource>
</PropertyGroup>
<!-- ...其他配置... -->
</Project>
在这个示例中:
<ApplicationIcon> 指定了图标的相对路径。
<WinExeIconFromBuildAsResource> 设置为 false 表明不要将图标作为资源嵌入到可执行文件中。
如果 appicon.ico 放在项目的根目录下,可以直接写成:
<ApplicationIcon>appicon.ico</ApplicationIcon>
如果图标不在项目根目录下,请提供完整路径或相对于 .csproj 文件的路径。
使用 dotnet publish 命令发布应用程序
接下来,使用 dotnet publish 命令来发布你的应用程序:
# 使用 release 构建模式并且针对 windows x64 平台发布
dotnet publish -c Release -r win-x64 --self-contained false /p:PublishSingleFile=true /p:PublishTrimmed=true
这条命令做了以下几件事:
-c Release: 使用 Release 构建模式。
-r win-x64: 针对 Windows 64-bit 平台发布。
--self-contained false: 不包含 .NET Runtime,减少最终生成文件大小。
/p:PublishSingleFile=true: 将所有依赖项合并到一个单一的可执行文件中。
/p:PublishTrimmed=true: 启用 IL Trimming,去除不需要的部分以减小文件大小。
完整示例
假设你的项目结构如下:
MyApp/
├── MyApp.csproj
└── appicon.ico
MyApp.csproj 内容
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net7.0-windows</TargetFramework>
<ApplicationIcon>appicon.ico</ApplicationIcon>
<WinExeIconFromBuildAsResource>false</WinExeIconFromBuildAsResource>
</PropertyGroup>
</Project>
发布命令
dotnet publish -c Release -r win-x64 --self-contained false /p:PublishSingleFile=true /p:PublishTrimmed=true
vs2022的Avalonia扩展安装
// 安装模板
dotnet new install Avalonia.Templates
// 验证
dotnet new list
Avalonia for Visual Studio 2022.rar
Avalonia入门及学习
开源GTKSystem.Windows.Forms框架
开发项目时,Visual Studio可以使用C#的原生WinForms表单窗体设计器,保持与原生WinForms相同的属性、方法和事件,无需额外学习。通过一次编译,可以实现跨平台运行,便于开发跨平台WinForms软件,以及将现有的C# WinForms软件升级为跨平台软件。
使用GTK3.24.24.95作为表单UI重写C#的System.Windows.Forms组件,在应用时,兼容原生C#程序组件。
Visual Studio插件安装
从NuGet上安装GTKSystem.Windows.FormsDesigner类库,此类库可以在编译工程时修正窗体设计器。
下载本插件工具,关闭Visual Studio 2022,直接双击GTKWinformVSIXProject.vsix文件安装(本框架下的工程,Studio没有添加Form模板项,需要安装此插件)。
插件会安装两个功能:
1、新建项的Form窗体模板、用户控件模板。
2、工程右键菜单。
Avalonia如何不采用数据绑定方式,手动更新界面,手动对组件赋值和获得值,给几个典型组件的代码例子
几种典型控件的手动操作方式:
获取控件引用:使用FindControl<T>()方法通过 Name 属性获取控件实例
1.TextBox 文本框:
设置值:_inputTextBox.Text = "初始文本";
获取值:string value = _inputTextBox.Text;
2.Button 按钮:
设置文本:通过 XAML 的 Content 属性
注册点击事件:_submitButton.Click += (sender, e) => { ... };
3.TextBlock 文本块:
设置显示文本:_displayTextBlock.Text = "等待输入...";
4.CheckBox 复选框:
检查状态:_agreeCheckBox.IsChecked
注册状态改变事件:Checked和Unchecked
5.ComboBox 下拉列表:
添加项:_optionsComboBox.Items.Add("选项1");
设置选中项:_optionsComboBox.SelectedIndex = 0;
获取选中项:_optionsComboBox.SelectedItem
注册选择改变事件:SelectionChanged
6.Slider 滑块:
设置值:_volumeSlider.Value = 50;
获取值:_volumeSlider.Value
注册值改变事件:ValueChanged
这种方式完全不依赖数据绑定,所有 UI 更新和值获取都是通过直接操作控件实例完成的,适合一些简单场景或需要更直接控制 UI 的情况。
MainWindow.xaml
<Window xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="ManualUIUpdateExample.MainWindow"
Title="手动更新界面示例">
<StackPanel Margin="20" Spacing="10">
<!-- 文本框 -->
<TextBox Name="InputTextBox" Width="200" />
<!-- 按钮 -->
<Button Name="SubmitButton" Content="点击我" Width="100" />
<!-- 文本块 -->
<TextBlock Name="DisplayTextBlock" />
<!-- 复选框 -->
<CheckBox Name="AgreeCheckBox" Content="同意条款" />
<!-- 下拉列表 -->
<ComboBox Name="OptionsComboBox" Width="200" />
<!-- 滑块 -->
<Slider Name="VolumeSlider" Width="200" Minimum="0" Maximum="100" />
<!-- 滑块值显示 -->
<TextBlock Name="SliderValueTextBlock" />
</StackPanel>
</Window>
MainWindow.xaml.cs
using Avalonia;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
namespace ManualUIUpdateExample
{
public partial class MainWindow : Window
{
// 声明控件变量
private TextBox _inputTextBox;
private Button _submitButton;
private TextBlock _displayTextBlock;
private CheckBox _agreeCheckBox;
private ComboBox _optionsComboBox;
private Slider _volumeSlider;
private TextBlock _sliderValueTextBlock;
public MainWindow()
{
InitializeComponent();
#if DEBUG
this.AttachDevTools();
#endif
// 初始化控件引用
InitializeControls();
// 设置初始值
SetInitialValues();
// 注册事件
RegisterEvents();
}
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
}
private void InitializeControls()
{
// 获取控件引用
_inputTextBox = this.FindControl<TextBox>("InputTextBox");
_submitButton = this.FindControl<Button>("SubmitButton");
_displayTextBlock = this.FindControl<TextBlock>("DisplayTextBlock");
_agreeCheckBox = this.FindControl<CheckBox>("AgreeCheckBox");
_optionsComboBox = this.FindControl<ComboBox>("OptionsComboBox");
_volumeSlider = this.FindControl<Slider>("VolumeSlider");
_sliderValueTextBlock = this.FindControl<TextBlock>("SliderValueTextBlock");
}
private void SetInitialValues()
{
// 手动设置控件初始值
_inputTextBox.Text = "初始文本";
_displayTextBlock.Text = "等待输入...";
// 向下拉列表添加项
_optionsComboBox.Items.Add("选项1");
_optionsComboBox.Items.Add("选项2");
_optionsComboBox.Items.Add("选项3");
// 设置默认选中项
_optionsComboBox.SelectedIndex = 0;
// 设置滑块初始值
_volumeSlider.Value = 50;
_sliderValueTextBlock.Text = $"滑块值: {_volumeSlider.Value}";
}
private void RegisterEvents()
{
// 按钮点击事件
_submitButton.Click += (sender, e) =>
{
// 获取文本框的值并设置到文本块
_displayTextBlock.Text = $"你输入了: {_inputTextBox.Text}";
};
// 复选框状态改变事件
_agreeCheckBox.Checked += (sender, e) =>
{
_displayTextBlock.Text = "已同意条款";
};
_agreeCheckBox.Unchecked += (sender, e) =>
{
_displayTextBlock.Text = "未同意条款";
};
// 下拉列表选择改变事件
_optionsComboBox.SelectionChanged += (sender, e) =>
{
if (_optionsComboBox.SelectedItem != null)
{
_displayTextBlock.Text = $"选中了: {_optionsComboBox.SelectedItem}";
}
};
// 滑块值改变事件
_volumeSlider.ValueChanged += (sender, e) =>
{
// 实时更新滑块值显示
_sliderValueTextBlock.Text = $"滑块值: {e.NewValue}";
};
}
}
}
Avalonia数据列表组件不采用数据绑定方式
MainWindow.xaml
<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="600"
x:Class="ListBoxWithXamlTemplate.MainWindow"
Title="带XAML模板的列表示例">
<StackPanel Margin="20" Spacing="15">
<TextBlock FontSize="20" FontWeight="Bold">带图片和文本的列表</TextBlock>
<!-- 输入区域 -->
<StackPanel Spacing="8">
<TextBox x:Name="ImagePathInput" PlaceholderText="图片路径 (URL或本地路径)"/>
<TextBox x:Name="TitleInput" PlaceholderText="标题"/>
<TextBox x:Name="DescriptionInput" PlaceholderText="描述" AcceptsReturn="True" Height="80"/>
<StackPanel Orientation="Horizontal" Spacing="10">
<Button x:Name="AddButton" Content="添加" Width="80" Classes="btn-primary"/>
<Button x:Name="EditButton" Content="编辑" Width="80" Classes="btn-secondary"/>
<Button x:Name="DeleteButton" Content="删除" Width="80" Classes="btn-danger"/>
</StackPanel>
</StackPanel>
<!-- 列表区域 -->
<ListBox x:Name="DataListBox" Height="300" Margin="0 10">
<!-- 列表项模板定义在XAML中 -->
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" Spacing="12" Margin="5" Padding="5"
Background="{Binding IsSelected, RelativeSource={RelativeSource AncestorType=ListBoxItem},
Converter={x:Static BoolToBrushConverter.Instance}}">
<!-- 图片控件 -->
<Image x:Name="ItemImage" Width="100" Height="100" Stretch="UniformToFill"
Margin="0 5"/>
<!-- 文本内容容器 -->
<StackPanel VerticalAlignment="Center" Spacing="5" Margin="5 0">
<TextBlock x:Name="ItemTitle" FontSize="16" FontWeight="Bold"/>
<TextBlock x:Name="ItemDescription" FontSize="12" Foreground="Gray"
MaxWidth="500" TextWrapping="Wrap"/>
</StackPanel>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<!-- 状态信息 -->
<TextBlock x:Name="StatusText" FontSize="12" Foreground="DarkSlateBlue"/>
</StackPanel>
</Window>
MainWindow.xaml.cs
using Avalonia;
using Avalonia.Controls;
using Avalonia.Data.Converters;
using Avalonia.Media;
using Avalonia.Media.Imaging;
using Avalonia.Platform;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
namespace ListBoxWithXamlTemplate
{
// 辅助转换器:根据选中状态改变背景色
public class BoolToBrushConverter : IValueConverter
{
public static readonly BoolToBrushConverter Instance = new BoolToBrushConverter();
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value is bool isSelected && isSelected)
return new SolidColorBrush(Color.FromArgb(20, 0, 120, 215));
return Brushes.Transparent;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
// 数据项模型类
public class ListItem
{
public string Id { get; }
public string ImagePath { get; set; }
public string Title { get; set; }
public string Description { get; set; }
public Bitmap Image { get; set; }
public ListItem(string imagePath, string title, string description)
{
Id = Guid.NewGuid().ToString();
ImagePath = imagePath;
Title = title;
Description = description;
LoadImage();
}
// 加载图片
public void LoadImage()
{
try
{
if (!string.IsNullOrEmpty(ImagePath))
{
if (ImagePath.StartsWith("http"))
{
Image = new Bitmap(new Uri(ImagePath));
}
else if (File.Exists(ImagePath))
{
Image = new Bitmap(ImagePath);
}
else
{
Image = GetDefaultImage();
}
}
else
{
Image = GetDefaultImage();
}
}
catch
{
Image = GetDefaultImage();
}
}
// 获取默认图片
private Bitmap GetDefaultImage()
{
return new Bitmap(AssetLoader.Open(new Uri("resm:Avalonia.Controls.Resources.DefaultIcon.png")));
}
}
public partial class MainWindow : Window
{
// 控件引用
private TextBox _imagePathInput;
private TextBox _titleInput;
private TextBox _descriptionInput;
private Button _addButton;
private Button _editButton;
private Button _deleteButton;
private ListBox _dataListBox;
private TextBlock _statusText;
// 数据集合
private List<ListItem> _dataItems = new List<ListItem>();
public MainWindow()
{
InitializeComponent();
#if DEBUG
this.AttachDevTools();
#endif
// 初始化控件引用
InitializeControls();
// 注册事件处理
RegisterEvents();
// 设置初始数据
SetInitialData();
}
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
}
private void InitializeControls()
{
// 获取所有控件的引用
_imagePathInput = this.FindControl<TextBox>("ImagePathInput");
_titleInput = this.FindControl<TextBox>("TitleInput");
_descriptionInput = this.FindControl<TextBox>("DescriptionInput");
_addButton = this.FindControl<Button>("AddButton");
_editButton = this.FindControl<Button>("EditButton");
_deleteButton = this.FindControl<Button>("DeleteButton");
_dataListBox = this.FindControl<ListBox>("DataListBox");
_statusText = this.FindControl<TextBlock>("StatusText");
}
private void RegisterEvents()
{
_addButton.Click += AddButton_Click;
_editButton.Click += EditButton_Click;
_deleteButton.Click += DeleteButton_Click;
_dataListBox.SelectionChanged += DataListBox_SelectionChanged;
_dataListBox.ItemPrepared += DataListBox_ItemPrepared;
}
private void SetInitialData()
{
// 添加初始数据
_dataItems.Add(new ListItem(
"https://picsum.photos/id/237/100/100",
"小狗",
"一只可爱的小狗,正在草地上玩耍"));
_dataItems.Add(new ListItem(
"https://picsum.photos/id/10/100/100",
"山脉风景",
"壮丽的山脉景观,蓝天白云相映成趣"));
_dataItems.Add(new ListItem(
"https://picsum.photos/id/96/100/100",
"花朵",
"鲜艳的花朵,展现了大自然的美丽"));
UpdateListDisplay();
UpdateStatusText($"初始数据加载完成,共 {_dataItems.Count} 项");
}
/// <summary>
/// 当列表项准备好时手动设置UI元素的值
/// </summary>
private void DataListBox_ItemPrepared(object sender, ItemPreparedEventArgs e)
{
// 获取数据项
var listItem = e.Item as ListItem;
if (listItem == null) return;
// 获取模板中的UI元素
var image = e.Container.FindControl<Image>("ItemImage");
var title = e.Container.FindControl<TextBlock>("ItemTitle");
var description = e.Container.FindControl<TextBlock>("ItemDescription");
// 手动设置UI元素的值
if (image != null) image.Source = listItem.Image;
if (title != null) title.Text = listItem.Title;
if (description != null) description.Text = listItem.Description;
}
/// <summary>
/// 手动更新列表显示
/// </summary>
private void UpdateListDisplay()
{
// 保存当前选中项ID
var selectedItem = _dataListBox.SelectedItem as ListItem;
string selectedId = selectedItem?.Id;
// 清空并重新填充列表
_dataListBox.Items.Clear();
foreach (var item in _dataItems)
{
_dataListBox.Items.Add(item);
}
// 恢复选中状态
if (!string.IsNullOrEmpty(selectedId))
{
var itemToSelect = _dataItems.Find(i => i.Id == selectedId);
if (itemToSelect != null)
{
_dataListBox.SelectedItem = itemToSelect;
}
}
}
private void AddButton_Click(object sender, EventArgs e)
{
if (string.IsNullOrWhiteSpace(_titleInput.Text))
{
UpdateStatusText("请输入标题");
return;
}
var newItem = new ListItem(
_imagePathInput.Text,
_titleInput.Text.Trim(),
_descriptionInput.Text?.Trim() ?? ""
);
_dataItems.Add(newItem);
UpdateListDisplay();
ClearInputFields();
UpdateStatusText($"已添加: {newItem.Title}");
// 选中新添加的项
if (_dataListBox.Items.Count > 0)
{
_dataListBox.SelectedIndex = _dataListBox.Items.Count - 1;
}
}
private void EditButton_Click(object sender, EventArgs e)
{
var selectedItem = _dataListBox.SelectedItem as ListItem;
if (selectedItem == null)
{
UpdateStatusText("请先选择要编辑的项");
return;
}
if (string.IsNullOrWhiteSpace(_titleInput.Text))
{
UpdateStatusText("请输入标题");
return;
}
string oldTitle = selectedItem.Title;
// 更新数据
selectedItem.ImagePath = _imagePathInput.Text;
selectedItem.Title = _titleInput.Text.Trim();
selectedItem.Description = _descriptionInput.Text?.Trim() ?? "";
selectedItem.LoadImage(); // 重新加载图片
UpdateListDisplay();
UpdateStatusText($"已更新: {oldTitle} -> {selectedItem.Title}");
}
private void DeleteButton_Click(object sender, EventArgs e)
{
var selectedItem = _dataListBox.SelectedItem as ListItem;
if (selectedItem == null)
{
UpdateStatusText("请先选择要删除的项");
return;
}
string deletedTitle = selectedItem.Title;
_dataItems.Remove(selectedItem);
UpdateListDisplay();
ClearInputFields();
UpdateStatusText($"已删除: {deletedTitle}");
}
private void DataListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
var selectedItem = _dataListBox.SelectedItem as ListItem;
if (selectedItem != null)
{
_imagePathInput.Text = selectedItem.ImagePath;
_titleInput.Text = selectedItem.Title;
_descriptionInput.Text = selectedItem.Description;
UpdateStatusText($"已选择: {selectedItem.Title}");
}
}
private void ClearInputFields()
{
_imagePathInput.Text = string.Empty;
_titleInput.Text = string.Empty;
_descriptionInput.Text = string.Empty;
}
private void UpdateStatusText(string message)
{
_statusText.Text = $"状态: {message}";
}
}
}
1.XAML 模板定义:
在 XAML 中通过ListBox.ItemTemplate定义了列表项的 UI 结构
模板包含 Image 和两个 TextBlock,分别显示图片、标题和描述
使用转换器实现了选中项的背景色变化效果
2.手动数据绑定:
通过ItemPrepared事件手动将数据项的值设置到 UI 元素上
不使用 Avalonia 的数据绑定表达式,完全手动控制值的传递
3.核心实现逻辑:
当列表项准备好显示时,DataListBox_ItemPrepared事件被触发
在事件处理中,找到模板中的 UI 元素并手动设置其属性
数据更新后通过UpdateListDisplay方法刷新整个列表
4.保持原有功能:
保留了完整的添加、编辑、删除功能
维持了选中状态记忆和输入框自动填充功能
这种方式结合了 XAML 的 UI 定义优势和手动控制数据的灵活性,既便于设计复杂的 UI 结构,又能精确控制数据流向和 UI 更新时机。对于需要精细控制 UI 渲染过程的场景非常适用。
Avalonia常用的界面组件介绍和例子代码数据采用非绑定方式的
Avalonia 是一个跨平台的.NET UI 框架,提供了丰富的界面组件。以下是一些常用组件的介绍和非绑定方式的示例代码:
1. Button(按钮)
按钮是最常用的交互组件,用于触发操作。
XAML 示例:
xml
<Button Name="MyButton" Content="点击我" Width="100" Height="30" />
C# 代码(事件处理):
csharp
public MainWindow()
{
InitializeComponent();
var button = this.FindControl<Button>("MyButton");
button.Click += (sender, e) =>
{
button.Content = "已点击";
};
}
2. TextBlock(文本块)
用于显示文本内容,不可编辑。
XAML 示例:
xml
<TextBlock Name="MyTextBlock" Text="初始文本" FontSize="16" Foreground="Blue" />
C# 代码:
csharp
var textBlock = this.FindControl<TextBlock>("MyTextBlock");
textBlock.Text = "更新后的文本";
textBlock.Foreground = Brushes.Red;
3. TextBox(文本框)
用于输入和编辑文本。
XAML 示例:
xml
<TextBox Name="MyTextBox" Width="200" Height="30" Text="默认文本" />
C# 代码:
csharp
var textBox = this.FindControl<TextBox>("MyTextBox");
// 设置文本
textBox.Text = "通过代码设置的文本";
// 获取文本
string inputText = textBox.Text;
4. CheckBox(复选框)
用于表示布尔值选项,可选中或取消选中。
XAML 示例:
xml
<CheckBox Name="MyCheckBox" Content="同意条款" />
C# 代码:
csharp
var checkBox = this.FindControl<CheckBox>("MyCheckBox");
// 设置选中状态
checkBox.IsChecked = true;
// 获取选中状态
bool? isChecked = checkBox.IsChecked;
checkBox.Checked += (sender, e) =>
{
// 处理选中事件
};
5. RadioButton(单选按钮)
用于从多个选项中选择一个,通常成组使用。
XAML 示例:
xml
<StackPanel>
<RadioButton Name="Radio1" GroupName="Options" Content="选项1" />
<RadioButton Name="Radio2" GroupName="Options" Content="选项2" />
</StackPanel>
C# 代码:
csharp
var radio1 = this.FindControl<RadioButton>("Radio1");
var radio2 = this.FindControl<RadioButton>("Radio2");
radio1.IsChecked = true; // 设置为选中
radio1.Checked += (sender, e) =>
{
// 处理选中事件
};
6. ComboBox(下拉列表)
用于从预定义列表中选择一项。
XAML 示例:
xml
<ComboBox Name="MyComboBox" Width="150" Height="30" />
C# 代码:
csharp
var comboBox = this.FindControl<ComboBox>("MyComboBox");
// 添加选项
comboBox.Items.Add("选项1");
comboBox.Items.Add("选项2");
comboBox.Items.Add("选项3");
// 设置默认选中项
comboBox.SelectedIndex = 0;
// 处理选择变化事件
comboBox.SelectionChanged += (sender, e) =>
{
var selectedItem = comboBox.SelectedItem;
};
7. Slider(滑块)
用于从一定范围内选择数值。
XAML 示例:
xml
<Slider Name="MySlider" Width="200" Minimum="0" Maximum="100" />
C# 代码:
csharp
var slider = this.FindControl<Slider>("MySlider");
slider.Value = 50; // 设置初始值
slider.ValueChanged += (sender, e) =>
{
double value = slider.Value;
};
8. ProgressBar(进度条)
用于显示操作的进度。
XAML 示例:
xml
<ProgressBar Name="MyProgressBar" Width="200" Height="20" />
C# 代码:
csharp
var progressBar = this.FindControl<ProgressBar>("MyProgressBar");
progressBar.Maximum = 100;
progressBar.Value = 30; // 设置当前进度
// 模拟进度更新
var timer = new DispatcherTimer
{
Interval = TimeSpan.FromSeconds(0.5)
};
timer.Tick += (sender, e) =>
{
progressBar.Value += 5;
if (progressBar.Value >= progressBar.Maximum)
{
timer.Stop();
}
};
timer.Start();
这些示例展示了 Avalonia 中常用组件的基本用法,采用了非绑定方式,直接通过代码操作组件的属性和事件。在实际应用中,你可以根据需要组合这些组件,创建复杂的用户界面。
Avalonia常用的界面布局组件介绍和例子代码
在 Avalonia 中,布局组件用于控制界面元素的排列方式,是构建复杂 UI 的基础。以下是常用的布局组件介绍及示例代码:
1. StackPanel(栈式布局)
作用:按垂直或水平方向线性排列子元素,适合简单的列表式布局。特点:子元素会按顺序排列,不会自动换行(垂直方向高度自适应,水平方向宽度自适应)。
XAML 示例:
xml
<!-- 垂直排列(默认) -->
<StackPanel Margin="10" Spacing="8">
<Button Content="按钮1" Width="100"/>
<Button Content="按钮2" Width="100"/>
<Button Content="按钮3" Width="100"/>
</StackPanel>
<!-- 水平排列 -->
<StackPanel Margin="10" Orientation="Horizontal" Spacing="8">
<Button Content="按钮A" Height="30"/>
<Button Content="按钮B" Height="30"/>
<Button Content="按钮C" Height="30"/>
</StackPanel>
C# 动态添加元素:
csharp
var stackPanel = this.FindControl<StackPanel>("MyStackPanel");
// 添加新按钮
var newButton = new Button { Content = "动态添加的按钮", Width = 120 };
stackPanel.Children.Add(newButton);
2. Grid(网格布局)
作用:通过行和列定义分割区域,适合复杂的结构化布局(如表单、多区域界面)。特点:子元素可指定占用的行 / 列范围,支持比例或固定尺寸定义。
XAML 示例:
xml
<Grid Margin="10">
<!-- 定义3行:第1行高50,第2行高*(剩余空间),第3行高2*(剩余空间的2倍) -->
<Grid.RowDefinitions>
<RowDefinition Height="50"/>
<RowDefinition Height="*"/>
<RowDefinition Height="2*"/>
</Grid.RowDefinitions>
<!-- 定义2列:第1列宽100,第2列宽*(剩余空间) -->
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<!-- 子元素指定位置 -->
<TextBlock Grid.Row="0" Grid.Column="0" Text="标题" FontSize="18"/>
<Button Grid.Row="0" Grid.Column="1" Content="操作" HorizontalAlignment="Right"/>
<TextBox Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2" Margin="5" HintText="跨两列的输入框"/>
<TextBlock Grid.Row="2" Grid.Column="0" Text="说明" VerticalAlignment="Top"/>
<TextBlock Grid.Row="2" Grid.Column="1" Text="网格布局适合复杂界面分区" Margin="5"/>
</Grid>
3. WrapPanel(自动换行布局)
作用:按水平或垂直方向排列子元素,当空间不足时自动换行(或换列)。特点:适合展示数量不固定的元素(如标签、图片列表)。
XAML 示例:
xml
<WrapPanel Margin="10" Orientation="Horizontal" Spacing="5" ItemWidth="80" ItemHeight="30">
<Button Content="标签1"/>
<Button Content="标签2"/>
<Button Content="标签3"/>
<Button Content="标签4"/>
<Button Content="标签5"/>
<Button Content="标签6"/>
<Button Content="标签7"/>
</WrapPanel>
Orientation:排列方向(Horizontal/Vertical)
Spacing:元素间距
ItemWidth/ItemHeight:强制子元素统一尺寸
4. DockPanel(停靠布局)
作用:按上、下、左、右方向停靠子元素,剩余空间由最后一个元素填充。特点:适合工具栏、状态栏等需要固定在边缘的元素。
XAML 示例:
xml
<DockPanel Margin="10" LastChildFill="True">
<!-- 顶部停靠(工具栏) -->
<StackPanel DockPanel.Dock="Top" Orientation="Horizontal" Height="40" Background="LightGray">
<Button Content="文件" Margin="5"/>
<Button Content="编辑" Margin="5"/>
</StackPanel>
<!-- 左侧停靠(导航栏) -->
<StackPanel DockPanel.Dock="Left" Width="100" Background="LightBlue">
<Button Content="首页" Margin="5"/>
<Button Content="设置" Margin="5"/>
</StackPanel>
<!-- 底部停靠(状态栏) -->
<TextBlock DockPanel.Dock="Bottom" Text="状态栏" Height="25" Background="LightGray" HorizontalAlignment="Stretch" TextAlignment="Center"/>
<!-- 最后一个元素填充剩余空间(内容区) -->
<TextBlock Text="主内容区域" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="16"/>
</DockPanel>
DockPanel.Dock:子元素的停靠方向(Top/Bottom/Left/Right)
LastChildFill:是否让最后一个子元素填充剩余空间(默认 True)
5. ScrollViewer(滚动布局)
作用:当内容超出显示区域时,提供滚动条。特点:适合展示长文本、大图片或内容动态增长的场景。
XAML 示例:
xml
<ScrollViewer Margin="10" Height="200" Width="300" VerticalScrollBarVisibility="Auto">
<StackPanel Spacing="10">
<TextBlock Text="长文本内容..." FontSize="14" TextWrapping="Wrap"/>
<Button Content="按钮1"/>
<Button Content="按钮2"/>
<Button Content="按钮3"/>
<Button Content="按钮4"/>
<Button Content="按钮5"/>
<Button Content="按钮6"/>
</StackPanel>
</ScrollViewer>
VerticalScrollBarVisibility/HorizontalScrollBarVisibility:滚动条显示策略(Auto/Visible/Hidden/Disabled)
6. Border(边框布局)
作用:为子元素添加边框、背景或圆角,本身不控制布局,但可嵌套其他布局。特点:常用于美化元素外观(如卡片、分组区域)。
XAML 示例:
xml
<Border Margin="10"
BorderThickness="2"
BorderBrush="Blue"
Background="AliceBlue"
CornerRadius="5"
Padding="10">
<StackPanel>
<TextBlock Text="带边框的区域" FontSize="16"/>
<TextBlock Text="这是Border组件的示例" Margin="5 0"/>
</StackPanel>
</Border>
7. Canvas(画布布局)
作用:通过坐标(Left/Top)精确定位子元素,适合自定义绘图或绝对定位场景。特点:子元素位置不受其他元素影响,需手动控制布局(不推荐复杂 UI)。
XAML 示例:
xml
<Canvas Margin="10" Height="300" Width="300" Background="LightGray">
<Button Canvas.Left="50" Canvas.Top="30" Content="位置(50,30)"/>
<Button Canvas.Left="150" Canvas.Top="100" Content="位置(150,100)"/>
<TextBlock Canvas.Left="80" Canvas.Top="200" Text="画布布局示例"/>
</Canvas>
布局组件的选择建议:
简单线性排列:优先用 StackPanel
复杂结构化布局:用 Grid(最常用)
动态数量元素(需换行):用 WrapPanel
边缘固定元素(工具栏 / 状态栏):用 DockPanel
内容过长:用 ScrollViewer 包裹
美化边框:用 Border 嵌套其他布局
通过组合这些布局组件,可以构建出灵活且美观的 Avalonia 界面。
上一篇:.NET Core基础问题收集