Creating a WPF Frame Inside of a Window with AllowsTransparency Set to True





0/5 (0 vote)
How to create a WPF frame inside of a window with AllowsTransparency set to true
As much as I love Microsoft, it's a wonder that they don't update some of their developer controls/tools to use the technology that they are writing everything else in.
Thankfully, the developer community is on top of it.
WPF: Using a Frame element in a custom shaped window
Here's my modified code to enable this functionality as a reusable class:
using System; using System.Runtime.InteropServices; using System.Windows; using System.Windows.Controls; using System.Windows.Interop; using System.Windows.Media; using DrawingPoint = System.Drawing.Point; namespace VisibleFrame { /// <summary> /// Original code from: http://davidfulop.spaces.live.com/blog/cns!BC8EF43294ECB87!427.entry /// Converted window into reusable class: http://www.aronweiler.com /// </summary> internal class VisibleFrame { //The following two windows-calls will be necessary to draw the Frame onto the main window [DllImport("user32.dll")] internal static extern bool ClientToScreen(IntPtr hWnd, ref DrawingPoint point); [DllImport("user32.dll")] internal static extern bool MoveWindow (IntPtr hWnd, int x, int y, int width, int height, bool repaint); //The invisible window in which the Frame will be hosted Window w = new Window { WindowStyle = WindowStyle.None, ShowInTaskbar = false, ResizeMode = ResizeMode.NoResize }; Window targetWindow; Border targetControl; Frame frame; internal VisibleFrame (Window targetWindow, Border targetControl, string initialLocation) { this.targetWindow = targetWindow; this.targetControl = targetControl; targetWindow.Loaded += WindowLoad; frame = new Frame(); if(!string.IsNullOrEmpty(initialLocation)) { Navigate(initialLocation); } } internal void WindowLoad(object sender, RoutedEventArgs e) { //It is crucial to set the Owner, //because if we don't the inner window won't be repainted after a task-change w.Owner = targetWindow; //Creating the Frame and registering to the repaint-related events w.Content = frame; targetControl.SizeChanged += delegate { RepaintFrame(); }; targetWindow.LocationChanged += delegate { RepaintFrame(); }; //Showing the Window that contains our Frame w.Show(); //Initial call to the RepaintFrame //lets us place the Frame to the correct location RepaintFrame(); } private void RepaintFrame() { //We get a Win32 representation of the main window HwndSource hostWindow = HwndSource.FromVisual(targetWindow) as HwndSource; //We get a visual manager for point transformations CompositionTarget ct = hostWindow.CompositionTarget; //We need to translate the coordinates of the //embedded window to the Border element (browserhost) //Note, that the ClientToScreen function don't understand //WPF's Point struct, that's why we have to convert it Point loc = ct.TransformToDevice.Transform (targetControl.TranslatePoint(new Point(), targetWindow)); DrawingPoint locD = new DrawingPoint((int)loc.X, (int)loc.Y); ClientToScreen(hostWindow.Handle, ref locD); //We have to calculate the size - basically the //bottom right coordinate of the Border element Point size = ct.TransformToDevice.Transform(new Point (targetControl.ActualWidth, targetControl.ActualHeight)); //Last thing to do: call a Win32 function to paint //the Frame to the correct location MoveWindow((HwndSource.FromVisual(w) as HwndSource).Handle, locD.X, locD.Y, (int)size.X, (int)size.Y, true); } internal void Navigate(string location) { frame.Navigate(new Uri(location)); } } }