Force control to stay beside another - c#

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'

Related

Resize parent by moving splitter

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.

Cannot get grid splitter to work the way I would like within 3 column grid in WPF

I have the following grid using WPF and a few third party controls (Telerik):
<Grid x:Name="grid2" Grid.Row="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" MinWidth="150"/>
<ColumnDefinition Width="5"/>
<ColumnDefinition Width="*" MinWidth='80'/>
</Grid.ColumnDefinitions>
<Grid Grid.Column="0">
<Grid.RowDefinitions>
<RowDefinition Height="26"/>
<RowDefinition/>
</Grid.RowDefinitions>
<telerik:RadBreadcrumb Grid.ColumnSpan="3" Header="RadBreadcrumb"/>
<telerik:RadTreeView Grid.Row="1"/>
</Grid>
<GridSplitter Grid.Column="1" HorizontalAlignment="Center" Width="5" Height="auto"/>
<telerik:RadTransitionControl x:Name="Trans" Grid.Column="2" Width="auto"/>
</Grid>
Currently I am trying to make it so that the grid in column 0 (on the left side) will not re-size while re-sizing the window. I was able to achieve this effect by setting the width of column "0" to either a static 150 or auto. However, when I did this, the grid splitter no longer respected the minimum width of column 2 and allowed it to drag off the screen. By setting both column 0 and 2 to a width of star (the way I have it in the code now) the min widths are respected (the columns can't shrink past the 150 and 80 defined) but they don't re-size properly (the left column re-sizes in proportion to the right column). I would like to somehow get both the resize and the gridsplitter to work at the same time. Let me know if I wasn't clear enough or if more input is needed.
So, this isn't exactly what I was looking for, but it's doing the job for me:
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto" MinWidth="150" MaxWidth="1000"/>
<ColumnDefinition Width="5"/>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
I set the MaxWidth of my left hand column so that you could no longer drag the splitter past the point of no return on the right side. This solution also allows me to set the first column's width to auto (which makes the re-sizing work the way I intended as well). Unless you have a monitor smaller than 1000px wide (which in the environment I'm working in won't happen) this solution will work just using XAML. Again, I'm a little disappointed with this solution but its at least working in a simplistic manner.

Gridsplitter: limit row heights to window size

I have just started to experiment with gridsplitters and have stumbled across a very weird behaviour and I cannot seem to fix it. Apparently the others have similar issues (according to google), but there were no helpful comments.
I have a grid with 2 rows. On start up the bottom one has a Hight of 250. The top row takes the rest with *. When I resize the rows with the splitter the behaviour is as expected for the top row. But when I drag the splitter upwards and past the program window, the content of the bottom row will drop out of the window (=move downwards until it is gone). I'd expect that I cannot make each row larger than the parent container.
<Grid x:Name="grid_main" ScrollViewer.VerticalScrollBarVisibility="Disabled" >
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition MinHeight="250" Height="250"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<GridSplitter x:Name="splitter"
ResizeDirection="Rows" Grid.Column="0" Grid.ColumnSpan="1" Grid.Row="0" Width="Auto"
Height="5" HorizontalAlignment="Stretch" VerticalAlignment="Bottom" Margin="0" ResizeBehavior="BasedOnAlignment" />
<Grid Grid.Column="0" Grid.Row="0">
</Grid>
<Grid Grid.Column="0" Grid.Row="1">
</Grid>
</Grid>
This is my code. The content of both rows is again hosted in grids and has been removed for the sake of simplicity. Again: Resizing for the top row works fine. But the bottom row can be resized to infinity. It works as expected if I hard-code a MaxHeight. But that has to depend on the window size.
Try changing your second RowDefinition to the following:
<RowDefinition MinHeight="250" MaxHeight="{Binding ElementName=grid_main, Path=ActualHeight}" Height="250"/>
This will ensure that the row height will not exceed the window size.
Richard's solution didn't work for me (the ActualHeight of the grid expanded past the window size along with the row height).
Using Snoop, I found that the ActualHeight of an ancestor ContentPresenter wasn't increasing. Thus the following bottom row definition worked for me, although I was still seeing issues if I set MinHeight on either the top or bottom rows:
<RowDefinition Height="430"
MaxHeight="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ContentPresenter}}, Path=ActualHeight}"/>
This problem only occurs because the second row has an absolute Height. If you actually want an absolute Height value try Richards's solution. Otherwise, just use a relative Height (e.g. 2*) on the second row as well.
Grigory Zhadko's answer is good to me.
I had a problem with this code
gridBase.RowDefinitions[1].Height = (GridLength)gridLengthConverter.ConvertFrom("1");
gridBase.RowDefinitions[3].Height = (GridLength)gridLengthConverter.ConvertFrom("1");
and I fixed it like this
gridBase.RowDefinitions[1].Height = new GridLength(0.1, GridUnitType.Star);
gridBase.RowDefinitions[3].Height = new GridLength(0.1, GridUnitType.Star);
and the grid converter works perfectly

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);
}

Allow user resize WPF TreeView node by dragging

I'd like to give the user the ability to resize TreeView node by dragging its border, the same way you would resize a window.
What control should I put inside TreeNode template to make this possible?
Or, if there is no such control, what is the best way to do this?
I was playing with GridSpliter and was reminded about your question. Here's another way to do it, more light way, without 3rd party controls, besides it's always nice to have options :) This is just a sample that gives you an idea about the grid splitter:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition x:Name="Column1" Width="35*"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition x:Name="Column2" Width="65*"/>
</Grid.ColumnDefinitions>
<Border BorderBrush="Gray" BorderThickness="1" Margin="2">
<TextBlock>your treeview</TextBlock>
</Border>
<GridSplitter Width="2" ResizeBehavior="PreviousAndNext" Grid.Column="1"/>
<Border BorderBrush="Gray" BorderThickness="1" Grid.Column="2" Margin="2"/>
</Grid>
you can use avalon docking lib. It's free and super easy to setup. There are a few posts even here (on stack overflow). But basically you can just pin treeview to the side, set some properties not to allow floating or close, and you're good to go.
overview/tutorial
http://avalondock.codeplex.com/documentation
download of 1.3:
http://avalondock.codeplex.com/releases/view/48794

Categories

Resources