WPF ScrollViewer set ScrollableHeight - wpf

I have a user control which paints content in OnRender. The Height of that control grows by and by.
I added this control to a ScrollViewer. The control does only repaint the currently visible area (viewport) (+/- a view lines for smoother scrolling).
Everything works fine so far...
But since the control usualy grows up to a few hundred thousands of pixels I want to keep the Height of my control as small as possible and provide a different Height value to bind to the ScrollableHeight of the ScrollViewer (same goes for VerticalOffset). But there is no setter for ScrollableHeight. It binds automatically to the Height of my Control. Neither can I override Height.
How can I customize my ScrollViewer (or VerticalScrollbar) to keep the real Height of my control small?

I did something like this in the past. What you need to do is to write your own layout Panel and implement the IScrollInfo in it. The interface looks big, but most of it is just calling one of the main set methods. The layouter needs to set some of the IScrollInfo properties, like ExtentHeight, Offset etc. and these are your way to customize how the ScrollViewer will calculate the scroll position and the scrollable area for your "virtual" canvas size. For implementing the IScrollInfo i used this tutorial as a guidance.

Related

How to make a resizeable (from conner) layout like in 3d max main window

I have WPF prototype application which includes 1-4 other controls (WebBrowser control) like on picture
A need to resize a control (with facebook) taking it's conner and reducing size until the center of a window. If the size of this control would be less then "minSize" then it should be hidden\closed. Other layouts should fill an empty area.
I don't know from which controls should I start my experiments. No one does the right work.
I tried Grid, but it's impossible to take cell's conner to resize webBrowser control.
GridSplitter works just for two panels and doesn't let me take cell's conner.
Some developers say about custom control creating...

Silverlight 4/WPF - Nested ScrollViewer panel that scales with available screen size

In the Windows Forms world you can take a panel and set it's dock property to fill and so on with nested panels, when the user resizes the window the panels and nested panels automatically resize too. I want to achive something similar with Silverlight, here is my current structure.
Main
ScrollViewer // for body
UserControl
Grid
control
Scrollviewer // this is where my problem is
Control
The problem is I can set a size for the nested scroll viewer that looks good for 1024 resolution, but I also want to account for users that have larger resolution. If I leave it auto the content just stretches below the visible bottom line and defers to the top level ScrollViewer.
If I could achieve something analogous to how Windows Forms handles this with docking I think my problem would be solved. I must have a ScrollViewer for the nested panel and I want it to fill all visible space left. How Can I achieve this with SL4 or WPF?
[Edit]
Here is an illustration of what i'm after.
The top-level ScrollViewer allows its content to be as large as it needs to be, and adds scrollbars if that means they don't fit in the window. Its children no longer know or care how tall the window is; they just know that they've got as much space as they want.
So what is it that you want from your nested ScrollViewer? It's got all the space it needs, so it will grow to show all of its content -- there's nothing to restrict it to the height of the window. In fact, you added a top-level ScrollViewer, which specifically told it "don't restrict it to the height of the window".
If you want your inner ScrollViewer to be restricted to the window height, then take out the top-level ScrollViewer.

Silverlight canvas scrollbars

I have read that placing a canvas inside a scrollviewer won't work because the canvas does not report its size. I have been experimenting with different containers (borders, grids, canvases and scrollviewers) and could really do with a simple explanation of how scrollviewers behave within nested containers. e.g. If I have a container hierarchy of UserControl>Grid1>Canvas1>ScrollViewer>Grid2>Canvas2 should scrollbars appear around Grid2 when Canvas2 becomes wider than Canvas1? (or indeed wider than UserControl) If not, how should I organise my containers so I can add loads of uielements to Canvas2 and have scrollbars appear as necessary. (My usercontrol width and height are set to 100%)
Canvas will work with a ScrollViewer if you explicitly give it a size. The problem comes from the fact that if you don't supply a Height and Width for any control it will try and determine it's available area based off it's parent container. A ScrollViewer however has infinite available area.
Take a Grid for example. If I define a Grid that has 2 Star Width columns and 2 Star Height rows. How does the Grid know how wide each of those columns should be? The star says they should be half of the available area, but inside a ScrollViewer the available area is infinity.
What controls are you adding to Canvas2? If you are adding them with fixed positions than the ScrollViewer will expand to house all elements. If you aren't giving them fixed positions than all the controls will stack on top of each other, because that is the arrange behavior of a Canvas

Panel with percentage coordinates

I would like use a panel whose children have coordinates specified as percentage of total panel's width/height. Moreover, I should be able to animate the coordinate property, for example to make a button move from 10% to 50% panel's width.
I've made 2 attempts:
Use a Grid and specify size as stars - this was not enough, because AFAIK by default WPF cannot animate distance properties specified by stars. I've found somewhere a custom class that enabled me to do so, it even worked, hovewer I consider that solution overly complicated an I am looking for something simpler.
Use a Canvas with fixed width and height and put it inside a Viewbox - this is a simple solution, but when resizing the Viewbox the whole content of Canvas is resized too. I want the content to have fixed size.
Is there a simple solution or should I implement my own panel (or maybe extend one of the existing ones, i.e. Canvas)?
Cheers!
I would:
subclass Canvas, perhaps calling it RelativeCanvas or RatioCanvas
add two attached properties: XRatio and YRatio
override ArrangeOverride and loop over all children. For each child, use their XRatio and YRatio along with the ActualWidth and ActualHeight of the RelativeCanvas to calculate and apply values for their Canvas.Left and Canvas.Top attached properties
You would use it as follows:
<local:RelativeCanvas>
<!-- the top-left of this button will be center of panel -->
<Button local:RelativeCanvas.XRatio="50" local:RelativeCanvas.YRatio="50"/>
</local:RelativeCanvas>
One thing you might like to add after you get that working is control over alignment. For example, I might to align the center of a control to the specified ratio, not its top-left corner.
There's one here: WPF Proportional Panel

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