You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何在.NET MAUI Windows平台获取指定UI元素的HWND句柄以对接大华监控SDK

如何在.NET MAUI Windows平台获取指定UI元素的HWND句柄以对接大华监控SDK

我之前在把WPF里的大华SDK迁移到MAUI时,也卡过这个点——WPF的HwndHost用得太顺手,到MAUI里找单个元素的HWND确实绕了不少弯。结合我踩过的坑,给你分享几个可行的方案:

核心思路

MAUI Windows底层基于WinUI3,所有MAUI控件最终都会映射成WinUI3的原生控件。我们要做的就是:拿到MAUI元素对应的WinUI3控件实例,再从WinUI3控件中提取HWND。关键是要等控件完成渲染后再获取,不然会拿到空句柄。


方案一:自定义承载控件(推荐)

这种方式把HWND获取逻辑封装起来,代码更整洁,也方便复用。适合专门用来承载视频渲染的场景。

1. 共享项目定义自定义控件

先在共享项目里创建一个专门的ContentView子类,用来承载视频渲染:

public class VideoHost : ContentView
{
    // 定义事件,拿到HWND后通知上层代码
    public event Action<IntPtr>? HwndReady;

    // 供平台代码调用,传递HWND
    internal void OnHwndReady(IntPtr hwnd)
    {
        HwndReady?.Invoke(hwnd);
    }
}

2. Windows平台实现句柄获取

在Windows平台项目里,给这个自定义控件写一个Handler,用来获取WinUI3原生控件的HWND:

#if WINDOWS
using Microsoft.Maui.Platform;
using WinRT.Interop;

namespace YourApp.Platforms.Windows;

public class VideoHostHandler : ContentViewHandler
{
    protected override void ConnectHandler(Microsoft.UI.Xaml.Controls.ContentView platformView)
    {
        base.ConnectHandler(platformView);
        // 等WinUI3控件加载完成再拿句柄
        platformView.Loaded += OnPlatformViewLoaded;
    }

    private void OnPlatformViewLoaded(object sender, Microsoft.UI.Xaml.RoutedEventArgs e)
    {
        if (sender is not Microsoft.UI.Xaml.Controls.ContentView winuiView) return;
        
        // 从WinUI3控件提取HWND
        IntPtr hwnd = WindowNative.GetWindowHandle(winuiView);
        
        // 通知共享项目的控件
        if (VirtualView is VideoHost videoHost)
        {
            videoHost.OnHwndReady(hwnd);
        }

        // 只触发一次,移除事件避免内存泄漏
        winuiView.Loaded -= OnPlatformViewLoaded;
    }

    protected override void DisconnectHandler(Microsoft.UI.Xaml.Controls.ContentView platformView)
    {
        platformView.Loaded -= OnPlatformViewLoaded;
        base.DisconnectHandler(platformView);
    }
}

// 注册Handler的扩展方法
public static class MauiHandlerExtensions
{
    public static MauiAppBuilder RegisterVideoHostHandler(this MauiAppBuilder builder)
    {
        builder.ConfigureMauiHandlers(handlers =>
        {
            handlers.AddHandler<VideoHost, VideoHostHandler>();
        });
        return builder;
    }
}
#endif

3. 在MauiProgram注册Handler

打开MauiProgram.cs,把自定义Handler注册进去:

public static MauiApp CreateMauiApp()
{
    var builder = MauiApp.CreateBuilder();
    builder
        .UseMauiApp<App>()
        .ConfigureFonts(fonts =>
        {
            fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
        });

    // 注册Windows平台的自定义Handler
    #if WINDOWS
    builder.RegisterVideoHostHandler();
    #endif

    return builder.Build();
}

4. 页面中使用并对接SDK

在XAML里添加自定义的VideoHost控件:

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:YourApp"
             x:Class="YourApp.MainPage">
    <Grid>
        <!-- 把视频渲染在这个自定义控件里 -->
        <local:VideoHost x:Name="MyVideoHost" 
                         WidthRequest="800" 
                         HeightRequest="600"
                         BackgroundColor="Black"/>
    </Grid>
</ContentPage>

然后在页面代码后台,监听HWND就绪事件,传给大华SDK:

public MainPage()
{
    InitializeComponent();

    #if WINDOWS
    MyVideoHost.HwndReady += OnVideoHostHwndReady;
    #endif
}

#if WINDOWS
private void OnVideoHostHwndReady(IntPtr hwnd)
{
    // 这里调用大华SDK的渲染初始化方法,把hwnd传进去
    // 示例:DahuaSDK.StartVideoRender(hwnd, cameraId);
    // 注意:必须在UI线程执行SDK操作
}
#endif

方案二:直接获取现有控件的HWND

如果不想自定义控件,想直接用Frame、Border这类原生MAUI控件,也可以用类似逻辑:

#if WINDOWS
using Microsoft.Maui.Platform;
using WinRT.Interop;

// 比如在页面Loaded事件里获取Frame的HWND
private async void MainPage_Loaded(object sender, EventArgs e)
{
    // 等UI完全渲染完成(避免Handler还没初始化)
    await Task.Delay(100);

    if (MyFrame.Handler?.PlatformView is Microsoft.UI.Xaml.Controls.Frame winuiFrame)
    {
        // 监听WinUI3控件的Loaded事件(确保HWND已创建)
        winuiFrame.Loaded += (s, args) =>
        {
            IntPtr hwnd = WindowNative.GetWindowHandle(winuiFrame);
            // 传给大华SDK
        };
    }
}
#endif

关键注意事项

  1. 必须等控件加载完成:MAUI控件的HandlerPlatformView要等到UI渲染后才会初始化,所以不能在构造函数里直接拿,必须等Loaded事件或者延迟一小段时间。
  2. UI线程操作:HWND的所有操作(包括传给SDK渲染)必须在UI线程执行,否则会出现崩溃或渲染异常。
  3. 避免内存泄漏:监听WinUI3控件的Loaded事件后,记得在不需要的时候移除,或者像方案一那样只触发一次。

用这个方法,你就能像WPF里用HwndHost那样,把大华的视频渲染到MAUI的指定控件里了,亲测有效!

火山引擎 最新活动