Skip to content

FlyleafHost

SuRGeoNix edited this page Apr 6, 2023 · 6 revisions

FlyleafHost has been designed to host a DPI aware D3D rendering surface for Flyleaf Player within WinUI 3, WinForms or WPF application with an optional transparent overlay. Its purpose is to provide an embedded functionality and solve issues like airspace for WPF.

In WinUI 3 it is possible to provide a swap chain for compisition to the WinUI SwapChainPanel directly. This allows the application to use FlyleafHost as a normal control.

This is not possible for WinForms and WPF. A D3D rendering surface requires a separate handle which cannot be used in parallel with user's controls / drawing.

In Winforms every Control has a different handle which make it easier to incorporate with the rest controls. However, true transparency is not supported in WinForms.

In WPF, controls does not have handles (only the windows) and a custom implementation with a follower Window to a hosted control is required. As the user cannot use the same surface to draw other controls an additional (owned by surface) overlay is required to accomplish this. Both the surface and overlay are transparent, borderless and non-styled windows and custom resize, move, minimize, maximize, close implementations should be in place.

Currently supported features by FlyleafHost (incorporate with Player / Renderer) :-

Currently for WPF and Partially for WinForms/WinUI

  • Attach / Detach
  • Drag Move (Self / Owner)
  • Drag & Drop Swap
  • Drag & Drop Open
  • Full / Normal Screen
  • Idle Mode
  • Key Bindings
  • Pan Move
  • Pan Zoom
  • Pan Rotation
  • Resize (+Keep Ratio)

All the features can be assigned on surface, overlay or both windows. In addition to the mouse bindings, Player already supports key bindings with the embedded functions or you can assign your own custom actions.

NOTE: For WPF and WinForms, FlyeafHost is included in the main FlyleafLib package and no additional packages are required.

  • Required namespace xmlns:fl="using:FlyleafLib.Controls.WinUI"
<fl:FlyleafHost Player="{Binding Player}">
    <TextBlock Text="Hello Flyleaf Host!" Foreground="DarkRed" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="50"/>
</fl:FlyleafHost>

To use the FullScreen implementation you need to include also the FullScreenContainer: -

<fl:FullScreenContainer x:Name="FSC">
  <fl:FlyleafHost Player="{Binding Player}">
      <TextBlock Text="Hello Flyleaf Host!" Foreground="DarkRed" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="50"/>
  </fl:FlyleafHost>
</fl:FullScreenContainer>

WinUI and SwapChainPanel still have issues for example with Key Events and Focus. You can check the samples for possible workarounds.

For all the below examples you will need to add this namespace to your xaml:-

  • xmlns:fl="clr-namespace:FlyleafLib.Controls.WPF;assembly=FlyleafLib"

For more examples check WpfFlyleafHost project under Tests within the solution.

FlyleafHost Implementation Notes

  • By adding a FlyleafHost in your XAML it will create a WPF Control and it will also create a Surface Window for rendering (as WPF control does not have a separate handle and cannot be used directly for rendering with DirectX). Additionally, if you want to have overlay content above the Surface Window it will create also an Overlay Window. Those Windows by default will be attached to the FlyleafHost Control and will be following its location and size.

DataContext Notes

  • By default, the DataContext of the Overlay Window will be set to FlyleafHost control (so you can access the dependency properties as it is not possible to use RelativeSource in the Binding -it will not be in the same visual tree)
  • Your DataContext that FlyleafHost inherits will be synchronized and can be used through the HostDataContext dependency property e.g. "{Binding HostDataContext.MainVMPropertyHere}"
  1. Hosted with direct Detached and Overlay Content
<fl:FlyleafHost Width="200" Height="120" Player="{Binding Player}">

    <fl:FlyleafHost.DetachedContent>
    
        <!-- Detached Content Here -->
        <Viewbox>
            <TextBlock Text="Hello Flyleaf Host!" Foreground="DarkRed"/>
        </Viewbox>
        
    </fl:FlyleafHost.DetachedContent>
    
    <!-- Overlay Content Here -->
    <Viewbox>
        <TextBlock Text="Hello Flyleaf Overlay!" Foreground="DarkRed"/>
    </Viewbox>

</fl:FlyleafHost>
  1. Hosted with Style Template (OverlayTemplate will be transfered to the Overlay Window)
<Grid>
    <Grid.Resources>
        <ResourceDictionary>
            <Style TargetType="{x:Type fl:FlyleafHost}" BasedOn="{StaticResource {x:Type fl:FlyleafHost}}">
                <Setter Property="Width" Value="200"/>
                <Setter Property="Height" Value="120"/>
                <Setter Property="AttachedDragMove" Value="Surface"/>
                <Setter Property="DetachedContent">
                    <Setter.Value>
                        <Viewbox>
                            <TextBlock Text="Hello Flyleaf Host!" Foreground="DarkRed"/>
                        </Viewbox>
                    </Setter.Value>
                </Setter>
                <Setter Property="OverlayTemplate">
                    <Setter.Value>
                        <ControlTemplate>
                            <Viewbox>
                                <TextBlock Text="Hello Flyleaf Overlay!" Foreground="DarkRed"/>
                            </Viewbox>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Style>
        </ResourceDictionary>
    </Grid.Resources>

    <fl:FlyleafHost Player="{Binding Player}"/>
</Grid>
  1. Hosted with Custom Overlay Window (will not work in design mode)
<Window ...
    >
    
<Window.Resources>
    <<!--Creating a new Instace of OverlayWindow-->
    <local:OverlayWindow x:Key="OverlayWindow"/>
</Window.Resources>


<Grid>
    <!--Providing the Overlay Window to FlyleafHost-->
    <fl:FlyleafHost Player="{Binding Player}" Overlay="{StaticResource OverlayWindow}"/>
</Grid>
  1. Stand Alone Overlay Window
// Ensure Engine.Start() at App.OnStartup()
using FlyleafLib.Controls.WPF;
using FlyleafLib.MediaPlayer;

public partial class MainWindow : Window
{
    // Creates the Surface and assign this Window as the Overlay
    public FlyleafHost FlyleafHost { get; set; }
    
    // We pass a new Player to FlyleafHost
    public Player Player { get; set; } = new Player();

    public MainWindow()
    {
        FlyleafHost = new FlyleafHost(this)
        {
            KeyBindings = AvailableWindows.Both,
            DetachedResize = AvailableWindows.Both,
            IsAttached = false,

            Player = Player
        };

        InitializeComponent();

        DataContext = this;
    }
}

You just need to add FlyleafHost Control from your toolbox and after creating your own FlyleafLib.MediaPlayer.Player you will need to pass the Control to it.

Player player = new Player();
flyleafControl1.Player = Player;

Currently, not all functionality is supported (such as Overlay/Detached/Resize etc.) for WinForms but it will be added in the future.

Clone this wiki locally