要重新创建我所做的工作,请创建一个新的AvaloniaUI项目.在MainWindow.cs中,通过调用this.FindDescendantOfType<TitleBar>();
inprotected override void OnApplyTemplate(TemplateAppliedEventArgs e)
获取标题栏对象.然后将任何事件添加到其PointerPressed事件.
但是,永远不会到达事件处理程序方法的断点.
要重新创建我所做的工作,请创建一个新的AvaloniaUI项目.在MainWindow.cs中,通过调用this.FindDescendantOfType<TitleBar>();
inprotected override void OnApplyTemplate(TemplateAppliedEventArgs e)
获取标题栏对象.然后将任何事件添加到其PointerPressed事件.
但是,永远不会到达事件处理程序方法的断点.
你不能那样做.如果您判断TitleBar
,您会发现它实际上是一个没有大小或函数的通用对象,只是存在于树中(不确定它们为什么不只给您一个空的,可能是一些内部可空的问题).
无论如何,你做不到的原因是因为Chrome是基于操作系统的,并由操作系统控制,而实现是特定于操作系统的.另一种 Select 是构建您自己的标题栏,并隐藏系统标题栏,自己提供必要的功能(请查看此选项以了解 idea =>;Custom TitleBar Template).
如果你不想这样做,而且你只是在做Windows应用程序,你可以窥探你自己的消息队列(安全,因为没有DLL注入,并且GUI线程不会跨非托管线程移动)来检测"非客户端",例如标题栏点击消息(WM_NCLBUTTONDOWN)并做出react .例如:
MainWindow.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="Test01.MainWindow"
Title="Test01" >
<Grid>
<Label Name="MainLabel"/>
</Grid>
</Window>
MainWindow.axaml.cs
using Avalonia.Controls;
using System;
using System.Runtime.InteropServices;
namespace Test01;
public partial class MainWindow : Window
{
private const int WM_NCLBUTTONDOWN = 0x00a1;
private const int WH_GETMESSAGE = 3;
private IntPtr theHook;
public MainWindow()
{
InitializeComponent();
}
protected override void OnInitialized()
{
base.OnInitialized();
theHook = MyInterop.SetWindowsHookEx(WH_GETMESSAGE, MsgHook, IntPtr.Zero, MyInterop.GetCurrentThreadId());
// var err = Marshal.GetLastWin32Error();
}
private int MsgHook(int nCode, IntPtr wParam, IntPtr lParam)
{
// mandatory shortcut
if (nCode < 0) return MyInterop.CallNextHookEx(theHook, nCode, wParam, lParam);
// is it a NC click?
var msg = (MyInterop.MsgStruct?)Marshal.PtrToStructure(lParam, typeof(MyInterop.MsgStruct));
if (msg?.message == WM_NCLBUTTONDOWN)
{
// your action
MainLabel.Content = "I am pressed!!!";
}
return MyInterop.CallNextHookEx(theHook, nCode, wParam, lParam);
}
}
MyInterop.cs
namespace Test01;
internal static class MyInterop
{
[StructLayout(LayoutKind.Sequential)]
public class MsgStruct
{
public IntPtr hwnd;
public uint message;
// we dont care about the rest of MSG struct
}
internal delegate int HookProc(int code, IntPtr wParam, IntPtr lParam);
[System.Runtime.InteropServices.DllImport("user32.dll", EntryPoint = "SetWindowsHookEx", SetLastError = true)]
internal static extern IntPtr SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hMod, uint dwThreadId);
[System.Runtime.InteropServices.DllImport("user32.dll")]
internal static extern int CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);
[DllImport("kernel32.dll")]
internal static extern uint GetCurrentThreadId();
}
这只是一个工作示例,您可以将其重新打包为一些可观察到的模式或事件启动器.
此外,这只适用于Windows,不适用于Linux和MacOS.对于X11,也有一个消息队列,所以我认为替代方案可能是可能的.对于MacOS,我一点也不确定.
注意:由于Avalonia(Xaml Compiler error when code-behind class contains a DllImport method #10046)中的错误,我不得不将所有外部定义移到一个单独的类中.一旦修复,MyInterop就可以合并到Main.cs中