3

I have a SWF object embedded in a WindowsFormsHost Control inside a WPF window.

I'd like to add a toolbar over the swf movie.

The problem with the snippet of code I have below, is that when the new child is added to the host control (or the movie is loaded, I haven't figured out which yet), the toolbar is effectively invisible. It seems like the z-index of the swf is for some reason set to the top.

Here is what it looks like:

XAML:

<Grid Name="Player">
   <WindowsFormsHost Name="host" Panel.ZIndex="0" />
   <Grid Name="toolbar" Panel.ZIndex="1" Height="50"
      VerticalAlignment="Bottom">
           [play, pause, seek columns go here]
   </Grid>
</Grid>

C#:

private void Window_Loaded(object sender, RoutedEventArgs e)
{
   flash = new AxShockwaveFlashObjects.AxShockwaveFlash();
   host.Child = flash;
   flash.LoadMovie(0, [movie]); // Movie plays, but no toolbar :(
}

Any insight on this issue would be much appreciated.


Update: Since no suitable answer was posted, I've placed my own solution below. I realize this is more of a hack than a solution so I'm open to other suggestions.

funseiki
  • 9,167
  • 9
  • 36
  • 59
  • Note: I have also tried nesting the 'toolbar' inside a popup, with 'host' as its target. The problem with this method is that if the window is moved/resized, the popup will not follow. – funseiki Jun 28 '12 at 16:25
  • Looks like this may not be possible without some hacking. Microsoft's [post](http://msdn.microsoft.com/en-us/library/ms744952.aspx) – funseiki Jun 28 '12 at 18:21
  • (From your link above) "A hosted Windows Forms control is also drawn on top of any Adorner elements." I was going to say use an Adorner, but it looks like this won't work either. – Tom Jun 28 '12 at 18:25
  • Yeah :/, looks like I'll either have to go with the popup method and resize/move when the window moves or I'll need to nest two windows inside another window, with the toolbar being on top – funseiki Jun 28 '12 at 18:48
  • 1
    I updated my question with a possible solution. – funseiki Jun 28 '12 at 19:19

2 Answers2

1

Here is my hackaround the WindowsFormsHost Z-index issue.

The idea is to place whatever you need to be overlayed nested inside a Popup. Then to update that popup's position as per this answer whenever the window is resized/moved.

Note: You'll probably also want to handle events when the window becomes activated/deactivated, so the pop disappears when the window goes out of focus (or behind another window).

XAML:

<Window [stuff]
   LocationChanged="Window_LocationChanged"
   SizeChanged="Window_SizeChanged" >
   <Grid Name="Player">
   [same code as before]
       <Popup Name="toolbar_popup" IsOpen="True" PlacementTarget="{Binding ElementName=host}">
           [toolbar grid goes here]
       </Popup>
   </Grid>
</Window>

C#:

private void resetPopup()
{
   // Update position
   // https://stackoverflow.com/a/2466030/865883
   var offset = toolbar_popup.HorizontalOffset;
   toolbar_popup.HorizontalOffset = offset + 1;
   toolbar_popup.HorizontalOffset = offset;

   // Resizing
   toolbar_popup.Width = Player.ActualWidth;
   toolbar_popup.PlacementRectangle = new Rect(0, host.ActualHeight, 0, 0);
   toolbar_popup.Placement = System.Windows.Controls.Primitives.PlacementMode.Top;
}
private void Window_LocationChanged(object sender, EventArgs e)
{ resetPopup(); }

private void Window_SizeChanged(object sender, SizeChangedEventArgs e)
{ resetPopup(); }
Community
  • 1
  • 1
funseiki
  • 9,167
  • 9
  • 36
  • 59
0

Another solution I've discovered is to use Windows Forms' ElementHost control. Since I'm using a Windows Form inside a WPF window anyway, why not just use an entire Windows Form and save myself Z-Issue headaches.

The ElementHost control is really useful, because I can still use my toolbar UserControl, and embed it inside the Windows Form. I've discovered that adding a child can be finicky with Windows Forms, so here's a snippet describing the solution:

First, toss in the ActiveX object, then an ElementHost Control, using the designer.

Form1.Designer.cs:

private AxShockwaveFlashObjects.AxShockwaveFlash flash;
private System.Windows.Forms.Integration.ElementHost elementHost1;

Form1.cs

public Form1(string source)
{
     InitializeComponent();
     toolbar = new UserControl1();
     this.elementHost1.Child = this.toolbar;
     this.flash.LoadMovie(0, source);
}

Note that the child was not set in the designer. I found that for more complex UserControls the designer will complain (though nothing happens at runtime).

This solution is, of course, still not entirely ideal, but it provides the best of both worlds: I can still code my UserControls in XAML, but now I don't have to worry about Z-indexing issues.

funseiki
  • 9,167
  • 9
  • 36
  • 59