Resize parent by moving splitter - c#

i have a question about resizing.
I know the function of a splitter is to split some elements in the form without resizing the parent. The splitter splits the 100% of the parentsize in e.g. 40% and 60%. But in my case i need a splitter or something like that, which resize the parent (UserControl) and not the other element (Panel).
For example i have 2 panels with the height of 50px and 50px. Between them there is a splitter which resizes now one panel to 70px. The second panel should keep the 50px and the UserControl should resize to 120px.
Furthermore in my application the UserControl is added to a panel with autoscroll = true to show a vertical scrollbar. Does anyone have an idea to realize this?

You could try coding some action inside the splitter event that will change your window size. However it is counter intuitive (does not follow standard windows ui) that a window will resize following an action from the inside.
Consider setting your grid row definitions in a way that only the top one resizes when then window is resized. e.g. below for columns. the example is from a working real page that does what you asked (the columns on the right side are not squeezed or stretched when the windows is resized). Note that the splitters in the actual page xaml are far below (after all the content panels).
<Grid.ColumnDefinitions>
<ColumnDefinition Name="ThirdCol0" Width="353"></ColumnDefinition>
<ColumnDefinition Name="ThirdCol1" Width="*"></ColumnDefinition>
<ColumnDefinition Name="ThirdCol2" Width="*" MaxWidth="100"></ColumnDefinition>
<ColumnDefinition Name="ThirdCol3" Width="117" MaxWidth="267"></ColumnDefinition>
</Grid.ColumnDefinitions>
<!-- here there are different panels etc -->
<GridSplitter x:Name="MidSplitter" DragCompleted="MidSplitter_DragCompleted" SnapsToDevicePixels="True" Grid.Row="0" Grid.Column="1"
Width="5" Opacity="0.2" VerticalAlignment="Stretch" HorizontalAlignment="Right"
ShowsPreview="False"></GridSplitter>
<GridSplitter x:Name="Col2Splitter" DragCompleted="MidSplitter_DragCompleted" Grid.Row="0" Grid.Column="2"
Width="5" Opacity="0.2" VerticalAlignment="Stretch" HorizontalAlignment="Right"
ShowsPreview="False"></GridSplitter>
<GridSplitter DragCompleted="MidSplitter_DragCompleted" Grid.Row="0" Grid.Column="0"
Width="5" Opacity="0.2" VerticalAlignment="Stretch" HorizontalAlignment="Right"
ShowsPreview="False"></GridSplitter>

When the size of your user control changes, you need :
the panel1 to be resized
the panel2 to keep its height unchanged
Am I right ?
In this case, you don't need to use a splitter, but the Dock property of Controls :
Set the panel1.Dock property to DockStyle.Fill : the panel1 will take all available space in the UserControl
Set the panel2.Dock property to DockStyle.Bottom : the panel2 will keep its initial height to stay at the bottom of the UserControl
I hope it helps.

Related

How to change position of gridsplitter if user change it before control loading inside column/row attach to GridSplitter in wpf c#

<Grid Grid.Row="1" Visibility="Collapsed" Name="Main_Grid" >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" MinWidth="100" MaxWidth="1000"/>
<ColumnDefinition Width="2" />
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid Grid.Column="0">
<UserControl/>
</Grid>
<GridSplitter Grid.Column="1" VerticalAlignment="Stretch" HorizontalAlignment="Left" Margin="0" ResizeDirection="Columns" ShowsPreview="False">
<Grid Grid.Column="2">
</Grid>
Here is my Grid Structure .
After loading application I set Visibility of UserControl Visible/Collapsed depends on DataContext.
First time FirstColumn take width as per need(as Width property of ColumnDefination is define as "Auto").
But if user move GridSplitter and after that if I assign new Datacontext to User control or click something in UserControl which has different with GridSplitter remain at old position where user left.
How to refresh it so that it First GridColumn Take Width as per need and GridSplitter should appear attach to it.
So I understand that once the user had changed the position of GridSplitter manually, it will no longer automatically adjust its position even after the size of adjacent Grid changed. In such case, you can revive Auto settings of ColumnDefinition by setting it again from code behind.
this.Main_Grid.ColumnDefinitions[0].Width = GridLength.Auto;

How to make a certain section scrollable

I have got the following XAML:
<StackPanel HorizontalAlignment="Center">
<Image Name="logo" Source="logo.png" Margin="0,0,0,50"/>
<ScrollViewer>
<Dashboard_Control:AlignableWrapPanel x:Name="wrapPanel"/>
</ScrollViewer>
<TextBlock FontWeight="Bold" HorizontalAlignment="Center" x:Name="txtBottomText"></TextBlock>
</StackPanel>
I would like that the wrapPanel is scrollable only, so that the txtBottomText control will always be at the bottom as you scroll, and the logo image control will always be at the top - essentially only allowing the wrapPanel to be scrollable.
I have tried adding a ScrollViewer as shown above, however it never shows. I even tried adding a property to always have the vertical scrollbar, however it appears without letting me scroll (the scrollbar is disabled).
I suspect that this is because my wrapPanel's content is dynamically generated at run-time like so:
wrapPanel.Children.Add(content);
Any ideas what I can do to fix this?
It's not because of your wrapPanel's content. but because you're using a StackPanel to contain everything.
StackPanels grow indefinitely in the direction determined by their Orientation property. By default, that's vertically.
In your case, that makes the ScrollViewer "think" it has enough available space to stretch itself to accomodate its content, instead of activating the scroll bars. So it simply gets bigger as the WrapPanel inside gets bigger, pushing the TextBlock down.
To avoid this, you need to use a different Panel that is able to properly assign the available space to each control. Like a Grid.
<Grid HorizontalAlignment="Center">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Image Name="logo" Source="logo.png" Margin="0,0,0,50"/>
<ScrollViewer Grid.Row="1">
<Dashboard_Control:AlignableWrapPanel x:Name="wrapPanel"/>
</ScrollViewer>
<TextBlock Grid.Row="2" FontWeight="Bold" HorizontalAlignment="Center" x:Name="txtBottomText"></TextBlock>
</Grid>
I usually say that StackPanels tend to be overused :P They're practical and easy to use, but they have a bunch of quirks and limitations that make them not suitable for many situations, like this one.
EDIT: Make sure, also, that the Grid is not contained inside another vertical StackPanel, a Grid row with Height set to Auto, or something like that.
If the Height of your WrapPanel exceeds the height of the control or window where you have put the controls, the Textblock below the Wrap Panel inside the Stack Panel is put after the Wrap panel and so it is below the scroll area.
To be able to leave the Textblock always visible you have two means:
1) limit the height of your Wrap panel
2) Use a container like a Grid with 3 rows instead of the stack panel and put the Row Heights of the Grid respectively to
Auto, *, Auto so that the image on top and the textblock on bottom use the space of their content and the Scroll panel uses all the space remaining
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Image Grid.Row ="0" Source="myimage.jpg" />
<ScrollViewer Grid.Row="1">
<WrapPanel Height="1200" Width="600">
<TextBlock>Ciao sono io</TextBlock>
</WrapPanel>
</ScrollViewer>
<TextBox Grid.Row="2" TextWrapping="Wrap" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Text="IO c'ero" />
</Grid>
You have to set a fixed heigh to your scrollviewer - if not, the scrollviewer takes as much space as he needs, in order to show the complete content of its children.
Solutions:
Set the Height property of your scollviewer
Use a grid instead of a stackpanel an set the first and third rowheight to auto

Resize overlay control with window resize

I have a overlay control with a grid with few controls on it. On my WPF window I create an instance of this overlay as below
<overlays:OverlaySelector x:Name="Selector" Grid.Row="2" Grid.RowSpan="2" Grid.Column="3" Height="Auto"/>
My problem is that when I re-size my WPF window the overlay does not re-size. What could be the problem?
You shouldn't be manually resizing controls in WPF. Proper use of your control should do that for you. Try using the FrameworkElement.HorizontalAlignment, FrameworkElement.VerticalAlignment and FrameworkElement.Margin properties to automatically resize the control for you when the Window is resized. Try something like this:
<overlays:OverlaySelector x:Name="Selector" Grid.Row="2" Grid.RowSpan="2"
Grid.Column="3" Height="Auto" HorizontalAlignment="Stretch"
VerticalAlignment="Stretch" Margin="20" />
Of course, this won't work if you have hard coded any size or dimension values inside your OverlaySelector control.

Using "pure" xaml layout, is it possible to tell a container to not resize to it's children?

I have a XAML control that's very wide. It affects the size of it's parent, thus changing layout I don't want it to change. I don't mind if the control will be clipped, or whatever - but I want the following:
I want the control to be the width of it's parent and
I don't want it to otherwise affect the width of its parent.
I know I can achieve this by binding Width to ActualWidth of the parent control I am interested in. However, is there some panel or something that will take its size from its parent while ignoring it's children.
Because this is inside a Grid that has star sized columns, just putting it inside a ScrollViewer does not help - the ScrollViewer still grows to fill the grid.
In the following example, I want the button to govern the width of the middle column and the textblock to take, at most, the amount of space the Button does:
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Button Content="asdsadsad" Grid.Row="1" Grid.Column="1"/>
<TextBlock IsHitTestVisible="True" Opacity="0" Grid.Row="1" Grid.Column="1" Text="sdfsdfdsfdfhfkjahslkjfhsafhsakjhflkjsahflkjsahdflkjhsadfsdfkgljdsfkgjfdsjgdshf" />
</Grid>
You can put the TextBlock in a Canvas and then clip the canvas to its bounds:
<Canvas Grid.Row="1" Grid.Column="1" ClipToBounds="True">
<TextBlock IsHitTestVisible="True" Opacity="0.5" Text="sdfsdfdsfdfhfkjahslkjfhsafhsakjhflkjsahflkjsahdflkjhsadfsdfkgljdsfkgjfdsjgdshf" />
</Canvas>
if that's what you mean.
I saw you've already accepted the other answer, but if you're only referring to text blocks, couldn't you just use TextTrimming?
If that's not the case, a simple Panel subclass would be better than the canvas as you could explicitly ignore the children's size when determining the size you need. You'd still need to measure the children. You'd just ignore the 'DesiredSize' of them when determining the panel's size in the MeasureOverride. Then in ArangeOverride, it would respect the maximum size you specified in MeasureOverride.
The advantage of that is there too textboxes or any control for that matter would still properly size and layout as children, but but they would never affect the panel's size.
Here's the MeasureOverride code you'd need. Then in ArrangeOverride, you just lay the children out as you want, deciding to consider clipping or constraining to the panel as you see fit. (Custom panels are one of my favorite WPF things.)
protected override Size MeasureOverride(Size availableSize)
{
// You still measure the children. You just don't use them when determining the size of the panel.
foreach(FrameworkElement childElement in this.Children)
{
if(childElement.Visibility != Visibility.Collapsed)
childElement.Measure(availableSize);
}
return new Size(
Double.IsPositiveInfinity(availableSize.Width) ? 0 : availableSize.Width,
Double.IsPositiveInfinity(availableSize.Height) ? 0 : availableSize.Height);
}

Force control to stay beside another

I am in the process of completing a fault logger for my company.
Unfortunately, not all people have the same screen resolution (ranging from 800 - 1080), I need to create controls that can change size based on the window size.
So far, I have been able to force controls to change their dimensions based on window dimensions, but I am faced with a challenge of them overlapping after a certain size, as shown below:
Is there a way to force the TextBox and GroupBox to float just left of the DataGrid, so it will move right based on the width of the grid?
Grid columns will solve the overlap problem but you might want to consider using a GridSplitter control, for example:
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition Width="Auto" />
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<GridSplitter Grid.Column="1"
HorizontalAlignment="Center"
VerticalAlignment="Stretch"
Background="Black"
ShowsPreview="True"
Width="5"
/>
References & useful pages:
"GridSplitter Class (System.Windows.Controls)" [msdn.microsoft.com]
Bing Search: 'gridsplitter'

Categories

Resources