使用 WindowsXamlHost Overlay 托管 CaptureElement

Hosting CaptureElement with WindowsXamlHost Overlay

我试图在我的 WPF .NET Core 3.1 应用程序中将 Grid 覆盖在由 WindowsXamlHost 托管的 CaptureElement(相机供稿)之上,但是 CaptureElement始终位于任何其他控件之上。

无法在 WindowsXamlHost/CaptureElement 上叠加网格吗?

È 已创建示例应用程序 https://github.com/ValonK/SampleWPFXamlHost。我需要 CaptureElement,但还没有找到任何东西来捕捉相机画面并在上面放置一些叠加层。

Xaml代码

<Window x:Class="SampleWPFXamlHost.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        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"
        xmlns:local="clr-namespace:SampleWPFXamlHost"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
        <Grid Height="200"
              Width="200"
              Background="Red"/>
        <ContentControl HorizontalContentAlignment="Stretch"
                        VerticalContentAlignment="Stretch"
                        Content="{Binding XamlHostCaptureElement}"/>


    </Grid>
</Window>

视图模型

public class MainViewModel : PropertyChangedAware
{
    public MainViewModel()
    {
        GetUwpCaptureElement();
    }

    private MediaCapture _mediaCapture;

    public MediaCapture MediaCapture {
        get {
            if (_mediaCapture == null)
                _mediaCapture = new MediaCapture();
            return _mediaCapture;
        }
        set {
            _mediaCapture = value;
            OnPropertyChanged(nameof(MediaCapture));
        }
    }


    public CaptureElement CaptureElement { get; set; }

    public WindowsXamlHost XamlHostCaptureElement { get; set; }

    /// <summary>
    /// Create / Host UWP CaptureElement
    /// </summary>
    private void GetUwpCaptureElement()
    {
        XamlHostCaptureElement = new WindowsXamlHost
        {
            InitialTypeName = "Windows.UI.Xaml.Controls.CaptureElement"
        };
        XamlHostCaptureElement.ChildChanged += XamlHost_ChildChangedAsync;
    }

    private async void XamlHost_ChildChangedAsync(object sender, EventArgs e)
    {
        var windowsXamlHost = (WindowsXamlHost)sender;

        var captureElement = (CaptureElement)windowsXamlHost.Child;
        CaptureElement = captureElement;
        CaptureElement.Stretch = Windows.UI.Xaml.Media.Stretch.UniformToFill;

        try
        {
            await StartPreviewAsync();
        }
        catch (Exception)
        {

        }
    }

    private async Task StartPreviewAsync()
    {
        try
        {
            await MediaCapture.InitializeAsync();
        }
        catch (UnauthorizedAccessException ex)
        {
            //_logger.Info($"The app was denied access to the camera \n {ex}");
            return;
        }

        try
        {
            CaptureElement.Source = MediaCapture;
            await MediaCapture.StartPreviewAsync();
        }
        catch (System.IO.FileLoadException ex)
        {
            System.Diagnostics.Debug.WriteLine(ex.ToString());
        }

    }
}

public class PropertyChangedAware : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged([CallerMemberName]string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

Is it not possible to overlay a grid on top of WindowsXamlHost/CaptureElement?

没有。就像 WindowsFormsHost 中的 Windows Forms 控件一样,WindowsXamlHost 托管在单独的 HWND 中,该 HWND 始终绘制在 WPF 元素之上。

来自docs

A hosted Windows Forms control is drawn in a separate HWND, so it is always drawn on top of WPF elements.

有一个类似的问题有一些可用的答案here

当我尝试使用 XAML Islands 在我的 WPF 应用程序中托管 CaptureElement 时,我遇到了同样的问题。正如 mm8 所说,问题是因为 WPF 将在任何 WPF 元素之后绘制 WindowsXamlHost。

但是如果您只是想在 CaptureElement 上叠加 TextBlock 之类的东西,那么这个问题有一个快速的解决方案。只需托管一个 UWP 用户控件,而不是直接托管 CaptureElement。使用 MVVM,您可以将文本从 WPF 应用程序传递到 UWP 用户控件,它会显示出来。

示例:

<UserControl
    x:Class="MyUwpApp.MyUserControl1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    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">

    <Grid>
        <CaptureElement x:Name="captureElement"/>
        <TextBlock Text="{Binding MyText}" Foreground="Yellow" FontSize="64" VerticalAlignment="Bottom" HorizontalAlignment="Left" Margin="15"/>
    </Grid>
</UserControl>