Rotate WPF control or change screen orientation - wpf

I have wpf project with one Window (MainWindow). Depending upon the config file it shows one of two UserControl's as Content. It may be a horizontal (1920x1080) control or vertical (1080x1920) control. It's fine with horizontal screen, but when vertical is loaded I would like to do:
1) rotate window/control by 270 degrees
2) change primary screen orientation
I would prefer to just rotate application and don't interact with windows API. I can't change orientation manually, because I have only remote access to this computer.

You can not rotate the Window object itself, as it is positioned by the window management system built in Windows. You can, however, transform (and thus rotate) any FrameworkElement inside the window. This includes, but is not limited to, the Grid, the Button and the TextBox elements.
All you need to do is edit the LayoutTransform property on the element you want to rotate, which is most likely the root element in your window. Set the rotation to 270/-90 degrees and WPF will automatically rotate your UI.
Because you are using the LayoutTransform property, the layout system will also scale you UI correctly. The RenderTransform property causes the control to first be rendered, then be rotated.

YES WE CAN CHANGE SCCREEN ORIENTATION USING
DEVMODE & using System.Runtime.InteropServices;
its bit late to reply but I am replaying for the new ones , if someone com across this article for change screen rotation in C# or VB .
Please use the link given below to get help Mr. Hannes Completely write an article to change screen rotation and luckily its working fine for me (Windows 11) as now of..
https://www.codeguru.com/dotnet/creating-a-screen-rotator-in-net/

Related

WPF Window HorizontalAlignent Stretch

I have a simple task that I want to accomplish: Have a WPF window launch with a Horizontal Alignment that is stretched to the total width of the current screen. I want to achieve a kind of custom Overlay MessageBox (I dont want to use third party controls such as MahApps), I am not using any third party references for this.
Please see what I have achieved so far (Not sure if the image will show, the link is http://imgur.com/e27DyNJ):
I have tried setting the width with a Controller object that I wrote which works, that basically sets the Width, Height, Left and Top to the width of the primary monitor. Downside is the window then pops up on the primary screen, not on the screen that is currently in use.
As far as I know, WPF doesn't have any multi-screen functions. You could PInvoke some native Multiple Display Monitor Functions, wrap them in a managed class and utilize them in that regard, though.
As a workaround, I have done the following:
var screen = System.Windows.Forms.Screen.FromRectangle(new System.Drawing.Rectangle((int)window.Left, (int)window.Top, (int)window.Width, (int)window.Height));
window.Width = screen.WorkingArea.Width;
window.Left = screen.WorkingArea.Left;
where window is the instance of my window I want to resize.
This works with the current screen the window was opened on.

Is this how I make custom controls both transparent and flicker-free in Windows? Or do I have one of these steps wrong?

I could begin by asking the question outright or by citing my sources (this, this, this, and this) descriptively, but I'll walk you ll through what I'm trying to do instead.
Let's start with a main window. It has its own window class whose hbrBackground is set to COLOR_BTNFACE + 1. Now let's do
EnableThemeDialogTexture(hwnd, ETDT_ENABLE | ETDT_USETABTEXTURE)
so the tab control we're about to add will be drawn with visual styles. (Try Windows XP with the standard Luna theme for best results.) Now let's add a tab control and two tabs.
On the first tab, we create an instance (let's call it container) of a new window class. This window class is going to hold various controls. I could set hbrBackground to COLOR_BTNFACE + 1, but then it will draw over the tab background. So I want this new child window to be transparent. So what I do is
set the class hbrBackground to GetStockObject(HOLLOW_BRUSH)
set container's extended style to WS_EX_TRANSPARENT
set the class WM_ERASEBKGND handler to do SetBkMode((HDC) wParam, TRANSPARENT); return 0; to set the device context and have Windows draw the transparent background.
So far so good, right? I'm not sure if I'm really doing all this correctly, and I'd like this to also be flicker-free, which doesn't seem to happen: when I resize the window (at least in wine) I get either flicker or garbage drawn (even in child controls, somehow!). Windows XP in a VM just shows flicker. I tried tweaking some settings but to no avail.
But wait, now I want to have another control, one that just draws some bitmap data. On the next tab, create another container, then have a third window class area as a child of that. area only draws in the upper-left 100x100 area and has scrollbars; the rest of the window area should be transparent.
Right now, what I have for area is:
the window class hbrBackground set to NULL and styles CS_HREDRAW and CS_VREDRAW set
the extended window style being 0
the WM_ERASEBKGND simply doing return 1;
the WM_PAINT filling the entire update rect with COLOR_BTNFACE + 1 before drawing, and rendering all of it
This is flicker-free, but obviously not transparent. NOW I'm really not sure what to do, because I want the area to be transparent in such a way that it shows the tab control background. Again, I tried tweaking settings to bring them closer to what I tried above with container, but I got either flicker or invalidation leftovers when I tried.
So how do I get both of these custom control types (the container and the drawing area) to be both flicker-free and transparent?
I presently must target Windows XP at a minimum, though if the solution would be easier with Vista+ only I'd be happy to keep that solution on the side in case I ever drop XP support (unfortunately Stack Overflow doesn't let me hand out silver medals...).
Thanks!
To paint your window in a manner that is "flicker free", you will need to paint your window to a bitmap, then copy the bitmap to the destination device context. On Windows XP, you will need to create a bitmap, adjust the origin of the drawing DC and then paint your window. On Vista and later you can use BeginBufferedPaint and its associated routines to do the buffering for you.
Once you have buffered painting working, you can then use WM_PRINTCLIENT to paint your window's parent window into the your drawing DC before you do any actual drawing. Unfortunately, not all windows will support WM_PRINTCLIENT.
You could consider using DrawThemeParentBackground, rather than WM_PRINTCLIENT directly.
Combining these two methods together will leave you with transparent flicker-free drawing.

How to easily change the layout of the screen from Portrait to Landscape and vice versa in WPF

Let's suppose we have the designed the layout of some WPF application to be used on standard Full HD screen 1920x1080. Then we need to rotate the screen and install it in a box that is mounted on kiosk PC but in Portrait orientation.
I need to find a way on how to rotate the screen easily or at least in some more elegant way.
I tried to use use RenderTransform and RotateTransform applied to the contents of the window but this rotates the image and of course not the layout.
The controls remain of the same width and height.
Is there a way to do it automatically or should I take each control and change it properties one by one ?
The problem is present for TextBlocks and TextBoxes. They are intended to be used horizontally. You can rotate it but the layout is calculated based to it's horizontal width.
BTW. Rotation of the entire window is not allowed. It throws an exception.
It looks like that I have found the solution myself. If we choose the Layout transform instead of RenderTransform then the visual system does the arrangement and measurement of the layout automatically before the rendering.
The WPF framework does the job in this order
LayoutTransform
Measure
Arrange
RenderTransform
Render
This is best described here LAYOUTTRANSFORM VS. RENDERTRANSFORM - WHAT'S THE DIFFERENCE?

Winforms semi-transparent PNG over semi-transparent PNG

I think I must be missing something obvious, but I'm unable to find this after several hours of searching. Is there no way to use a PictureBox or other control to contain an image with partial transparent/alpha-blended pixels, and place that over another image and have the blending be based on the image under it?
For example, this produces the results I want:
Place a panel on a form.
Add an OnPaint handler.
In the OnPaint handler draw 1 PNG, then draw another PNG over it, using Graphics.DrawImage for both.
This does not:
Place a PictureBox on a form and set it to a PNG.
Place another PictureBox on the form and set it to a PNG.
Place the 2nd picture box over the first.
...even if the 2nd picture box is just empty and has a background color of Transparent, it still covers the picture below it.
I've read this stems from all winform controls being windows, so by nature they aren't transparent.
...but even the 15 year old platform I'm migrating from, Borland's VCL, had several windowless controls, so it's hard to imaging winforms doesn't at least have some easy solution?
My first example above is one answer, true, but that adds a lot of work when you can only use one big panel and draw all of your "controls" inside of it. Much nicer if you can have separate controls with separate mouse events/etc. Even if not an image control, and a control I have to draw myself, that would be fine, as long as I can just put one image in each control. In VCL they called this a "paint box", just a rectangle area you could place on a form and draw whatever you want on it. Has it's own mouse events, Bounds, etc. If you don't draw anything in it, it is like it's not even there (100% transparent) other than the fact it still gets mouse events, so can be used as a "hot spot" or "target" as well.
The PictureBox control supports transparency well, just set its BackColor property to Transparent. Which will make the pixels of its Parent visible as the background.
The rub is that the designer won't let you make the 2nd picture box a child of the 1st one. All you need is a wee bit of code in the constructor to re-parent it. And give it a new Location since that is relative from the parent. Like this:
public Form1() {
InitializeComponent();
pictureBox1.Controls.Add(pictureBox2);
pictureBox2.Location = new Point(0, 0);
pictureBox2.BackColor = Color.Transparent;
}
Don't hesitate to use OnPaint() btw.
Sorry, I just found this... once I decided to Google for "winforms transparent panel" instead of the searches I was doing before, the TransPictureBox example show seems to do exactly what I need:
Transparency Problem by Overlapped PictureBox's at C#
Looks like there are 2 parts to it:
Set WS_EX_TRANSPARENT for the window style
Override the "draw background" method (or optionally could probably make the control style Opaque).

WPF and Silverlight controls and layouts pan and zoom capabilities

I would like to understand the general requirements for WPF/Silverlight layout for making it possible to implement pan&zoom (drag and zoom) features. I don't mean pan&zoom for an image but for a total page (window) layout (or part of it) with some controls.
What features of the layout and what features of used custom controls make layout fixed and pan&zoom impossible?
General rule
With few exceptions, everything in WPF can be panned, zoomed, rotated, stretched, etc to your heart's content. This include single controls like Button, compound controls like ListBox, and containers like StackPanel.
The exceptions
Here are the exceptions:
If you are using Adorner and your AdornerDecorator is outside the panned/zoomed area, then the Adorners attached to your panned/zoomed area will pan but not zoom. The solution is to put an additional AdornerDecorator inside the panned/zoomed area.
If you use a Popup, it will display at the panned/zoomed location of its PlacementTarget but it will not itself be scaled. It will also not move as you pan the area containing its PlacementTarget (basically it sits in its own surface above the target control). To get around this, use a zero-size Canvas with high Z order instead when you want something to pop up within the zoom/pan area.
Any ContextMenu you define will be shown inside a popup, so the menu items will display normal size even when the area you clicked on is zoomed in or out. Because of the nature of a context menu, this is probably desirable behavior. If not, you can wrap the menu items in a ViewBox and tie the zoom to your main area's zoom.
Your ToolTips will display normal size even if the UI is panned or zoomed. Same solution as for ContextMenu.
If you used WinForms integration to integrated legacy WinForms controls and UI, they will not properly pan, zoom and clip in certain situations. There is an advanced technique for working around this, where you implement the WinForms control off-screen, then using BitBlt or similar copy the image into your window as an image, and forward mouse clicks and keystrokes to the offscreen window. This is a lot of work, though.
If you bypass WPF and directly use GDI+ or DirectX, or use Win32 hWnds to display content or UI, that content or UI will not be properly panned, zoomed or clipped to the window unless you do it yourself in your interface code.
Final notes
A good WPF UI always uses panels like Grid, DockPanel, etc to lay out controls in a flexible manner so they automatically adjust to container sizes, rather than using fixed sizes and positions. This is also true for the internal contents of your pan/zoom area as well, BUT there is an exception to this rule: the outermost element in your pan/zoom area must have a specified size. Otherwise what will define the area being panned/zoomed over?
The easy way to implement pan/zoom capabilities is to adjust the RenderTransform of the outermost control in your pan/zoom area. There are many different ways to implement controls for panning and zooming, for example you could use toolbar buttons and sliders, scroll bars, mouse wheel, spacebar+drag to pan, draggable areas of panned UI itself, or any combination of these. Whichever interface you choose, just have it update the RenderTransform appropriately from the code-behind and you're good to go.
If your chosen panning mechanism is scroll bars, you might want to use a ScrollViewer and only use the RenderTransform for the zoom.
Be sure you set clipping on the pan/zoom area. Otherwise if you zoom in or pan items off the side, they will still be visible outside the pan/zoom area.
Use a MultiScaleImage or Canvas area, and place everything you need to pan and zoom in it
<Canvas x:Name="panZoomPanel" Background="Transparent">
</Canvas>
In code use make a TranslateTransform and a ScaleTransform in a TransformGroup to pan and zoom
Check out other SO post or this example or this one
In general you can treat any composite set of UI elements the same as you would treat a single UIElement so the case of an image isn't really different than doing the same for an entire application. The best way to handle zooming based on user input (as opposed to automatic scaling that Viewbox does) is applying a ScaleTransform. This can be set on a high level parent element, like a Grid at the root of a Window layout. For panning you can combine in a TranslateTransform or in some cases use a ScrollViewer to handle moving the view of the content.
One really easy way of implementing zoom in XAML is to use a Silverlight ViewBox. This zooms the XAML not the pixels. You can specify the stretch to use and the ViewBox will scale based on this (Fill, None, Uniform etc). There are some great Viewbox blog posts on the web if you search for Silverlight+Viewbox on Google.
The panning is easily accomplished with a similar mechanism to drag and drop and there are also numerous how-to blog posts on this, available via Google. Just amounts to capturing MouseDown, MouseMove and MouseUp events.

Resources