對於使用avalonia
的時候某些功能需要到一些提示,比如異常或者成功都需要對使用者進行提示,所以需要單獨實現彈窗功能,並且可以自定義內部元件,這一期將手動實現一個簡單的小彈窗,並且很容易自定義
實現我們需要建立一個avalonia
MVVM的專案模板
並且取名PopoverExample
然後一直預設建立。
在Views
資料夾中建立一個元件,選擇Window模板
,建立名稱Dialog
然後開啟Dialog.axaml
檔案,修改相關程式碼,
<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="450"
x:Class="Dialog.Views.DialogBase"
ExtendClientAreaToDecorationsHint="True"
ExtendClientAreaChromeHints="NoChrome"
ExtendClientAreaTitleBarHeightHint="-1"
Title="DialogBase">
<StackPanel>
<Grid>
<Grid HorizontalAlignment="Left">
<TextBlock>標題</TextBlock>
</Grid>
<Grid HorizontalAlignment="Right">
<Button Click="Close_OnClick" Name="Close">關閉</Button>
</Grid>
</Grid>
<Grid>
<TextBlock Name="Content"></TextBlock>
</Grid>
</StackPanel>
</Window>
以下程式碼是用於隱藏預設的標題列的
ExtendClientAreaToDecorationsHint="True"
ExtendClientAreaChromeHints="NoChrome"
ExtendClientAreaTitleBarHeightHint="-1"
開啟DialogBase.axaml.cs
,修改修改程式碼
using Avalonia;
using Avalonia.Controls;
using Avalonia.Interactivity;
using Avalonia.Markup.Xaml;
namespace Dialog.Views;
public partial class DialogBase : Window
{
public DialogBase()
{
InitializeComponent();
#if DEBUG
this.AttachDevTools();
#endif
}
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
}
private void Close_OnClick(object? sender, RoutedEventArgs e)
{
Close();
}
}
Dialog
Manage類建立Dialog
Manage類,用於管理Dialog
建立DialogManage.cs
,新增以下程式碼
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Threading;
namespace Dialog.Views;
public static class DialogManage
{
private static readonly Dictionary<DialogType, DialogBase> _dialogBases = new();
public static void Show(DialogType type, string content, int height = 100, int width = 200, int timing = 3000)
{
DialogBase dialog;
// 防止並行可自行修改
lock (_dialogBases)
{
if (_dialogBases.Remove(type, out var dialogBase))
{
try
{
dialogBase.Close();
}
catch
{
}
}
dialog = new DialogBase
{
Height = height,
Width = width,
WindowStartupLocation = WindowStartupLocation.Manual // 不設定的話無法修改視窗位置
};
if (timing > 0)
{
// 彈窗定時關閉
_ = Task.Run(async () =>
{
await Task.Delay(timing);
// 先刪除並且拿到刪除的value
if (_dialogBases.Remove(type, out var dialogBase))
{
// 操作元件需要使用ui執行緒
_ = Dispatcher.UIThread.InvokeAsync(() =>
{
try
{
// 關閉彈窗元件
dialogBase.Close();
}
// 可能已經被關閉所以可能會出現異常
catch
{
}
});
}
});
}
// 新增到字典中
_dialogBases.TryAdd(type, dialog);
}
// 獲取當前螢幕
var bounds = dialog.Screens.ScreenFromVisual(dialog).Bounds;
// 偏移
int skewing = 20;
// window的工作列高度
int taskbar = 50;
int x, y;
switch (type)
{
case DialogType.topLeft:
x = skewing;
y = skewing;
break;
case DialogType.topCenter:
x = (int)((bounds.Width - dialog.Width) / 2);
y = skewing;
break;
case DialogType.topRight:
x = (int)((bounds.Width - dialog.Width) - skewing);
y = skewing;
break;
case DialogType.leftLower:
x = 20;
y = (int)(bounds.Height - dialog.Height) - taskbar - skewing;
break;
case DialogType.centerLower:
x = (int)((bounds.Width - dialog.Width) / 2);
y = (int)(bounds.Height - dialog.Height) - taskbar - skewing;
break;
case DialogType.rightLower:
x = (int)(bounds.Width - dialog.Width - skewing);
y = (int)(bounds.Height - dialog.Height) - taskbar - skewing;
break;
default:
throw new ArgumentOutOfRangeException(nameof(type), type, null);
}
// 設定彈窗的位置
dialog.Position = new PixelPoint(x, y);
// 獲取內容顯示的元件並且將內容顯示上去
var contentBox = dialog.Find<TextBlock>("Content");
contentBox.Text = content;
dialog.Show();
}
}
public enum DialogType
{
/// <summary>
/// 左上
/// </summary>
topLeft,
/// <summary>
/// 居中靠上
/// </summary>
topCenter,
/// <summary>
/// 右上
/// </summary>
topRight,
/// <summary>
/// 左下
/// </summary>
leftLower,
/// <summary>
/// 居中靠下
/// </summary>
centerLower,
/// <summary>
/// 右下
/// </summary>
rightLower
}
對於彈窗元件已經完成,
開啟MainWindow.axaml
檔案修改程式碼
<Window xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="using:Dialog.ViewModels"
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"
x:Class="Dialog.Views.MainWindow"
Height="400"
Width="400"
Icon="/Assets/avalonia-logo.ico"
Title="Dialog">
<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/>
</Design.DataContext>
<StackPanel HorizontalAlignment="Center">
<Button Height="40" Name="OpenDialog" Click="OpenDialog_OnClick">開啟新彈窗</Button>
</StackPanel>
</Window>
開啟 MainWindow.axaml.cs
修改相關程式碼
using Avalonia.Controls;
using Avalonia.Interactivity;
namespace Dialog.Views;
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
// 定義列舉開始的值
private int i = 0;
private void OpenDialog_OnClick(object? sender, RoutedEventArgs e)
{
// 彈窗新視窗
DialogManage.Show((DialogType)i++, "彈窗內容:" + i);
// 超過列舉值重新賦值
if (i == 6)
{
i = 0;
}
}
}
來自token的分享