Toolbar Overlay over WindowsFormsHost - c#

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.

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(); }

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.

Related

How can I capture WPF events from a Winforms app

I have an WPF User control which is is hosted in an Elementhost. I use elementhost to include an WPF user control in my classical Windows forms app.
Now, from Windows forms side I am trying to capture the mouseDown event that is produced in an WPF label but I don't know how to do it.
Any ideas?
A case might be able to help you. The winform form calls the wpf control.
Create a WPF custom control. The xaml code of the control is as follows.
<Grid>
<Image Margin="10,10,10,90" x:Name="img" Stretch="Uniform" Opacity="1">
<Image.BitmapEffect>
<DropShadowBitmapEffect Opacity="1" />
</Image.BitmapEffect>
</Image>
<TextBox Background="Transparent" Foreground="White" Height="40" FontSize="32" Margin="44,0,56,36" x:Name="txtBox1" Opacity="0.5" Text="" VerticalAlignment="Bottom" /> </Grid>
You need to add the corresponding function to set the effect. The code is as follows.
public void SetSource(string fileName)
{
img.Source = new BitmapImage(new Uri(fileName) );
}
public void SetOpacity(double opacity)
{
img.Opacity = opacity;
}
//
public string GetText()
{
return txtBox1.Text;
}
Create a Winform application and add a reference, otherwise the control will not work properly. The list of references is pictured below.
Regenerate the solution. On the left toolbar, a WPF control appears and drag it to the form.
Use the button control in the winform project to call the corresponding function.
private void button1_Click(object sender, EventArgs e)
{
((UserControl1)elementHost1.Child).SetSource(#"C:\Users\Admin\Pictures\Saved Pictures\9837f99502eba3d01d4fb671cab20c15.jpg");
}
private void button2_Click(object sender, EventArgs e)
{
((UserControl1)elementHost1.Child).SetOpacity(0.5);
}
private void button3_Click(object sender, EventArgs e)
{
string text = ((UserControl1)elementHost1.Child).GetText();
label1.Text = text;
}
Test items: The left side is the traditional Winform control. The right side is the imported WPF control. You can clearly see the "translucent" effect of the picture.
Not sure what exactly you're trying to achieve. Below is a simple example.You can edit the MouseDown event of the UserControl as needed.
If there is a problem, please make your problem clearer and show me the complete code sample that can reproduce your problem for analysis.
UserControl:
<Grid>
<Label x:Name="label" Content="Label" MouseDown="label_MouseDown" Background="AliceBlue" Width="300" Height="200" />
</Grid>
private void label_MouseDown(object sender, MouseButtonEventArgs e)
{
MessageBox.Show("hello");
}
Add the UserControl reference in the WinForms project, drag and drop the UserControl on the Form1 designer after rebuilding the WinForms project.
The result of running the project and clicking the Label in the UserControl is shown in the figure.

What alternatives do I have to flyout/ContentDialog? (c#, xaml)

I currently have a program where you can load a text in it.
Now I created a button that Pops up a flyout/ContentDialog but Im not happy with it because Limits me of what Im trying to achieve.
When I click the button it opens a flyout, the flyout gets the full Focus. That means I cannot scroll to the text WHILE the flyout-box is open. And if I click outside the flyout-box the flyout-box disappears.
I have a similar Problem to the ContentDialog.
When I click the button and the ContentDialog Pops up, everything behind the ContentDialog goes a bit into White/Grey Color. Also the ContentDialog does not allow any Focus outside the ContentDialog itself.
So what do I want to have?
I want that when I click on the button that a Window appears. I should be able to customize the window (writing text in it and it should have a button).
While this Window is open I want to be able to do Actions outside that window without the window Closing. For example Scrolling through the text I loaded.
Is there something I can achieve this with?
Take a look at the Popup class. This will let you display content on top of other content within your app's window. It's similar to the Flyout but without all of the built-in Flyout behavior that you don't want. The Popup class documentation has more details and commentary on when and how to use it.
Here's a really bland example with no styling.
<Grid>
<Popup x:Name="popup">
<StackPanel>
<TextBlock Text="Poppity pop pop" />
<Button Click="ClosePopup_Click">Close</Button>
</StackPanel>
</Popup>
<Button Click="OpenPopup_Click">Open Popup</Button>
</Grid>
private void OpenPopup_Click(object sender, RoutedEventArgs e)
{
popup.IsOpen = true;
}
private void ClosePopup_Click(object sender, RoutedEventArgs e)
{
popup.IsOpen = false;
}
There is a slightly more complicated example in the Popup documentation
I just hide and show grids with whatever I want inside.

Fix ZOrder/clipping of process-isolated (via FrameworkElementAdapter) WPF controls

I have a wpf application which hosts a group of controls which are backed by another process via FrameworkElementAdapter. For some reason, these controls have a clipping / Z order issue that non-remoted controls don't seem to exhibit.
The gridview in the above image is one of those hosted controls, and improperly overlaps the panel on the right, while the contentcontrol that hosts it behaves as expected. I have explicitly set ClipToBounds = true on the gridview.
My question is :
Is there a way to make my controls clip and honor the z order properly, or does FrameworkElementAdaptermake this impossible by, for example, rendering them onto the adorner layer or something?
Xaml:
<Grid>
<Viewbox>
<ContentControl Content="{Binding VM.ErrorView}" Height="240" Width="425" Loaded="ContentControl_Loaded"/>
</Viewbox>
</Grid>
C#:
public partial class ValidationView : UserControl
{
public ValidationView()
{
InitializeComponent();
}
private void ContentControl_Loaded(object sender, RoutedEventArgs e)
{
var cc = (sender as ContentControl);
var content = cc.Content as FrameworkElement;
content.ClipToBounds = true;
}
}
Interesting side note: if I inspect my app with Snoop, in the preview Snoop displays when you mouse over parts of the visual tree graph, the remoted controls don't appear at all and their respective host contentcontrols appear empty, but are the right size

Cannot drag text into a WPF window

I'm trying to set up a WPF window so that it can accept different types of data via Drag and Drop. If I make a new project and set the window to the following:
<Window x:Class="DropShare.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300" AllowDrop="True" DragEnter="Window_DragEnter">
<Grid>
</Grid>
</Window>
And set the code-behind to:
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
}
private void Window_DragEnter(object sender, DragEventArgs e)
{
}
}
I only ever get DragEnter firing for files. It never fires for anything else - text, images, etc.
Is there something I'm missing? All the tutorials I've read have seemed to suggest this is all that's needed as the DragEnter event handler let's me state what I accept.
So your code works fine for me. But try this...
In your Window:
<Label Background="Purple" HorizontalAlignment="Center" VerticalAlignment="Center" Content="Drag from here!" MouseDown="Label_MouseDown"/>
and in your code behind:
private void Label_MouseDown(object sender, MouseButtonEventArgs e)
{
DragDrop.DoDragDrop(this, "This is just a test", DragDropEffects.All);
}
Then drag from the label into the window and see if your event fires.
If this works, it may have something to do with the permissions level between Visual Studio and your outside environment (possibly).
See:
https://superuser.com/questions/59051/drag-and-drop-file-into-application-under-run-as-administrator
In WPF drag and drop feature always has to deal with DragDrop Class, Please check here how to do drag and drop across applications

Problems with webviewbrush and Rectangle

I'm having problems hiding a webview, my application is based on a webview as I'm showing words definitions with an html format, when I need to show any settings pane or any other element over the webview I need to hide it and fill a rectangle with a webviewbrush...
The problem is that when I do it, the rectangle shows an stretched image... I've tried using different stretch settings both for the webview brush and rectangle but can't make it look exactly like the webview...
For example if I use stretch none on the webviewbrush.. it works under some resolutions, but on higher resolutions it shows the image bigger than it is...
I can't seem to find a fix for this... could anybody give me a hand?
Try the MSDN-Example, it works well on my project. If it doesen't work create a new clean project and try it without your additional xaml maybe you mest up some properties ;-)
XAML:
<Grid>
<WebView x:Name="contentView" Source="http://www.contoso.com"/>
<Rectangle x:Name="contentViewRect"/>
</Grid>
Code behind:
private void AppBar_Opened(object sender, object e)
{
WebViewBrush wvb = new WebViewBrush();
wvb.SourceName = "contentView";
wvb.Redraw();
contentViewRect.Fill = wvb;
contentView.Visibility = Windows.UI.Xaml.Visibility.Collapsed;
}
private void AppBar_Closed(object sender, object e)
{
contentView.Visibility = Windows.UI.Xaml.Visibility.Visible;
contentViewRect.Fill = new SolidColorBrush(Windows.UI.Colors.Transparent);
}

Categories