Autoscaling to parent object within a ScrollViewer? - silverlight

I am having an autoscaling issue with my pages. The pages are displayed within a ScrollViewer, which usually contains a column on the ~33% right and a grid on the ~66% left.
I want to only autoscale the grid's Height (ie. independantly from the column at the right), so that it stretches according the size of the window, ergo, the object that contains the ScrollViewer and not the ScrollViewer itself.
So far, I have not managed to put this idea into practice... How could I possibly explain to my xaml code that I want my grid to be stretched in comparison to the ScrollViewer's "parent" rather than the ScrollViwer itself?
Here is a code example of what I'm trying to accomplish here, if it make my case any simpler:
<Grid x:Name="Parent" MinHeight="400" MaxHeight="700">
<ScrollViewer x:Name="Annoying ScrollViewer">
<Grid x:Name="Page Content" ScrollViewer.VerticalScrollBarVisibility="Auto">
<!-- IN ANOTHER USERCONTROL FAR, FAR AWAY... -->
<Grid x:Name="Inner Page Content">
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition Width="330" />
</Grid.ColumnDefinitions>
<Grid x:Name="Right column" Grid.Column="1"></Grid>
<Grid x:Name="Left Grid" Grid.Column="0" VerticalAlignment="StretchToParentUserControl? Please?"></Grid>
</Grid>
<!-- BACK TO THE PARENT USERCONTROL -->
</Grid>
</ScrollViewer>
</Grid>
EDIT: I solved my problem by using the Window size in code-behind directly through App.Current.Host.Content.ActualHeight and substracting the height of the parent files's contents (it is static, so I can just type the numbers). Still, I won't put this solution as an answer since it does not actually answer the original question.
And here is a little drawing of what my (reached) goal was as requested (uh... just switch the words "left" and "right" in the picture) :

Related

WPF control alignment is wrong when dynamically added

Hi I thought I could solve this easily but it is driving me crazy.
I am using a UserControl to house a video player control based on VLC, along with play and stop buttons etc. I then place the UserControl on my main form. if the UserControl is declared in XAML it behaves normally.
I decided to rewrite the code to instantiate my UserControl dynamically, in case I need to destroy it and create another on the fly. But when I do the video moves to the top of its container instead of the middle.
The UserControl relevant section is here:
<Grid x:Name="LayoutParent" >
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
<RowDefinition Height="12" />
</Grid.RowDefinitions>
<!-- I comment this if adding player dynamically -->
<!--<wpf:VlcPlayer Grid.Row="0" x:Name="Player" />-->
<!-- I un-comment this if adding player dynamically -->
<Grid x:Name="VideoPlayerPanel" Grid.Row="0" Margin="0" />
<StackPanel Grid.Row="1" Opacity="0.8">
...(buttons etc)
</StackPanel>
<ProgressBar ...(progressBar etc) />
</Grid>
My codebehind looks like this:
Dim Player As VlcPlayer = New VlcPlayer ' uncomment If adding the player dynamically
Public Sub New()
' This call is required by the designer.
InitializeComponent()
' Add any initialization after the InitializeComponent() call.
Player.SetValue(Canvas.ZIndexProperty, -1)
VideoPlayerPanel.Children.Add(Player)
VolumeSlider.Value = 50
End Sub
I have tried VerticalAlignment="Center" and VerticalAlignment="Stretch" in XAML on the VideoPlayerPanel, with Center the video disappears entirely, with Stretch it still aligns to the top.
Any thoughts as to what I might do to align this centrally would be much appreciated!
When adding Player dynamiccaly you have different result, because you wrap Play in additional Grid. Try to add Player directly to first row of LayoutParent:
Player.SetValue(Grid.Row, 0)
LayoutParent.Children.Add(Player)
Thanks to all that replied.
I did some more research, I substituted in a Rectangle for the player control and it aligned perfectly. That led me to discover that the third party control was itself at fault. I had to get the source and change the VerticalAlignment directly.
Sorry for the runaround.
Remove Height="*" from first Row . * is used to occupy remaining space, so it is good to use it for the last Row.
Use fixed width and or Auto.

WPF adding stackpanel with border to grid gives error

I'm working on a nested grid/stackpanel/grid window in WPF. Its a Calander, with a maingrid cell being a day. In this day there's a textbox and a stackpanel. The stackpanel contains a grid. EVerything is done in c#, build at run time, because the layout changes with the current month/year. No major problems sofar except when I want to add a border to a stackpanel. It gives the following error:
An unhandled exception of type 'System.Windows.Markup.XamlParseException' occurred in PresentationFramework.dll
Additional information: 'The invocation of the constructor on type 'ADBF.ToezAcad.Admin.OpleidingKalender.MainWindow' that matches the specified binding constraints threw an exception.' Line number '3' and line position '9'.
Nothing special at this position.
Funny thing is it only gives this error, the moment I add the stackpanel ( with border ) to the containing grid.
short version of the code:
Border stackpanelborder = new Border();
this.Content = stackpanelborder;
StackPanel stackpanel = new StackPanel();
stackpanelborder.Child = stackpanel;
Grid.SetColumn(stackpanel, m);
Grid.SetRow(stackpanel, d + 1);
mainGrid.Children.Add(stackpanel); // if I uncomment this line, it throws the error.
Any help would be highly appreciated,
Arnold
#ADBF you are adding the StackPanel to two different child collections. Each UIElement should only have one parent in the visual tree, though a UIElement may have many children, depending on it's type.
I think you wanted to add stackpanelborder to the children of the mainGrid instead.
Edit:
Also you should be referencing stackpanelborder in the SetColumn/SetRow Methods not stackpanel.
The reason being since stackpanel is a child of stackpanelborder it will render inside the that UIElement. However stackpanelborder needs to be told where to insert in the grid, assuming you intend to add additional columns/rows later.
Basically your XAML document if you had one should look like this:
<Grid Name="mainGrid">
<Grid.ColumnDefinitions>
<ColumnDefinition .../>
<ColumnDefinition .../>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition .../>
<RowDefinition .../>
</Grid.RowDefinitions>
<Border Name="stackpanelborder" Grid.Row="0" Grid.Column="0" ...>
<StackPanel Name="stackpanel" .../>
</Border>
</Grid>

Grid stretched upon resizing

I have 3 grids on the same row on a grid. Is there a way to stretch just the middle grid but not the other two upon resizing? All I could do right now is to stretch the last one.
I have tried to set the middle grid's horizontalAlignment to stretch but then it stretches all the way and even overlapped the last grid without the program running. Still don't quite understand why....
Not sure if i understood your layout/plan, but you should be able to do this with the Row/Column in the middle haivng star size.
e.g.
<Grid>
<Grid.ColumnDefintions>
<ColumnDefintion Width="Auto"/>
<ColumnDefintion Width="*"/>
<ColumnDefintion Width="Auto"/>
</Grid.ColumnDefintions>
<Grid Grid.Column="0">...</Grid>
<Grid Grid.Column="1">...</Grid> <!-- Middle will stretch -->
<Grid Grid.Column="2">...</Grid>
</Grid>

How to Hittest Grid ColumnDefinition?

I am making kind of WPF Designer. I want to find out ColumnDefinition i have clicked on to delete it from grid control. I will take care of those children who "are in that ColumnDefinition".
Can i get it from sender argument of click event handler?
Now im checking if e.GetPosition is in range of ColumnDefinition.ActualWidth but i wonder if there is more beautiful solution.
From within your click event handler:
int columnIndex = Grid.GetColumn((UIElement)sender);
where sender if a direct grid's child.
Why do you need to capture a click on ColumnDefinition anyway? Is virtual, it does not have any actual body, it is only a hint for Grid on how you want to layout its content.
So you have to set handlers on content objects, not on ColumnDefinition.
If you really need to capture a click on the whole surface of a grid cell, you may try to place a white (or other color the same as background) Reactangle inside it and capture a click on it.
Some clarification on how WPF Grid works.
When you add some controls to the Grid, they all become its children.
<Grid>
<Button/>
<TextBox/>
<Label/>
</Grid>
And they all will be displayed not regarding how you have configured Column or RowDefinitions.
Column and RowDefinitions only tell Grid how you want to aling all the existing elements inside it, but they are not containers, they don't hold elements inside.
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="10"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Button/><!-- this is identical to Grid.Column="0"-->
<TextBox Grid.Column="1"/>
<Label Grid.Column="2"/>
</Grid>
In this example we have created three ColumnDefinitions, even from the grid XAML you can see, that controls are not inside definitions. They are used just like ruler guides to align content.
Then you set attached properties on the elements to tell the grid where you want to put your elements.
When grid begins layout, it will see, that there are three elements, and three ColumnDefinitions, and will try to positions elements as ColumnDefinitions says.
But if you remove or change ColumnDefinitions in the runtime, grid will just realign controls in a new way.
If you want to hide some elements, you have to hide them, not ColumnDefinition.

How to toggle a WPF Grid column visibility

I'm having some trouble getting this to work in a WPF app I'm working on. Basically, what I'm after is something like the Task pane in an MMC:
The app has three columns in the main part of the display. I need a column on the right side which is resizable. I presume this means using a Grid with a GridSplitter but anything that works will do.
I want to be able to save the width of the right-side column when the app is closed and load it when the app is opened but this should be an initial size: the user should be able to resize it.
When I resize the window, I want the left- and right-side columns to stay the same size and the middle column to resize with the window width.
The left- and right-side columns need to have a minimum width. When I resize the right-side column I want the centre column to get smaller but not the left-side column.
I also want to be able to toggle the visibility of the right-side column with a toggle button which is outside the column and when it returns to visibility I want it to be the same width it was before.
I'm trying to do as much as possible in XAML and with binding.
And can I have it topped with cream, ice cream and chocolate chips, please? :-)
As I read your requirements, instead of thinking of a Grid, I think of a DockPanel.
<DockPanel>
<Grid Name="right"
DockPanel.Dock="Right" MinWidth="100" />
<Grid Name="Left"
DockPanel.Dock="Left" MinWidth="100" />
<Grid Name="middle" />
</DockPanel>
If you make a way to resize right, then middle will change as right is resized. If you resize the window, only middle will change. Storing and setting the Width of right is up to you, but shouldn't be hard.
As for allowing the user to resize right, that will a bit trickier, but I found this article that should help. This other article might help even more.
For the visibility of right, you can set its Visibility to Collapsed to hide it and restore it by setting it to Visible.
Note: The panels inside don't have to be Grids, but you will want to use some sort of Panel for each. Whatever you have inside your current Grid columns should work just fine.
I used a Grid with GridSplitters since this made it really easy to resize the middle column while maintaining the widths of the left and right columns.
XAML:
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="MainWindow"
Title="Main Window"
Width="640" Height="480">
<Grid>
<Grid.ColumnDefinitions>
<!-- Left column -->
<ColumnDefinition Width="200" MinWidth="100"/>
<!-- Left GridSplitter column -->
<ColumnDefinition Width="5"/>
<!-- Center column. A width of * means the column will fill
any remaining space. -->
<ColumnDefinition Width="*"/>
<!-- Right GridSplitter column -->
<ColumnDefinition x:Name="RightSplitterColumn" Width="5"/>
<!-- Right column -->
<ColumnDefinition x:Name="RightColumn" Width="200"
MinWidth="100"/>
</Grid.ColumnDefinitions>
<GridSplitter Grid.Column="1" HorizontalAlignment="Stretch" />
<GridSplitter Grid.Column="3" HorizontalAlignment="Stretch" />
<Button x:Name="ToggleButton" Grid.Column="2"
Content="Toggle Right Column" Width="150" Height="25"
Click="ToggleButton_Click" />
</Grid>
</Window>
Code-Behind
When hiding the right column, I just set the column width to 0 since grid columns don't have a visibility property.
public partial class MainWindow : Window
{
private double rightColumnWidth;
private double rightColumnMinWidth;
private bool rightColumnHidden;
public MainWindow()
{
this.InitializeComponent();
}
private void ToggleButton_Click(object sender, RoutedEventArgs e)
{
if (rightColumnHidden)
{
// Restore the widths.
RightColumn.MinWidth = rightColumnMinWidth;
RightColumn.Width = new GridLength(rightColumnWidth);
RightSplitterColumn.Width = new GridLength(5);
}
else
{
// Remember the user-set widths for the columns.
rightColumnWidth = RightColumn.Width.Value;
rightColumnMinWidth = RightColumn.MinWidth;
// Remember to set the minimum width to 0 before changing the actual
// width.
RightColumn.MinWidth = 0;
RightColumn.Width = new GridLength(0);
RightSplitterColumn.Width = new GridLength(0);
}
rightColumnHidden = !rightColumnHidden;
}
}
As for saving and restoring the column widths on startup, I would just store the width variables to a settings file and then apply them when your app is reopened.
Set the columndefinition Width to Auto and put a control inside that column and give Star for the other columns . Whenever you want to hide the column with content, set the control.Visibility=Collapsed and since column width is Auto, you wont see that column and the remaining columns will take the space.
3 years later you can find another approach on CodeProject.
http://www.codeproject.com/Articles/437237/WPF-Grid-Column-and-Row-Hiding
It adds a "Visible" property to custom Column definitions.

Resources