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();
Related
So i'am working with tabControl in windows forms application and i want to make the tabs get full width regardless whether the application window is maximized or not.
When the window isn't maximized everything appears great:
But when the window gets maximized the tabs doesn't get the full width:
Is there any known way to fix this problem?
Thanks in advance
You can achieve this in some way by modifying the ItemSize property as described bellow, else you'd have to draw the tab page selectors yourself.
public Form1()
{
InitializeComponent();
tabControl1.SizeMode = TabSizeMode.Fixed;
tabControl1.ItemSize = new Size((tabControl1.Width / tabControl1.TabPages.Count) - 1, tabControl1.ItemSize.Height);
}
//Hook to form or parent container Resize event, either Resize or ResizeEnd.
private void Form1_ResizeEnd(object sender, EventArgs e)
{
tabControl1.ItemSize = new Size((tabControl1.Width / tabControl1.TabPages.Count) - 1, tabControl1.ItemSize.Height);
}
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'm trying to create an overlay in wpf (with darkening background), similar to the ones you can find on the web to popup images.
I would like it to be reusable in more than 1 part of the application, with diffent types of content.
this is the temporary code of the constructor of the adorner class (just to try)
private readonly Grid _grid = new Grid();
public DarkOverlayAdorner(UIElement adornedElement, Object content) :
base(adornedElement)
{
_grid.Background = new SolidColorBrush(Color.FromArgb(99, 0, 0, 0));
IsHitTestVisible = true;
var visual = content as UIElement;
if (visual != null)
_grid.Children.Add(visual);
}
In addition in the class (of course), I have the ovverrides of MeasureOverride and ArrangeOverride to give the adorner the correct size of the adorned element, GetVisualChild, and VisualChildCount...
The problem here is that the adorner is correctly shown, but no events or behaviour are applied on the adorned element. For example:
AdornerLayer layer = AdornerLayer.GetAdornerLayer(textBoxProva);
layer.Add(new DarkOverlayAdorner(textBoxProva, new Button{Content = "prova"}));
The button here is shown, but I can-t click the button and no effects on button mouseover are applied.
I still can't figure out the problem.
Ok, I've lost a lot of time trying to figure out what was the problem.
In the end I found the solution:
If you want the element added to react to events, I think that the element must be bound to the visual tree of the adorner.
The way to do it is to use a VisualCollection, intitialized to the adorner itself:
VisualCollection visualChildren;
FrameworkElement #object;
public DarkOverlayAdorner(UIElement adornedElement) :
base(adornedElement)
{
visualChildren = new VisualCollection(this);
#object = new Button {Content = "prova"};
visualChildren.Add(#object);
}
protected override Visual GetVisualChild(int index)
{
return visualChildren[index];
}
This way the events are correctly routed.
You might want to take a look at the ChildWindow control in the Extended WPF Toolkit. It is a control that pops up a Window with a modal background effect, and you can specify the content to put inside the Window.
I noticed that when overriding the System.Windows.Window OnRender method fails to draw to the screen. I'm sure there's a good reason for this but was unable to find the explanation.
The following code demonstrates this:
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
namespace WpfApplication1
{
public partial class Window1 : Window
{
Pen pen = new Pen();
public Window1()
{
InitializeComponent();
pen.Brush = Brushes.Black;
}
protected override void OnRender(DrawingContext dc)
{
base.OnRender(dc);
dc.DrawRectangle(Brushes.Black, pen, new Rect(0, 0, 600, 400));
dc.DrawEllipse(Brushes.Green, pen, new Point(300, 300), 50, 50);
}
}
}
replacing the drawing logic in a FrameworkElement (then setting the element as the content of a window) work fine.
thanks,
Danny
The answer is given by Chales Petzold here.
His answer is 'don't know why', however a comment correctly suggests that setting the window's Background to transparent fixes the bug.
Actually, the Window paints itself, which among others is a rectangle for the background. Whatever is added in the OnRender is behind the background. Make the Background transparent and one can see what is behind it.
At least that is what I found out when using Button and OnRender. If I draw only within the button, nothing can be seen, because the button is drawn over it. But if the drawing extends beyond the button boundaries, anything outside can be seen.
Here an empty button is drawn over a yellow background. In the OnRender, I draw 2 black lines forming a cross. But only the parts of the line outside the button can be seen.
Very strange behavior of OnRender, indeed !
just as a check, does the snippet work with the dc.Draw... lines removed (i.e. is it the act of overriding or the additional draw commands that cause the issue)?
I found a link that suggests that simply re-ordering the calls may solve the issue (i.e. doing the dc.Draw... calls before calling base.OnRender(dc)).
http://www.codeproject.com/Messages/3356653/Override-OnRender-class-inherits-frameworkelement.aspx
I think, that Grid generate this problem. Becouse by default Window contains Grid element
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;