WPF 3.5 WebBrowser control and ZIndex - wpf

I'm trying to figure out why the control does not honor ZIndex.
Example 1 - which works fine
<Canvas>
<Rectangle Canvas.ZIndex="1" Height="400" Width="600" Fill="Yellow"/>
<Rectangle Canvas.ZIndex="2" Height="100" Width="100" Fill="Red"/>
</Canvas>
Example 2 - which does not work
<Canvas>
<WebBrowser Canvas.ZIndex="1" Height="400" Width="600" Source="http://www.stackoverflow.com"/>
<Rectangle Canvas.ZIndex="2" Height="100" Width="100" Fill="Red"/>
</Canvas>
Thanks,
-- Ed

Unfortunately this is because the WebBrowser control is a wrapper around the Internet Explorer COM control. This means that it gets its own HWND and does not allow WPF to draw anything over it. It has the same restrictions as hosting any other Win32 or WinForms control in WPF.
MSDN has more information about WPF/Win32 interop.

You are running into a common WPF pitfall, most commonly called the "The Airspace Problem". A possible solution is to NOT use the WebBrowser control, and instead go for something a little crazier - namely an embedded WebKit browser rendering directly to WPF. There are two packages that do this; Awesomonium (commercial) and Berkelium (open-source). There's a .NET wrapper for both of these.

You could SetWindowRgn to fake the overlapping area by hiding it as shown here:
flounder.com
msdn

I solved a similar issue where I was hosting a 3rd party WinForms control in my WPF application. I created a WPF control that renders the WinForms control in memory and then paints it to a bitmap. Then I use DrawImage in the OnRender method to draw the rendered content. Finally I routed mouse events from my control to the hosted control. In the case of a web browser you would also have to route keyboard events.
My case was fairly easy - a chart with some simple mouse interaction. A web browser control may have other issues that I didn't take into consideration. Anyway I hope that helps.

I hit this issue as well. In my case I was dragging images from one panel into the WebBrowser, but of course as soon as my image moved into the browser it was hidden.
Currently working on the following solution:
When the Image drag starts, create a Bitmap of the WebBrowser using "RenderTargetBitmap"
Add your Bitmap to the canvas, using the same width/location as the webbrowser
webControl.Visibility = Visibility.Hidden.
When the drag is released, remove your bitmap and set webControl.Visibility = Visible.
This solution is very specific to my situation, but maybe it will give you some ideas.

I managed to solve this by using this structure, check out the properties configuration in each element:
<Canvas ClipToBounds="False">
<Popup AllowsTransparency="True" ClipToBounds="False" IsOpen="True">
<Expander>
<Grid x:Name="YourContent"/>
</Expander>
<Popup>
</Canvas>
You just have to manage the Expander to show or hide your content, I'm using it for a menu bar, I think that the expander is optional depending on the case.
Check out this picture with the result, you can even show your controls on top of the WebBrowser and even outside the main window:

Related

Elysium style destroyed when using WindowsFormsHost

I'm using Elysium in my wpf application to get a metro styled interface. However the style is not preserved when I try to use Windows forms control.
Example:
<Grid>
<RichTextBox />
</Grid>
Gives a perfect result (with the thin white border around the wpf control)
However:
xmlns:WinForms="clr-namespace:System.Windows.Forms;assembly=System.Windows.Forms"
.
.
<Grid>
<WindowsFormsHost Name="wfh">
<WinForms:RichTextBox />
</WindowsFormsHost>
</Grid>
Gives me a different look with the legacy windows form type of border.
I want the thin white border around my WindowsFormElement if possible. I'm out of ideas at the moment.

Having difficulty using Z-Index in WPF

I've followed some examples trying to layer a rectangle over the WebBrowser object:
Here is the MSDN example link. (I got it to work)
Layers issue using Z-Index
Here is the code I'm trying to get to work:
<Grid>
<Canvas Margin="2,4,0,-450" >
<Rectangle Height="452" Canvas.ZIndex="1000" Name="rectangle1" Stroke="Black" Width="524" Opacity=".5" Fill="#8CBABABA" Canvas.Top="-7" Canvas.Left="-3" />
<WebBrowser Name="mapBrowser" Canvas.ZIndex="999" Margin="5,5,5,5" Height="452" Width="516" Canvas.Top="-11" />
</Canvas>
</Grid>
I'm trying to make the WebBrowser appear grayed out by making the rectangle appear over top of it. I'll also disable it.
Can anybody point to what I'm doing wrong?
I solved this issue by creating a .png image which I placed in the same space as the webbrowser. It looks like a grayed-out version of what first appears in the webbrowser. Then I conditionally hid the webbrowser which makes the image visible. This is the only way I've found to make it work using .Net 4.0.

wpf controls traveling around the grid/stack panel and not staying put

I am building a user control in WPF and put a few buttons in a stackpanel laying inside a grid. Problem is that when I build the app and run it, the buttons "sail around" and don't stay where I put them in the designer window. Is there any attribute I'm missing(or some sort of container?)?
Thanks.
Try setting the alignment properties of your grid:
<Grid HorizontalAlignment="Left" VerticalAlignment="Top">
...
</Grid>

SurfaceScrollViewer: getting touch on nested children

I have the following piece of code, which is part of a WPF 4 UserControl:
<Popup x:Name="CantoPopup" IsOpen="False" PlacementRectangle="50,-100,500,120"
AllowsTransparency="True" PopupAnimation="Fade"
StaysOpen="True" Width="500" Height="120">
<Border BorderBrush="#FF120403" BorderThickness="1" CornerRadius="10" Background="#FF9350">
<s:SurfaceScrollViewer x:Name="IndexScroller" Width="500" Height="120" Margin="10" VerticalScrollBarVisibility="Disabled" HorizontalScrollBarVisibility="Visible">
<DockPanel x:Name="InnerIndexPanel" />
</s:SurfaceScrollViewer>
</Border>
</Popup>
The DockPanel is then populated in the code-behind with a collection of TextBlocks. Basically, I am trying to build a scrollable horizontal list of touchable items.
Now, I would like to detect which textblock was touched by the user. However, neither adding a TouchDown event handler to the TextBlocks nor using TouchExtensions to handle tap gestures worked. Can someone please point me in the right direction?
Under the covers, Popup creates another hwnd to render its content into. This is different from all other WPF controls. You need to register this hwnd with the Surface SDK so it will start sending touch events to it. Use this to do that: http://msdn.microsoft.com/en-us/library/microsoft.surface.presentation.input.touchextensions.enablesurfaceinput.aspx
I found out that the point is that the Popup component has some peculiarities :) In this case, it seems that it did not detect neither TouchDown events nor PreviewTouchDown ones. Therefore, I resorted to creating a UserControl made of a Canvas containing the code above and then making such control visible on top of the rest whenever I needed the popup to open. I do not know whether this is the best solution, but now it reacts as expected.

WP7 Silverlight -- tapping image in a stackpanel scrollview to show that same picture in another grid

I am probably the absolute worst "coder" trying to create a Windows Phone 7 app, but I am in dire need of help, and some of you may even consider it to be laughably easy (which it probably is).
My problem: How on earth do I code the tapping of a picture from one grid to display as a bigger image on another grid?
And I'll elaborate:
I have an app page (in landscape mode only), with two grids splitting the screen.
The first grid (smallgrid) contains a Scrollviewer (small) with a Stackpanel (smallimages) of images reduced to 1/10 of their size within it, essentially showing thumbnails of images.
The second grid (contentgrid) is designed where once you tap on a thumbnail image from smallgrid that image will be shown in contentgrid
By default, balloon0 is displayed in the contentgrid and will change when a person taps on one of the smaller images.
I'll try to provide some mock code for this:
<grid x:name="smallgrid">
<scrollviewer x:name="small">
<stackpanel x:name="smallimages">
<image="balloon0.jpg"><image>
<image="balloon1.jpg"><image>
<image="balloon2.jpg"><image>
<image="balloon3.jpg"><image>
</stackpanel>
</scrollviewer>
</grid>
<grid x:name="contentgrid">
<image source="balloon0.jpg"><image>
</grid>
The code behind is where I need help. I am thinking I either use a button that once clicked, that image then replaces the image in contentgrid but I have no idea how to do that.
Or I can use a gesturelistener that when an image is tapped, it will replace the image in contentgrid... but I also don't know how to do that.
Any insight is helpful. Thank you for any help, as I am not a C# coder, let alone know the language or WP7 silverlight too well.
Be sure to add the Silverlight Toolkit assembly reference to your phoneapplicationpage element (and as a reference to the project):
xmlns:toolkit="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone.Controls.Toolkit"
You can use the GestureListener from the Silverlight Toolkit in your XAML like this (also be sure to add the name property to your large image):
<grid x:name="smallgrid">
<scrollviewer x:name="small">
<stackpanel x:name="smallimages">
<image="balloon0.jpg">
<toolkit:GestureService.GestureListener>
<toolkit:GestureListener Tap="smallImage_Tap" />
</toolkit:GestureService.GestureListener>
<image>
<image="balloon1.jpg">
<toolkit:GestureService.GestureListener>
<toolkit:GestureListener Tap="smallImage_Tap" />
</toolkit:GestureService.GestureListener>
<image>
<image="balloon2.jpg">
<toolkit:GestureService.GestureListener>
<toolkit:GestureListener Tap="smallImage_Tap" />
</toolkit:GestureService.GestureListener>
<image>
<image="balloon3.jpg">
<toolkit:GestureService.GestureListener>
<toolkit:GestureListener Tap="smallImage_Tap" />
</toolkit:GestureService.GestureListener>
<image>
</stackpanel>
</scrollviewer>
</grid>
<grid x:name="contentgrid">
<image x:Name="BigImage" source="balloon0.jpg"><image>
</grid>
Then in your code-behind you can handle the event like this:
private void smallImage_Tap(object sender, GestureEventArgs e)
{
BigImage.Source = (sender as Image).Source;
}
If you look into the toolkit source code, then it appears that GestureListener.Tap event is generated whenever XNA TouchPanel detects Tap gesture. Intuitively I would expect that this happens whenever MouseLeftButtonUp event is generated. Ok, not always, but in the described type of interaction it is basically "always".
Hence I feel both these levels (XNA and Toolkit classes) as unnecessary overhead - at least for something as simple as the tap event. (Other negative consequences: App size increases as you have to include the toolkit, slower launching as more assemblies have to be loaded.)
Having said that, I would start by simply listening to MouseLeftButtonUp event as for example
<Image Source="123.jpg" MouseLeftButtonUp="smallImage_Tap" ImageOpened="..." ImageFailed="..."/>
I included also ImageOpened/Failed events. You can optionally use them to fine tune your app. They could solve problems such as too frequent tap events or image load failures.

Resources