How can canvas in wpf be autosized? I have a canvas in scrollviewer and I will add several buttons and lines in this canvas in code behind. since I don't know the position of the buttons, I have to hard code a very large number for the width and height of the canvas or if I add too many buttons, it can only show part of them.
I try to set the Width and Height to Auto but it doesn't work.
<Grid>
<ScrollViewer HorizontalScrollBarVisibility="Visible" VerticalScrollBarVisibility="Visible">
<Canvas Width="Auto" Height="Auto" Name="cv1"></Canvas>
</ScrollViewer>
</Grid>
The Canvas element is the only element that can not be automatically resized, because has no inherent layout characteristics. If you want the Control to be resized as child elements come in, you could use something deriving from Grid.
Try a UniformGrid instead of your Canvas ans fill it with the elements you want. It allows you to just add elements without any layout constraints that are handled by the UniformGrid. otherwise if you use a simple Grid, you will have to define a Position for your element by setting the Margin property of each child element.
Hope this helps.
Related
I have a Window with a DockPanel, and within the DockPanel I have two user controls. The "header" user control is docking at the top of the window like I expect. However, the "footer" user control does not dock at the very bottom of the window, but instead seems to dock about 500 or so pixels below the header. There's maybe another 300 pixels (I'm just guessing by where it appears in the window) below the "footer" of just empty space.
The header control has a DesignHeight of 100, and the footer control has a DesignHeight of 20.
Why is the footer not docking at the very bottom of the Window?
MainWindow.xaml code:
<Window x:Class="RATTA.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="clr-namespace:RATTA.ViewModel"
xmlns:vw="clr-namespace:RATTA.View"
Title="RATTA" Height="800" Width="600" Background="WhiteSmoke">
<DockPanel Width="Auto" Height="Auto" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<vw:HeaderVw DataContext="MainHeaderVM" DockPanel.Dock="Top" />
<vw:FooterVw DataContext="MainFooterVM" DockPanel.Dock="Bottom" />
</DockPanel>
</Window>
The DockPanel.Dock property for the last child in the DockPanel does nothing because the DockPanel's property LastChildFill is set to true by default. Therefore, it doesn't matter what DockPanel.Dock property you assign -- if it's the last child, it's going to fill the remainder of the DockPanel.
The reason why it appears to be about 300px from the header and the bottom of the window is because when the last child fills if the last child's height is explicitly set it will sit in the center of the remaining space.
There are a few solutions which depend on your design intentions.
Place another object after the footer (eg. a Grid). This is typical usage of a DockPanel -- toolbars, statusbars, menus, etc. are docked first and the primary content of the view is the last object in the DockPanel (it will fill the remaining space).
Place the footer before the header. This will cause the footer to be docked first and the header will fill the remainder, which might be what you want to do.
Alternatively, set LastChildFill of the DockPanel to false. This will cause your docked objects to behave correctly but the remaining space in the DockPanel won't be filled if you add another object to it.
Use a different control. A Grid could also be a suitable control -- 3 rows, the first with a height of Auto, the second with no specified height (or a height of * or 1* if you want to be explicit), and the third with a height of Auto.
I'm trying to implement a certain layout.
I have two elements that I want to stack vertically (I need them to follow each other closely). I am currently trying to achieve it using a Stackpanel.
The problem is that I want the first element to have a limited width and the other to use all the width available in the StackPanel. Ideally, I would like that the first element have a width equals to the width of four columns from the grid that contains the StackPanel, here is my code.
<Grid>
<!-- Colums and Rows definition go here -->
<StackPanel Grid.Column="0" Grid.ColumnSpan="4" Grid.Row="3" Grid.RowSpan="8">
//The first element
<Viewbox Name="viewbox_choix" Margin="160,0,0,0" HorizontalAlignment="Left" VerticalAlignment="Top" Grid.Column="0" Grid.ColumnSpan="4" Grid.Row="3" Grid.RowSpan="4">
//The second element
<StackPanel Grid.Column="0" Grid.ColumnSpan="5">
<Border></Border>
etc...
</StackPanel>
</StackPanel>
</Grid>
The grid attributes are referring to the parent grid of the stackpanel. But the Grid.Column and Grid.ColumnSpans seem to have no effect when I try to use them inside the StackPanel.
The problem of that code is that the first element also uses all the width of the StackPanel but that isn't what I want...
Can anybody help me ? I precise that I'm still learning WPF and I don't really know how bindings work...
In WPF, a StackPanel does not work like a Grid. There is no maximum width... it will happily let content disappear out of its right side. If you want automatic resizing, just replace the StackPanels with `Grid
UPDATE >>>
In the Grid class, there is an attached property called IsSharedSizeScope. Add this to the parent Grid and set it to true. Then in your RowDefinitions, you can add SharedSizeGroup properties to the columns that you require.
These examples may help you:
Grid's SharedSizeGroup and * sizing (SO post)
Grid.IsSharedSizeScope Attached Property (MSDN)
You may need to experiment a bit, but you should be able to get the desired effect using these properties.
I hope this isn't a duplicate but I can't find any documentation or examples on how to actually use ScrollToVerticalOffset(). I'm using it in a Windows Phone 8 app, but I think it will still apply to WP7 and Silverlight (although, feel free to correct me if I'm wrong).
So here is my basic set up (pseudo-code from memory):
<phone.PivotItem>
<ScrollViewer>
<Grid Height="1500">
<Grid.RowDefinitions>
<!-- about 20 rows, all auto-height -->
</Grid.RowDefinitions>
<Border Grid.Row="0">
<TextBox x:Name="txt1" />
</Border>
<Border Grid.Row="1">
<TextBox x:Name="txt2" />
</Border>
<!-- ...... -->
<Border Grid.Row="19">
<TextBox x:Name="txt20" />
</Border>
</Grid>
</ScrollViewer>
</phone.PivotItem>
So as you can see, I've got a ScrollViewer within a PivotItem, and inside is a Grid. In the Grid there are about 20 TextBoxs, each within a Border. I am dynamically setting focus to one of these TextBoxs when this page loads, so anytime I set focus to TextBox #6-20 (roughly) - I have to manually scroll down to see it. I want to auto-scroll my ScrollViewer so that whichever TextBox has focus, it will be centered for the user to see.
The documentation for ScrollToVerticalOffset() says:
Scrolls the content that is within the ScrollViewer to the specified
vertical offset position.
And that it accepts a type of System.Double.
What I don't understand is A) the value I'm supposed to pass, and B) how I could even get that value? Is it supposed to be a number between 0 and the height of my Grid (1500)? If so, how could I determine the position of any given TextBox so I can scroll to it?
If there are any straightforward examples, please feel free to link out to them. I'm not sure if the content within the ScrollViewer matters when calling this method, but in case it does I wanted to show exactly how I'm using it.
Many thanks in advance!
You can see any UIElement's position relative to another UIElement using the UIElement.TransformToVisual call.
First, get the transform between the TextBox and ScrollViewer.
GeneralTransform transform = textBox.TransformToVisual(scrollViewer);
Then, figure out what point (0,0) of the TextBox is relative to the ScrollViewer. Meaning, the TextBox origin (0,0) is located at what ScrollViewer position.
Point textBoxPosition = transform.Transform(new Point(0, 0));
Now that you know the Y position of the TextBox relative to the ScrollViewer, scroll to that Y offset.
scrollViewer.ScrollToVerticalOffset(textBoxPosition.Y);
Good luck!
This is a very old post, but the meaning of VerticalOffset varies.
Most of the solutions I have seen assume VeritcalOffset is in pixels. This is not always the case.
From: https://learn.microsoft.com/en-us/dotnet/api/system.windows.controls.scrollviewer.extentheight
If CanContentScroll is true, the values of the ExtentHeight, ScrollableHeight,
ViewportHeight, and VerticalOffset properties are number of items. If
CanContentScroll is false, the values of these properties are Device Independent Pixels.
In a scenario like this:
<StackPanel x:Name="StackPanel1" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" Orientation="Horizontal">
<Element1/>
<Element2>
</StackPanel>
It possible to stretch last element (Element2) in control list to fit all possible space (like width="*")?
I am forced to use a grid?
The StackPanel content area collapses to fit the children. Stretch in the direction that grows on a StackPanel is only useful for painting the background. It does not affect the children.
Use a grid or a custom container.
I have the following structure in my WPF application. (Using Prism and Regions)
Window---->
UserControl---->
DockPanel------>
Grid(2X2)------>Row0Col0--
Grid (2X1)------>
ItemsControl------>
UserControl(injected into ItemsControl with Prism)----->
DockPanel----->
DataGrid.(60 rows, 10 columns)
The behavior that I expect is that the DataGrid will size itself to fit the size of the grid cell and display both scrollbars because it is too big to fit. But it doesnt. It remains its maximum size and cuts out of the edges of the grid cell. All cells of both grids have no size specifications (Auto Sized). When I explicitly specify datagrid's height and width, I see the scrollbars, but of course I don't want to do that.
Please help!.
Thanks
I have saved the screenshots at the following link.
http://s1199.photobucket.com/albums/aa467/vikasgoyalgzs/
You say: "All cells of both grids have no size specifications (Auto Sized)" - this is where the problem is. When the grid cell is auto sized the grid gives the content in that cell as much space as it wants (doesn't matter if it fits in the window or not). To fix it you have to put your DataGrid into a star-sized cell.
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Border Grid.Row="0">
<!-- Content that will take as much space as it wants -->
</Border>
<Border Grid.Row="1">
<!-- Content that will take all the remaining space -->
</Border>
</Grid>
UPDATE: Based on the screenshots you provided...
First, get rid of the DockPanel in the top level control. DockPanel gives its child all the space it asks for. If it is not a "fill" child (LastChildFill="True"). Use grid instead of DockPanel (i.e. at the top level a grid with two rows - one auto-sized for the menu and the second star-size for the rest of the stuff, the in that star-size row put another grid for you items controls, etc.).
Remember, whenever you put the content either in an auto-size cell in a grid or in a DockPanel with dock type different than Fill, the content will take as much space as it required without showing a scroll bar (it will go beyond the window).
UPDATE 2: Looking at the new screenshots (see comments to this post)...
OK, I think I see the problem. The thing is that ItemsControl uses StackPanel to display its children, but StackPanel also gives its children all the space they want (your DataGrid thinks that it has enough space to render itself without scroll bars).
To fix that you need to put your items controls inside an ScrollViewer like this:
<ScrollViewer VerticalScrollBarVisibility="Auto"
HorizontalScrollBarVisibility="Auto">
<ItemsControl ... />
</ScrollViewer>