Easier way to scale controls? - wpf

Recently I coded an extremely graphical interface in for hi-res displays(1900x1200). Of course my the requirements changed, and it needed to be redone in 1366x768. Rather than retool the app for a fixed resolution(lesson learned), i moved everything into its own ViewBox and recrafted my grid controls to handle this. The app looks great and scales to (nearly)any size without artifacts.
My question is, is there an easier way to accomplish full dynamic control scaling in WPF with putting each control in its own viewbox? ViewBox was the only control I could find to do this, but it can only contain one child element, which made this a VERY tedious process. Is there a better control that can contain child controls that scales?

Why not put a Grid or StackPanel inside the viewBox, and then fill them with the controls?
Something like this
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:WfpApplication1="clr-namespace:WfpApplication1"
Title="MainWindow" Height="350" Width="525">
<Viewbox>
<StackPanel>
<CheckBox Content="Hello World!"/>
<TextBlock Text="Hello world"/>
<Button Content="Hello world!"/>
</StackPanel>
</Viewbox>

Related

Why AdornerLayers are always the top most layers? Is there a way to change it?

Why is that the adorner layer is always rendered as the top most layer in an application (under AdornerDecorator - refer screenshot)?
Is there a way to change the layer/level on to which the adorners can be drawn?
In the following screenshot, AdornerLayer is added to AdornerDecorator and the Adorners (MyAdorners) are added to this AdornerLayer. But the AdornerLayer is retrieved like this,
AdornerLayer layer1 = AdornerLayer.GetAdornerLayer(button1);
layer1.Add(new MyAdorner(button1));
To answer my second question,
Is there a way to change the layer/level on to which the adorners can be drawn?
I guess I have found a solution. Just place an AdornerDecorator element around the level on to which the adorners needs to be rendered. Any control requiring an adorner layer would use this AdornerDecorator element to place its decorators.
Here I have moved the adorners to a different level using the following code snippet.
<Window x:Class="CustomAdornerLayer.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525" Loaded="Window_Loaded">
<Grid>
<StackPanel Background="Yellow" Width="Auto">
<Button>Button3</Button>
</StackPanel>
<AdornerDecorator>
<Grid>
<AdornerDecorator>
<Button x:Name="button1" Margin="70,73,265,158">Button1</Button>
</AdornerDecorator>
<AdornerDecorator>
<Button x:Name="button2" Margin="87,51,248,180">Button2</Button>
</AdornerDecorator>
</Grid>
</AdornerDecorator>
</Grid>
While the AdornerLayer is still queried in the same way,
AdornerLayer layer1 = AdornerLayer.GetAdornerLayer(button1);
layer1.Add(new MyAdorner(button1));
AdornerLayer layer2 = AdornerLayer.GetAdornerLayer(button2);
layer2.Add(new MyAdorner(button2));
Kindly correct me if I am wrong.
Adorner layer is provided by AdornerDecorator. When you ask for the layer for the given control wpf looks for the AdornerDecorator upper visual tree.
Why do you need to change this logic? Adorners system made intentionally this way for decorations to appear above the decorated element.
You can search for AdornerDecorator yourself with VisualTreeHelper

Is there a way to touch-enable scrolling in a WPF ScrollViewer?

I'm trying to create a form in a WPF application that will allow the user to use iPhone-like gestures to scroll through the available fields. So, I've put all my form controls inside a StackPanel inside a ScrollViewer, and the scrollbar shows up as expected when there are too many elements to be shown on the screen.
However, when I try to test this on my touch-enabled device, a panning gesture (placing a finger down on the surface and dragging it upward) does not move the viewable area down as I would expect.
When I simply put a number of elements inside a ListView, the touch gestures work just fine. Is there any way to enable the same kind of behavior in a ScrollViewer?
My window is structured like this:
<Window x:Class="TestTouchScrolling.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525" Loaded="Window_Loaded">
<Grid>
<ScrollViewer Name="viewer" VerticalScrollBarVisibility="Auto">
<StackPanel Name="panel">
<StackPanel Orientation="Horizontal">
<Label>Label 1:</Label>
<TextBox Name="TextBox1"></TextBox>
</StackPanel>
<StackPanel Orientation="Horizontal">
<Label>Label 2:</Label>
<TextBox Name="TextBox2"></TextBox>
</StackPanel>
<StackPanel Orientation="Horizontal">
<Label>Label 3:</Label>
<TextBox Name="TextBox3"></TextBox>
</StackPanel>
<!-- Lots more like these -->
</StackPanel>
</ScrollViewer>
</Grid>
You should use the attached properties:
ScrollViewer.PanningMode
ScrollViewer.PanningDeceleration
ScrollViewer.PanningRatio
The PanningMode defaults to None in the ScrollViewer default style, but setting it to another value will enable touch scrolling. I'm currently investigating using this feature in my app and am looking for a good deceleration and ratio value... I'll probably just have to test them out to find something that works well.
If you are using .NET 4.0, there is a cool thing recently released by Microsoft team!! They ported all those nice Surface controls to Win7. SurfaceScrollViewer is really cool like iphone one. Install this toolkit and start a SurfaceWin7Touch project from VS2010 project template
http://www.microsoft.com/en-us/download/details.aspx?id=26716

WPF Textbox & Borders - curious resizing behavior

The following XAML produces a window with strange behavior around the textbox:
<Window x:Class="WpfSandbox.CuriousExample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="CuriousExample" Height="300" Width="300">
<DockPanel Margin="15">
<TextBox BorderThickness="1" BorderBrush="#FF000000"></TextBox>
</DockPanel>
</Window>
What happens, at least during my limited testing, is that the textbox renders with an inset border pattern (top/left is black, right/bottom is grey). However, when you resize to any position except the original, the entire textbox border goes to black. Whenever you return the window to the exact number of on-screen pixels the form had when it first loaded, it's inset again.
I'm guessing it isn't pixel snapping as I can easily correct the problem with this code:
<Window x:Class="WpfSandbox.CuriousExample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="CuriousExample" Height="300" Width="300">
<DockPanel Margin="15">
<Border BorderThickness="1" BorderBrush="#FF000000">
<TextBox BorderThickness="0" ></TextBox>
</Border>
</DockPanel>
</Window>
Anyone care to venture an explanation as to what I'm seeing? Or is it all in my head?
Like I said, the above workaround can resolve this problem - just trying to understand what is happening here.
Thanks,
-Scott
You can force the application to use the vista theme (aero)
Open your app.xaml and put something like:
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/PresentationFramework.Aero;V3.0.0.0;31bf3856ad364e35;component/themes/aero.normalcolor.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
Don't forget to put the PresentationFramework.Aero reference into your project.
With this, you will se you application in XP like in Vista.
Hmm... are you running into a focus issue? I loaded the Aero theme, and I'm seeing your TextBox inset when the TextBox has focus or is moused-over. You can see this pretty clearly when you add a second TextBox like so:
<DockPanel Margin="15">
<TextBox BorderThickness="1" BorderBrush="#FF000000"></TextBox>
<TextBox BorderThickness="1" BorderBrush="#FF000000"></TextBox>
</DockPanel>
The default Style for Aero uses a ControlTemplate which sets the TextBox's border to use the ListBoxChrome which looks to set some extra properties when the control has Focus or is moused over.
Alternately, the default Style for the Luna theme binds the containing Border's BorderBrush directly to the TemplateBinding, which means that this is always respected (and why it works in XP/Luna and not in 2008 or Vista).

Controls "out of window/chrome" in WPF

Is there a way to have controls/images/etc "out of" the Window/Chrome (ie, Aero's glass) in WPF?
An example of what I mean is the WPF Yahoo Messenger which was released (and then discontinued) awhile back. The WindowStyle looks like it is set to None, but AllowTransparencies/CanResize set to false/true respectively - and the avatar is slightly "out of the window/chrome".
I know I could create my own glass border, but that may be a fair bit of effort to get it looking consistent.
Yes, I believe you will have to replace window's interface with your own. You can start with transparent window and a grid within leaving some margin around the grid. Then put thumbs, titlebar etc on the grid to simulate window behavior. Margin around the grid will allow you to draw controls outside your "window".
<Window
x:Class="TransparentFormDemo.Window2"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window2" Height="300" Width="300"
AllowsTransparency="True"
WindowStyle="None" Background="Transparent">
<Grid Margin="20" Background="AliceBlue">
<Thumb Name="topThumb" Height="5" HorizontalAlignment="Stretch" VerticalAlignment="Top"
DragDelta="topThumb_DragDelta" Cursor="SizeNS"/>
<!--Thumbs continued-->
<Polygon Points="10,110 60,10 110,110" Fill="Blue" Margin="0,-30"/>
</Grid>
</Window>

Absolutely centered content inside a WPF layout panel

I need to find a way of absolutely centering the content of a LayoutPanel in WPF. I have two textblock elements which must render at the vertical and horizontal center of the panel without relying on absolute heights and widths.
This is something i can do quite easily with a single element since any ContentControl can have it's verticalContentAlignment property set but then you only have a single child element to play with and i'm back to square one.
Any help would be massively appreciated.
<Window x:Class="WpfApplication1.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<Grid VerticalAlignment="Center">
<StackPanel HorizontalAlignment="Center">
<TextBlock>First</TextBlock>
<TextBlock>and the second</TextBlock>
</StackPanel>
</Grid>
</Window>
You could also write your own Panel subclass that does this automatically.
Fixed it as i asked it!
What i needed to do was place a StackPanel inside a ContentControl and set the StackPanels VerticalAlignment to Center. Seems obvious now!

Resources