I have an existing WinForm app which is too much to port to WPF right now.
However, I need a window with some tricky transparency behavior that I cannot achieve in a WinForm (yes, tried Layerd Windows but it's a no-go).
WPF allows the transparency behavior I need beautifully and simply.
I googled of course, but can only find hints how to create a WPF control within a WinForm but that is NOT what I need. I need a separate WPF window that is completely independant of my other Forms.
The WPF window will be a rather simple full-screen and borderless overlay window where I will do some simple drawings, each with different transparencies.
How can I create a WPF window within a WinForm application?
Add the necessary WPF references to your project, create a WPF Window-instance, call EnableModelessKeyboardInterop and show the window.
The call to EnableModelessKeyboardInterop makes sure, that your WPF window will get keyboard inputs from your Windows Forms app.
Take care, if you open a new Window from within your WPF window, the keyboard input will not be routed to this new window. You have to call also for these newly created windows EnableModelessKeyboardInterop.
Fore your other requirements, use Window.Topmost and Window.AllowsTransparency. Don't forget to set the WindowStyle to None, otherwise, transparency is not supported.
Update
The following references should be added to use WPF in your windows forms application:
PresentationCore
PresentationFramework
System.Xaml
WindowsBase
WindowsFormsIntegration
Here's the (tested) solution. This code can be used in both a WinForm or a WPF app.
No XAML needed at all.
#region WPF
// include following references:
// PresentationCore
// PresentationFramework
// WindowsBase
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Shapes;
#endregion
public class WPFWindow : Window
{
private Canvas canvas = new Canvas();
public WPFWindow()
{
this.AllowsTransparency = true;
this.WindowStyle = WindowStyle.None;
this.Background = Brushes.Black;
this.Topmost = true;
this.Width = 400;
this.Height = 300;
canvas.Width = this.Width;
canvas.Height = this.Height;
canvas.Background = Brushes.Black;
this.Content = canvas;
}
}
The window background is fully transparent.
You can draw on the canvas and each element can have it's own transparency (which you can determine by setting the alpha channel of the Brush used to draw it).
Simply invoke the window with something like
WPFWindow w = new WPFWindow();
w.Show();
Related
I have a wpf usercontrol that contains an activex control housed in a windowsformhost.
I'm using an MVVM pattern that says
ViewModel1 is mapped to a Pure WPF View and
ViewModel2 is mapped to wpf content and the above usercontrol
If ViewModel2 is "Hidden" and then becomes Visible then the Activex control inside it doesn't show (Specifically I'm talking about the VLC activex control).
I've tested in a non MVVM pattern with a button and the usercontrol. The usercontrol is hidden until you press the button and the same thing happens but if I create a method in the usercontrol to re attach the activex control to the windowsformhost then it reappears. If I call this method from a viewmodel then it still remains blank. Does anyone know how I can get this to show again?
EDIT - I've just discovered it's because I have transparency on in my wpf application. It seems it's not possable to do what I want with windowsformshost and transparency enabled.
As there are no obvious answers I'll share my experience. When transparency is turned on in the wpf window then the windows form host doesn't refresh when changing from Hidden to Visable. I have found no way to make this work unless it is hosted in a new window with "Allowstransparency=false".
How are you setting up your active x control? The following Typically works for me in WPF if you are just needing it to attach to a grid. No user control required.:
//Active X Control initializer
private Ax addAxObject<Ax>(Grid container)
where Ax : System.Windows.Forms.Control, new()
{
Ax ax = new Ax();
var hoster = new System.Windows.Forms.Integration.WindowsFormsHost();
hoster.Child = (System.Windows.Forms.Control)ax;
container.Children.Add(hoster);
return ax;
}
private MyActiveXControl myActiveXControl;
public Grid InitializeActiveX(Grid grid)
{
myActiveXControl = addAxObject<myActiveXControl>(grid);
return grid;
}
Then all you do is is add it to your grid in your main window like so:
public MainWindow()
{
InitializeComponent();
//initialize Active X control
gridMain = InitializeActiveX(gridMain);
}
It shows up just fine for me. (Obviously not in the designer since it is programatically created)
I created an application using Microsoft ribbon for WPF. I used RibbonWindow instead of simple Window to place QuickAccessToolbar to window header.
The problem is that normal Window becomes fullscreen when i set
WindowStyle="None"
WindowState="Maximized"
But RibbonWindow becomes bigger and its bottom part hides behind taskbar.
I suppose that the only difference between window and RibbonWindows is the controlTemplate.
But i dont actually understand how can i via template place the window above the taskbar.
Any ideas how to show my RibbonWindow above taskbar just as normal window does?
Link to the VS2010 project (10KiB) (Microsoft Ribbon For WPF isn't included)
RibbonWindow uses custom WindowChrome. That is the reason of incorrect behavior. Try this code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using Microsoft.Windows.Shell;
namespace Utils
{
public static class WindowHelper
{
public static void Fullscreen(Window p_oWindow)
{
p_oWindow.WindowStyle = WindowStyle.None;
p_oWindow.Topmost = true;
p_oWindow.WindowState = WindowState.Maximized;
WindowChrome.SetWindowChrome(p_oWindow, null);
}
public static void UndoFullscreen(Window p_oWindow)
{
p_oWindow.WindowStyle = WindowStyle.SingleBorderWindow;
p_oWindow.Topmost = false;
p_oWindow.WindowState = WindowState.Normal;
WindowChrome.SetWindowChrome(p_oWindow, GetChrome());
}
public static WindowChrome GetChrome()
{
WindowChrome oCustomChrome = new WindowChrome();
oCustomChrome.CornerRadius = new System.Windows.CornerRadius(0, 0, 0, 0);
oCustomChrome.CaptionHeight = 0;
oCustomChrome.ResizeBorderThickness = new System.Windows.Thickness(2, 2, 2, 2);
return oCustomChrome;
}
}
}
The problem is the WindowStyle. This happens in all WPF windows when you remove the chrome. (They really optimized this feature for full-screen kiosk apps).
In order to handle maximizing your window to the correct size, you're going to need to handle it yourself. When you maximize button is clicked, you will need to get the working area of the current monitor you're on. There isn't a WPF way of doing this, but you can use the WinForms Screen class.
Your maximize method would look like so:
// you must save the restore bounds, since we never set Window.WindowState,
// so the RestoreBounds property will get set to the maximized bounds
private System.Drawing.Rectangle restoreBounds;
private void DoMaximize(object sender, EventArgs e)
{
var bounds = new System.Drawing.Rectangle((int)Left, (int)Top,
(int)ActualWidth, (int)ActualHeight));
var screen = System.Windows.Forms.Screen.FromRectangle(bounds);
var area = screen.WorkingArea;
restoreBounds = bounds;
Left = area.X;
Top = area.Y;
Width = area.Width;
Height = area.Height;
}
I have an excel AddIn which exposes IWin32Window as it's main UI.
I want to show a WPF window that uses this as it's parent.
How do I go about doing that ?
You can use WindowInteropHelper to parent the WPF window appropriately:
var helper = new WindowInteropHelper(theWpfWindow);
helper.Owner = win32Window.Handle;
theWpfWindow.Show(); // This is now parented appropriately
I think you need to use a WindowInteropHelper, like shown here: IWin32Window Owner For WPF Window
I'm using WPF in WinForms with ElementHost. When the form loads, there is a flash of black background where the ElementHost is about to load. This looks kind of bad. Any suggestions on how to get rid of this?
Hide the element (Visibility = Hidden) until the WinForms control is fully loaded...
I know this has already been answered and the question is old but none of the presented answers worked for myself and after a long time of troubleshooting the issue. I finally found an easier answer.
If you build a class extending from Element Host and in the initial constructor. You can set a Load Event for the Host Container. The Host Container is the panel that the Element Hosts Child is being displayed on top of. From there, just set the Host Containers background color to being of the Element Hosts Parents background color.
Like this
using System.Windows;
using System.Windows.Forms;
using System.Windows.Media;
public class MyElementHost : ElementHost
{
public MyElementHost()
{
this.HostContainer.Loaded += new RoutedEventHandler(HostPanelLoad);
}
public void HostPanelLoad(object sender, RoutedEventArgs e)
{
System.Drawing.Color parentColor = this.Parent.BackColor;
this.HostContainer.Background = new SolidColorBrush(Color.FromArgb(parentColor.A, parentColor.R, parentColor.G, parentColor.B));
}
}
you need first show control with empty bounds first time to avoid black flickering
if (!_control.Created && _control.BackColor != Color.Transparent)
{
_control.Bounds = Rectangle.Empty;
_control.Show();
}
// set control bounds and show it
Rectangle bounds = GetBounds(context, rect);
if (_control.Bounds != bounds)
_control.Bounds = bounds;
if (!_control.Visible)
_control.Show();
How can I go about hosting flash content inside a WPF form and still use transparency/alpha on my WPF window? Hosting a WinForms flash controls does not allow this.
Unless the control you use to display the Flash content is built in WPF, you will run in to these "airspace" issues. Every display technology from Win32 to WinForms used HWNDs "under the hood", but WPF uses DirectX. The Window Manager in Windows however, still only understands HWNDs, so WPF apps have one top-level HWND-based window, and everything under that is done in DirectX (actually things like context menus and tooltips also have top-level HWNDs as well). Adam Nathan has a very good description of WPF interop in this article.
Although I haven't done it, you can probably use the WebBrowser control found in WPF 3.5 sp1 to wrap your Flash content within WPF. I'm not sure how the transparency will be affected though.
Can you use Expression to convert the flash content to XAML? I believe that there are tools in there or off to the side that do this.
Just have been struggling with same problem of how to upload & Make WPF transparent with ability of displaying Flash, because if you enable on your MainWindow "Allow transparency" Flash will not show once the application will run.
1) I used WebBrowser Control to play Flash(.swf) files. They are on my PC, however it can play from internet or wherever you have hosted them. Don't forget to name your WebBrowser Control to get to it in C#.
private void Window_Loaded(object sender, RoutedEventArgs e)
{
MyHelper.ExtendFrame(this, new Thickness(-1));
this.MyBrowser.Navigate(#"C:\Happy\Download\flash\PlayWithMEGame.swf");
}
2) Now for transparency. I have set in WPF 'false' to "Allow Transparency" and set "Window Style" to 'None'. After that I have used information from HERE and HERE and created a following code that produced desired effect of allowing transparency on MainWindow and running Flash at same time, here is my code:
public class MyHelper
{
public static bool ExtendFrame(Window window, Thickness margin)
{
IntPtr hwnd = new WindowInteropHelper(window).Handle;
window.Background = Brushes.Transparent;
HwndSource.FromHwnd(hwnd).CompositionTarget.BackgroundColor = Colors.Transparent;
MARGINS margins = new MARGINS(margin);
DwmExtendFrameIntoClientArea(hwnd, ref margins);
return true;
}
[DllImport("dwmapi.dll", PreserveSig = false)]
static extern void DwmExtendFrameIntoClientArea(IntPtr hwnd, ref MARGINS margins);
}
struct MARGINS
{
public MARGINS(Thickness t)
{
Left = (int)t.Left;
Right = (int)t.Right;
Top = (int)t.Top;
Bottom = (int)t.Bottom;
}
public int Left;
public int Right;
public int Top;
public int Bottom;
}
And called it from Window_Loaded() + you need 'below' line for 'DllImport' to work.
using System.Runtime.InteropServices;
using System.Windows.Interop;