Click here to Skip to main content
15,896,063 members
Articles / Desktop Programming / WPF

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

Rate me:
Please Sign up or sign in to vote.
0.00/5 (No votes)
19 May 2011CPOL 12.6K   1  
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));
        }
    }
}

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Architect
United States United States
Check out my technical blog here: The Fyslexic Duck. You can find most of what I've put on CodeProject there, plus some additional technical articles.

Comments and Discussions

 
-- There are no messages in this forum --