How to force a scrollbar to scroll a canvas - wpf

I was wondering if there is any way to force a scrollbar to scroll a canvas.
I placed canvas in scrollview and I overrode the measureoverride method. Scrollbars show when I reach the ends of visible parts of the canvas. However I would like the canvas to scroll because now, despite the fact that scrollbars show, the canvas does not follow item. I hope you understand me, sorry for my bad English :)

Let me try,
1) You have a hosted a canvas inside a scroll viewer.
2) When the canvas size increases, the scroll viewer is appearing. [Since, you have set the horizontal or vertical scrollbar visibility to auto]
3) What you want is, When you reach the end of the canvas [Size of canvas gets increases, so scroll bars of scroll viewer will appear.] you want the scroll bar of the scroll viewer to scroll automatically to show the extra space.
If, the above question is right. Here goes, the answer.
You have to do a calculation based on the ActualWidth or ActualHeight of the canvas and set the value to the ScrollToHorizontalOffset or ScrollToVerticalOffset property accordingly.

Below sample will show a red circle in a blue canvas which will have vertical and horizontal scrollbars if it don't fit in the window.
<Window x:Class="WpfApplication.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">
<ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
<Canvas Width="500" Height="500" Background="Yellow">
<Ellipse
Stroke="Red" StrokeThickness="10"
Width="{Binding Path=ActualWidth, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Canvas}}}"
Height="{Binding Path=ActualHeight, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Canvas}}}" />
</Canvas>
</ScrollViewer>
</Window>

Related

How do I properly draw and scale a Canvas as a WPF background to a control?

I have a StackPanel that needs to contain drawn background. Specifically, my StackPanel needs to have the ability to grow and the rectangle must grow with the StackPanel, but must remain pseudo-anchored to each side at a fixed position.
I've attempted to use the Canvas.Left, Canvas.Right, Canvas.Top and Canvas.Bottom attached properties, but so far they've not worked. Furthermore, this does seem to work when drawing within Canvas objects, just not when they are embedded within a VisualBrush set as a background. How can I accomplish drawing this resizable, rectangular background within my StackPanel?
Below is the state of my current code. I've tried various approaches but none seem to work.
My Code:
<StackPanel DockPanel.Dock="Right" Orientation="Vertical" VerticalAlignment="Center">
<StackPanel.Background>
<VisualBrush Stretch="None">
<VisualBrush.Visual>
<Canvas Background="Magenta" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
Rectangle Fill="#FFDDECF7" Canvas.Left="20" Canvas.Top="20" Canvas.Bottom="20" Canvas.Right="0"/>
</Canvas>
</VisualBrush.Visual>
</VisualBrush>
</StackPanel.Background>
...
</StackPanel>
This currently doesn't render anything. I set the canvas background to magenta just so I could see if it were drawing, and I'm not even seeing that. Other attempts have drawn the canvase, however, the blue rectangle is always stretched to fill the window, regardless of attached canvas property settings.
Sample:
The image below is a sample of what I want. Again, I'm using an ugly Magenta color to show the offset of the internal, blue rectangle. As the StackPanel grows or shrinks, the rectangle needs to be affixed to the top, left, right and bottom.
My suggestion is to place the stackpanel inside a grid:
<Grid DockPanel.Dock="Right" VerticalAlignment="Center" Background="Magenta">
<Rectangle Margin="20" Fill="#FFDDECF7"/>
<StackPanel Orientation="Vertical">
no background...
</StackPanel>
</Grid>
Wrap Canvas into a ViewBox, then work on a ViewBox. As far as I know Canvas doesn't support scalling too well.

How do you control the height of a scrollviewer inside a tabitem?

I am having trouble getting the height of a scrollviewer to adjust to whatever the height is of a tabitem.
XAML:
<TabItem header="Item">
<ScrollViewer Height={Binding ActualHeight, RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=TabItem}}>
<Grid>
.
.
.
</Grid>
</ScrollViewer>
</TabItem>
When I do this the scrollviewer is only about 50 pixels high. The content inside displays fine. The viewing area height is limited.
I tried this.
<TabItem header="Item" x:Name="itemname">
<ScrollViewer Height="{Binding ElementName="itemname", Path=ViewportHeight}">
The scrollviewer is not limited but when the content inside the
scrollviewer grows it goes beyond the viewing area and the scrollbar
deos not work.
I have used the first (FindAncestor) example with a StackPanel and it works. Not sure why it won't with a TabItem.
Why not use the HorizontalAlignment / VerticalAlignment properties?
<ScrollViewer HorizontalAlignment="Stretch" VerticalAlignment="Stretech">

ScrollViewer inside (Stack-)Panel

I'm fighting with a ScrollViewer inside a StackPanel. The ScrollViewer only shows one scrollbar depending on the StackPanel's orientation, what I kind of understand as the StackPanel thinks to be unlimited in that direction. I therefore tried to limit the size of the ScrollViewer by binding it to the StackPanel's width and height. When the application is brought up it shows both scrollbars but they do not resize properly. What is wrong or how should I do it.
(Remark: I know I can use a Grid instead of the StackPanel and the ScrollViewer behaves as expected. However once I place that Grid into a StackPanel the problem shows up again.)
<Window x:Class="tt_WPF.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="500" Width="500">
<StackPanel x:Name="sp" Orientation="Horizontal">
<ScrollViewer
HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto"
Width="{Binding ElementName=sp, Path=ActualWidth}"
Height="{Binding ElementName=sp, Path=ActualHeight}">
<Button Background="LightCoral" Width="500" Height="500">Hey</Button>
</ScrollViewer>
</StackPanel>
A Scroll viewer is useless inside a vertical StackPanel. A vertical StackPanel has its height set to infinity, so the ScrollViewer has all the size it wants and will never show the scrollbar. You should switch to a Grid or DockPanel.
I had the same problem, i solved it by switching stackpanel and scrollviewer.

Silverlight 2.0 - scroll vertically, wrap horizontally

In silverlight 2.0. I have some content that i want to scroll vertically and wrap horizontally. In the controls I have a dock panel. The DockPanel's last child, which fills it, is a ScrollViewer
<UserControl x:Class="MyProject.MyControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:WinControls="clr-namespace:Microsoft.Windows.Controls;
assembly=Microsoft.Windows.Controls"
Width="400" Height="300">
<WinControls:DockPanel LastChildFill="True">
...
<ScrollViewer x:Name="MessageScroll" HorizontalScrollBarVisibility="Hidden"
VerticalScrollBarVisibility="Auto" BorderThickness="0" >
<Controls:TextDisplay x:Name="TextDisplay"></Controls:TextDisplay>
</ScrollViewer>
The TextDisplay control XAML looks like this:
<UserControl x:Class="MyProject.TextDisplay"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<TextBlock x:Name="TextDisplayText" TextWrapping="Wrap">
</TextBlock>
</UserControl>
What I want to happen: The TextDisplay should occupy the main area of the control,
with a vertical scrollbar if the height doesn't fit. The messages should wrap when they get too long horizontally.
The scrolling works, but now the messages don't wrap at the right-hand edge. they just cut off. It's not constraining the width, just hiding the HorizontalScrollBar. If I set HorizontalScrollBarVisibility="Auto" I can see them scrolling off to the right. How do i force it to wrap?
Try setting the HorizontalScrollBarVisibility of the ScrollViewer to Disabled (or do not specify a value as Disabled is the default) then the TextDisplay will wrap correctly and the horizontal scroll bar will not be displayed.

How to incorporate Canvas into a larger layout in WPF?

Canvas doesn't seem to play well together nicely with the other elements when you try to build it into a layout and have e.g. controls on the side and the canvas is the drawing area.
For instance, why can I put a border around every element except a canvas? In the following code, border wraps canvas but the canvas only has the border on the top but not on the left, right or bottom:
<Window x:Class="WpfApplication25.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">
<StackPanel>
<TextBlock DockPanel.Dock="Bottom" Text="Move the slider to reveal the answer:"/>
<Slider DockPanel.Dock="Bottom" Name="theSlider"
HorizontalAlignment="Left"
Width="200"
Minimum="0"
Maximum="1"
Value="1"
Cursor="Hand"/>
<Border BorderBrush="Tan" BorderThickness="2">
<Canvas>
<TextBlock Canvas.Left="45" Canvas.Top="50" Text="test" FontSize="16"/>
<Rectangle
Canvas.Left="10"
Canvas.Top="10"
Width="100"
Height="100"
Fill="Silver"
Opacity="{Binding ElementName=theSlider, Path=Value}"
/>
</Canvas>
</Border>
</StackPanel>
</Window>
From what I can tell in XamlPad, the problem appears to be that your Canvas does not have an explicit height/width, and that its HorizontalAlignment defaults to being in the middle of the Border. Without an explicit height and width the Border appears to collapse to 0 height and stretches on the width. My assumption is this is because your Border is in a StackPanel, as placing the Border in a Grid, causes it to behave as expected.
Your best bet is to give the Canvas an explicit Height and Width. Not sure that is what you're looking for though.
As far as I understand what you are trying to achieve, you should place your controls in one cell of a Grid and your Canvas in another.

Resources