Reputation: 655
Been wrestling with this seemingly easy problem for a couple hours.
I have a main window, and inside that window is a canvas that holds a tab control. The tab control houses various user controls. The user controls fit the window just fine when it is full size (and the window has to be fixed size). However, one of the machines this runs on is lower resolution than the main window size. So I put a maxheight in code behind the main window to only size to the max height/width of the display.
public MainWindow()
{
InitializeComponent();
this.MaxHeight = SystemParameters.MaximizedPrimaryScreenHeight - 20;
this.MaxWidth = SystemParameters.MaximizedPrimaryScreenWidth;
...
So now the main window is only as big as the screen (minus the size of the taskbar). Which is good. I, however, can't seem to make any scrollbars appear at the right scope (which is over the whole window). So, when the resolution is too small I want a window no bigger than the screen and which has scrollbars to scroll through the entirety of its content.
I've tried placing a Scrollviewer at multiple levels, but even though I can show the scrollbars, I can never get them to enable. I figure this is because none of the content of the main window is ever too big for it, I just can't see it cause the window size is smaller (as each content item fits exactly inside it's parent).
So, how do I make the window scroll all of it's content? I've tried enabling Horizontal & Vertical scrolling in the window xaml and enclosing the canvas, also. I've also tried wrapping the window around a scrollviewer (which doesn't work).
What am I missing, in either xaml or codebehind.
P.S. - I've taken out all the scrollViewer references I've been messing with in case my fumblings confuse someone.
<Window x:Class="myWin.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:usercontrols="myControls"
Title="PCU ATS" Height="985" Width="1280" Left="0" Top="0" Background="#FFAE4949" ResizeMode="NoResize">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Closing">
<i:InvokeCommandAction Command="{Binding CloseCmd}" />
</i:EventTrigger>
</i:Interaction.Triggers>
<Canvas Background="CadetBlue">
<TextBlock x:Name ="debugBlock" Canvas.Left="1030" TextWrapping="Wrap" Text="" Canvas.Top="4" Width="91"/>
<Button x:Name= "btnLogIn" Content="Access Debug" Command="{Binding LoginCmd}" VerticalAlignment="Top" Height="23" Background="Maroon" Foreground="White" BorderBrush="#FF060303" Canvas.Left="1126" Width="79" />
<TabControl Canvas.Left="0" Canvas.Top="0" Height="946" Name="mainTabControl" Width="1264" Padding="0" ScrollViewer.CanContentScroll="True" >
<TabItem Header="Test Description" Name="testTab" FontWeight="Bold">
<Grid Background="LightSteelBlue">
<usercontrols:testDescEntry x:Name="userControl1" Loaded="testUserControl_Loaded" ScrollViewer.CanContentScroll="True" Margin="0,0,0.5,0" />
</Grid>
</TabItem>
<TabItem Header="Start Test" Name="sTab" FontWeight="Bold" ScrollViewer.CanContentScroll="True">
<Grid Background="LightSteelBlue" ScrollViewer.CanContentScroll="True">
<usercontrols:StartCon x:Name="userControl2" ScrollViewer.CanContentScroll="True"/>
</Grid>
</TabItem>
<TabItem Header="Manual Debug" Name="mainDTab" FontWeight="Bold" Visibility="Hidden">
<Canvas Background="DarkOrange" >
<TabControl Canvas.Left="0" Canvas.Top="0" Height="922" Name="debugControl" Width="1262" Padding="0">
<TabItem Header="debug3" Name="debug1Tab" FontWeight="Bold">
<Grid Background="LightSteelBlue">
<usercontrols:debug3 x:Name="Control1" ScrollViewer.CanContentScroll="True" />
</Grid>
</TabItem>
<TabItem Header="Name1" Name="debug2Tab" FontWeight="Bold">
<Grid Background="LightSteelBlue">
<usercontrols:debug4 x:Name="Control2" ScrollViewer.CanContentScroll="True" />
</Grid>
</TabItem>
<TabItem Header="Nam2" Name="debug3Tab" FontWeight="Bold">
<Grid Background="LightSteelBlue">
<usercontrols:Name3 x:Name="Control3" ScrollViewer.CanContentScroll="True" />
</Grid>
</TabItem>
</TabControl>
</Canvas>
</TabItem>
</TabControl>
</Canvas>
Upvotes: 1
Views: 1927
Reputation: 10622
Add a ScrollViewer above canvas and set its height and width according to the controls. I've made a working one..
put scrollViewer Like
<ScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto">
<Canvas Name="canvas1" Background="CadetBlue">
....
....
.
void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
autoSizeCanvas(canvas1);
}
void autoSizeCanvas(Canvas canv)
{
int height = canv.Height;
int width = canv.Width;
foreach (UIElement ctrl in canv.Children)
{
bool nullTop = ctrl.GetValue(Canvas.TopProperty) == null || Double.IsNaN(Convert.ToDouble(ctrl.GetValue(Canvas.TopProperty))),
nullLeft = ctrl.GetValue(Canvas.LeftProperty) == null || Double.IsNaN(Convert.ToDouble(ctrl.GetValue(Canvas.LeftProperty)));
int curControlMaxY = (nullTop ? 0 : Convert.ToInt32(ctrl.GetValue(Canvas.TopProperty))) +
Convert.ToInt32(ctrl.GetValue(Canvas.ActualHeightProperty)
),
curControlMaxX = (nullLeft ? 0 : Convert.ToInt32(ctrl.GetValue(Canvas.LeftProperty))) +
Convert.ToInt32(ctrl.GetValue(Canvas.ActualWidthProperty)
);
height = height < curControlMaxY ? curControlMaxY : height;
width = width < curControlMaxX ? curControlMaxX : width;
}
canv.Height = height;
canv.Width = width;
}
Use the function only in Loaded event or later and not in constructor. The window has to be measured before loading..
Upvotes: 0
Reputation: 3369
My suggestion is: don't use Canvas
. In WPF, unlike Windows Forms, absolute positioning of UI elements is strongly discouraged. This is because when you do it, you disable WPF's ability to dynamically reposition items, which is what a lot of WPF layout functionality is based on.
Basically, when you use a Canvas
, you're telling WPF to just give you a space to draw and not to worry about it. If you don't specify a size, WPF will not know how big your Canvas
is and, therefore, cannot make a decision whether the scroll bars should be visible or not. This can be fixed by giving the Canvas
a fixed size and using a ScrollViewer
. Something like this:
<ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
<Canvas Background="CadetBlue" Width="1500" Height="1000">
<!-- your canvas content -->
</Canvas>
</ScrollViewer>
However, I strongly advise against this. What if the window size changes or someone has different screen resolution that you? Your layout can be achieved in a much better and flexible way using other WPF containers. Here is an example of what it may look like (I removed a bunch of stuff that has no impact on layout):
<Grid Background="CadetBlue">
<StackPanel VerticalAlignment="Top" HorizontalAlignment="Right"
Margin="0,0,20,0" Orientation="Horizontal">
<TextBlock x:Name ="debugBlock" Margin="0,0,20,0"/>
<Button x:Name="btnLogIn" Content="Access Debug" Height="23""/>
</StackPanel>
<TabControl Name="mainTabControl" Padding="0">
<TabItem Header="Test Description">
<Border Background="LightSteelBlue">
</Border>
</TabItem>
<TabItem Header="Start Test">
<Border Background="LightSteelBlue">
</Border>
</TabItem>
<TabItem Header="Manual Debug">
<Border Background="DarkOrange" >
<TabControl Padding="0">
<TabItem Header="debug3">
<Border Background="LightSteelBlue">
</Border>
</TabItem>
<TabItem Header="Name1">
<Border Background="LightSteelBlue">
</Border>
</TabItem>
<TabItem Header="Nam2">
<Border Background="LightSteelBlue">
</Border>
</TabItem>
</TabControl>
</Border>
</TabItem>
</TabControl>
</Grid>
For the background of the content of the tabs, I used Border
, as it is a little more lightweight that Grid
. But you can use either.
With this approach, everything should resize nicely when the screen itself is resized. You can see that this achieves basically the same layout as your canvas while being much simpler.
If you want to use ScrollViewer
, keep in mind that there must be something inside that that has fixed size.
TL;DR Don't use Canvas
, don't give elements absolute size and position. Use a StackPanel
, Grid
or any panel except Canvas
, position your elements within it, then fine-tune the position using Margin
or Padding
.
Upvotes: 1