Lock element on the right - wpf

I have two textboxes in my app, with a variable lenght. One is on the left, the other one on the right. By default their width is pretty little, 30 px. But as they contain a lot of numbers, the textbox on the left shifts the right one and enlarges the window (same thing when the right textbw contains too many numbers). To avoid this, I would like to stabilize the right textbox on the right, even if its width rises.
I've tried to play with the columns size, but not.
<Grid Grid.Row="2">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="170" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="10" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBox Grid.Column="1" MinWidth="30" Margin="0,0,0,0" Name="maxGmapWest" Text="{Binding Path=Options.MaxGmapWest, ElementName=Window, Mode=OneWay, Converter={StaticResource StringToDoubleConverter}}" PreviewTextInput="Tab1_PreviewTextInput" Width="auto" />
<TextBox Grid.Column="3" MinWidth="30" Margin="230,0,0,0" Name="maxGmapEast" Text="{Binding Path=Options.MaxGmapEast, ElementName=Window, Mode=OneWay, Converter={StaticResource StringToDoubleConverter}}" PreviewTextInput="Tab1_PreviewTextInput" Width="auto" HorizontalAlignment="Left" />
</Grid>

Try something like that markup
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<ScrollViewer Grid.Column="0" Width="auto" MinWidth="50" VerticalScrollBarVisibility="Auto" Margin="0,0,0,0" HorizontalAlignment="Left" MaxHeight="40" >
<TextBox Name="maxGmapWest" TextWrapping="Wrap" />
</ScrollViewer>
<ScrollViewer Grid.Column="1" HorizontalAlignment="Right" VerticalScrollBarVisibility="Auto" MinWidth="50" Margin="0,0,20,0" MaxHeight="40">
<TextBox Name="maxGmapEast" TextWrapping="Wrap" />
</ScrollViewer>
</Grid>
maxwidth for textbox=width of column, fixed max height and using ScrollViewer for large text

Related

Why doesn't a textbox stretch inside stackpanel WPF?

<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="25*" />
<ColumnDefinition Width="49*" />
<ColumnDefinition Width="25*" />
</Grid.ColumnDefinitions>
<StackPanel Grid.Column="1" Margin="30" VerticalAlignment="Center">
<StackPanel Orientation="Horizontal">
<TextBlock Margin="0,0,5,0" Text="Username:" />
<TextBox HorizontalAlignment="Stretch"/>
</StackPanel>
</StackPanel>
--Result image--
Im trying to make it so that the textbox will fill the rest of the space inside the current StackPanel.
however the "Stretch" propety doesn't seem to work - why is that?
Is there a different way do it or what am I doing wrong?
A StackPanel always tries to achieve the minimum possible height/width, depending on orientation; therefore, Stretch has no effect. You might want to use a DockPanel instead, which allows children to stretch:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="25*" />
<ColumnDefinition Width="49*" />
<ColumnDefinition Width="25*" />
</Grid.ColumnDefinitions>
<StackPanel Grid.Column="1"
Margin="30"
VerticalAlignment="Center">
<DockPanel>
<TextBlock DockPanel.Dock="Left" Margin="0,0,5,0"
Text="Username:" />
<TextBox HorizontalAlignment="Stretch"/>
</DockPanel>
</StackPanel>
</Grid>

Horizontal scroll bar prevents text box wrapping

I am trying to make TextBox to wrap text and grow with the Window. That works if I don't set ScrollViewer's HorizontalScrollBarVisibility property. But if I do, TextBox will grow infinitely. The problem is solved by setting MaxWidth property to the TextBox, but in that case TextBox does not grow beyond the MaxWidth value. My idea was then to bind MaxWidth to ColumnDefinition's ActualWidth, but that also doesn't work because ColumnDefinition's ActualWidth property is not a DependencyProperty. Here is my code:
<ScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Row="0" Grid.Column="0" Text="Name:" Margin="5" />
<TextBox MinWidth="200" Grid.Row="0" Grid.Column="1" TextWrapping="Wrap" AcceptsReturn="True" Margin="5"/>
</Grid>
</ScrollViewer>
Any ideas will be appreciated.
Try this:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Text="Name:" Margin="5" />
<ScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto" Grid.Column="1">
<TextBox MinWidth="200" TextWrapping="Wrap" AcceptsReturn="True" Margin="5" MaxWidth="{Binding Path=ActualWidth, RelativeSource={RelativeSource AncestorType={x:Type ScrollViewer}}}" />
</ScrollViewer>
</Grid>

Textblock.TextTrimming not working inside a grid

I have a 3 column grid for my layout with each of it width set to Width="*". For the middle (2nd) grid, I have another 3 column grid each containing it own textblock, and again the column grids width are set to Width="*".
When the Window is resized, the grids are resized as expected, however the 3rd textblock isn't getting trimmed if the text goes outside the boundary of the grid. I have textbox set with TextTrimming="WordEllipsis" and TextWrapping="Wrap", and the properties are not being enforced for some reason.
Here is some of the code I have:
Layout grid:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition MinWidth="150" MaxWidth="300" Width="1*" />
<ColumnDefinition Width="Auto"/>
<ColumnDefinition MinWidth="150" MaxWidth="500" Width="1*" />
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="2*"/>
</Grid.ColumnDefinitions>
</Grid>
2nd column code:
<Grid Grid.Column="2" VerticalAlignment="Bottom" HorizontalAlignment="Left" Margin="5" Width="Auto">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding Path=FeedItems.Count}" Foreground="White" FontSize="18" Width="Auto" FontWeight="SemiBold" />
<TextBlock Text=" items from " Foreground="White" FontSize="18" Width="Auto" Grid.Column="1" />
<TextBlock Text="{Binding Path=Name}" Foreground="White" FontSize="18" Grid.Column="2" TextTrimming="CharacterEllipsis" HorizontalAlignment="Left" Width="Auto" TextWrapping="NoWrap" ClipToBounds="True" />
</Grid>
In order for this to work, you would need the last column in the second grid to have a * size, otherwise it will tell the TextBlock that it has as much space as it wants, even if it doesn't. Auto sized columns won't restrict the content to the bounds of a grid. However, you would probably get better results if you did this with a single TextBlock, and multiple Runs:
<TextBlock FontSize="18" TextTrimming="CharacterEllipsis">
<Run Text="{Binding Path=FeedItems.Count}" FontWeight="SemiBold" />
<Run Text=" items from " />
<Run Text="{Binding Path=Name}" />
</TextBlock>
Note that you can only bind Run.Text as of .NET 4.0. If you're using an older version of the framework, you'll have to create your own BindableRun, which is pretty simple as seen here.

Gridsplitter ignores minwidth of columns

I want to have a simple 3 column grid with resizeable columns and a MinWidth of 80.
The code looks like this:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="120" MinWidth="80"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*" MinWidth="80"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="120" MinWidth="80"/>
</Grid.ColumnDefinitions>
<GridSplitter Grid.Column="1" Width="5" HorizontalAlignment="Center" />
<GridSplitter Grid.Column="3" Width="5" HorizontalAlignment="Center" />
</Grid>
But it doesn't work in the way I want and expected. When the splitters are pushed to the left, all works fine. When the second splitter is pushed to the right all works fine. But if the first splitter is pushed to the right, it pushes the 3rd column and the second splitter out of the grid(or makes their width=0).
I used seperate columns for the gridsplitters, like it was done in the msdn example:
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition Width="Auto" />
<ColumnDefinition/>
</Grid.ColumnDefinitions>
...
<GridSplitter Grid.Column="1"
HorizontalAlignment="Center"
VerticalAlignment="Stretch"
Background="Black"
ShowsPreview="True"
Width="5"
/>
I also set the alignment to center as i read somewhere right alignment could be a problem
and tried different ResizeBehaviors.
Does anyone know, how to fix this issue, so that at all time the 3 columns are visible with at least 80px width?
Thanks for any help
Try this instead for three columns that have minwidth set to 80. Use * instead of specifying exact width when using gridsplitters.
<ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Hidden">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" MinWidth="80" />
<ColumnDefinition Width="5"/>
<ColumnDefinition Width="*" MinWidth="80"/>
<ColumnDefinition Width="5"/>
<ColumnDefinition Width="*" MinWidth="80"/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Text="{Binding Path=ActualWidth, RelativeSource={RelativeSource Self}}" />
<GridSplitter Grid.Column="1" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" Background="Red" />
<TextBlock Grid.Column="2" Text="{Binding Path=ActualWidth, RelativeSource={RelativeSource Self}}" />
<GridSplitter Grid.Column="3" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" Background="Red" />
<TextBlock Grid.Column="4" Text="{Binding Path=ActualWidth, RelativeSource={RelativeSource Self}}" />
</Grid>
</ScrollViewer>
Not able to post this as comments; So putting this in the Answer list.
If I put a Grid with GridSplitter as the content on the right side of the main Grid with GridSplitter, I'm able to push the right most pane out of bounds of the window. Any idea?
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" MinWidth="80" />
<ColumnDefinition Width="5"/>
<ColumnDefinition Width="*" MinWidth="80"/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Text="{Binding Path=ActualWidth, RelativeSource={RelativeSource Self}}" />
<GridSplitter Grid.Column="1" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" Background="Red" />
<Grid Grid.Column="2">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" MinWidth="80" />
<ColumnDefinition Width="5"/>
<ColumnDefinition Width="*" MinWidth="80"/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Text="{Binding Path=ActualWidth, RelativeSource={RelativeSource Self}}" />
<GridSplitter Grid.Column="1" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" Background="Red" />
<TextBlock Grid.Column="2" Text="{Binding Path=ActualWidth, RelativeSource={RelativeSource Self}}" />
</Grid>
</Grid>

WPF layout for autosize textblock and icon floating on the right - how?

I am trying to get a layout where an icon floats on the right end of a textblock; the textblock grows/shrinks to content. I cannot make this happen without the textblock running outside the grid. For example:
<Grid x:Name="LayoutRoot" Width="500" HorizontalAlignment="Left" ShowGridLines="True" >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="40"/>
</Grid.ColumnDefinitions>
<TextBlock x:Name="textBlock" VerticalAlignment="Top" Height="25" TextWrapping="NoWrap" TextTrimming="CharacterEllipsis" Grid.Column="0" >
<TextBlock.Text>longer keeps going and going testgrand you going and then t
</TextBlock.Text>
</TextBlock>
<Rectangle Fill="#FFDE3030" Stroke="Black" VerticalAlignment="Top" Height="41" Width="41" Grid.Column="1"/>
</Grid>
Seems like the natural approach and works fine when the text is shorter than the column/grid, except the textbox and column will grow indefinitely and not honor the bounds of the grid.
The inverse, with the icon on the left, works fine with a simpler layout, and the textblock doesn’t grow indefinitely. This is achieved with this markup:
<Grid Grid.Row="1" Width="500" HorizontalAlignment="Left">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="40" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Rectangle Fill="#FFDE3030" Stroke="Black" VerticalAlignment="Top" Height="41" Width="41" Grid.Column="0"/>
<TextBlock x:Name="textBlock2" VerticalAlignment="Top" Height="25" TextWrapping="NoWrap" TextTrimming="CharacterEllipsis" Grid.Column="1" HorizontalAlignment="Left">
<TextBlock.Text>longer testgrow the textblock and it will just keep growing but it will stop when it gets too </TextBlock.Text>
</TextBlock>
</Grid>
Any help appreciated. If a grid won’t work, is there an alternate layout where I can get the icon floating on the right of the text, and the textblock will trim text when it’s too long?
Also:
No, using * size columns doesn't work because the columns are fixed, and the icon won't float at the end of the text
A DockPanel doesn't work either, or at least I or others I've asked haven't been able to. The best it can do is to have the icon half-cut-off outside the dockpanel's right side.
Can you get what you want by setting MaxWidth on the TextBlock? If you add MaxWidth="460" to your first example:
<Grid x:Name="LayoutRoot" Width="500" HorizontalAlignment="Left" ShowGridLines="True" >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="40"/>
</Grid.ColumnDefinitions>
<TextBlock MaxWidth="460" x:Name="textBlock" VerticalAlignment="Top" Height="25" TextWrapping="NoWrap" TextTrimming="CharacterEllipsis" Grid.Column="0" >
<TextBlock.Text>longer keeps going and going testgrand you going and then t</TextBlock.Text>
</TextBlock>
<Rectangle Fill="#FFDE3030" Stroke="Black" VerticalAlignment="Top" Height="41" Width="41" Grid.Column="1"/>
</Grid>
Then the TextBlock will grow horizontally and always have the rectangle immediately on its right. It won't be wider than 460, so the TextBlock plus the Rectangle shouldn't be wider than 500. If you need the Grid to resize dynamically then you can bind TextBlock.MaxWidth to Grid.ActualWidth with a converter that subtracts the width of the Rectangle.
Edit:
Actually, it should be even simpler than that. Use star sizing on the columns, but set MaxWidth instead of Width on the Grid. That way, the grid itself will get smaller when the text is smaller so that the rectangle is always at the edge of the text.
<Grid x:Name="LayoutRoot" MaxWidth="500" HorizontalAlignment="Left" ShowGridLines="True" >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="40"/>
</Grid.ColumnDefinitions>
<TextBlock x:Name="textBlock" VerticalAlignment="Top" Height="25" TextWrapping="NoWrap" TextTrimming="CharacterEllipsis" Grid.Column="0" >
<TextBlock.Text>longer keeps going and going testgrand you going and then t</TextBlock.Text>
</TextBlock>
<Rectangle Fill="#FFDE3030" Stroke="Black" VerticalAlignment="Top" Height="41" Width="41" Grid.Column="1"/>
</Grid>
Someone internally suggested this answer, which works:
<WrapPanel HorizontalAlignment="Left" VerticalAlignment="Top">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="10" />
</Grid.ColumnDefinitions>
<AccessText TextTrimming="CharacterEllipsis" Grid.Column="0" Margin="0,0,4,0" Text="type more typingon the long hi longer than what if you keep tyingin and get to the end and that's why it changed because you were in the middle" />
<Border Grid.Column="1" Width="10" Height="10" Background="Red" />
</Grid>
</WrapPanel>
The wrappanel seems to provide the necessary magic. I haven't tried Quartermeister's but will save it for future reference!
Our final layout is more complicated and looks like this (it's the header bar for an expander):
<WrapPanel Orientation="Vertical">
<Grid x:Name="HeaderSite" >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="19" />
<ColumnDefinition Width="16" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition />
<ColumnDefinition Width="Auto" /> <!-- 7/14: fix from list: wrap the whole thing in a wrappanel. Allows for one * col. -->
<ColumnDefinition Width="19" />
</Grid.ColumnDefinitions>
<ToggleButton x:Name="buttonExpanderToggleButton"
Height="20" VerticalAlignment="Top"
/>
<Image x:Name="imageActivityIcon" Grid.Column="1"
Height="16" Width="16"
HorizontalAlignment="Left" VerticalAlignment="Top"
Margin="0"/>
<AccessText x:Name="textActivityID"
Grid.Column="2"
VerticalAlignment="Top" Margin="5,2,0,0"
TextTrimming="CharacterEllipsis"
FontSize="12" HorizontalAlignment="Left" Text="MA77777"/>
<AccessText x:Name="textActivityHeader"
Grid.Column="3"
VerticalAlignment="Top" Margin="0,2,0,0"
TextTrimming="CharacterEllipsis"
FontSize="12" HorizontalAlignment="Left" Text="Title title title title aand Title title title title a little and if you type more what happens as you keep typing "/>
<AccessText x:Name="textActivityStatus"
FontWeight="Normal"
FontStyle="Italic"
Grid.Column="4"
TextTrimming="CharacterEllipsis"
VerticalAlignment="Top" Margin="0,2,8,0"
FontSize="12" HorizontalAlignment="Left" Text="(On Hold)"/>
<Image x:Name="imageLink"
Stretch="None" VerticalAlignment="Top" HorizontalAlignment="Left" Grid.Column="5"/>
</Grid>
</WrapPanel>
This works fine too even with the other auto sized columns. The key seems to be the wrappanel and the one * sized column. If you set them all to auto it doesn't work.
I hope this and Quartermeister's answer helps somebody, because this drove me #$%#$% crazy.
The below code will result in the following output, is that what you are looking for???
longer keeps going and going... [red rectangle]
<Grid Width="200">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Text="longer keeps going and going testgrand you going and then t" TextTrimming="CharacterEllipsis"/>
<Rectangle Grid.Column="1" Fill="#FFDE3030" Stroke="Black" VerticalAlignment="Top" Height="41" Width="41" />
</Grid>
I had a somewhat similar problem; I wanted to show some content with an externally-sized border area but containing two TextBlocks, where the first is auto-sized and the second is fixed-sized, and the second floats left as the first gets smaller but stops at the right edge (so the first block's text is clipped instead of the second becoming invisible).
Distilling the previous answers, it appears that the key bit of magic is simply to use HorizontalAlignment="Left" with the first column set to star-sized.
<Border BorderThickness="1" BorderBrush="Black">
<Grid HorizontalAlignment="Left">
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Text="{Binding Value}" />
<TextBlock Grid.Column="1" Text="⏫" Margin="4,0,0,0" Foreground="Blue" />
</Grid>
</Border>
It appears that the way this works is that (a bit counter-intuitively) the Border stays full width (as set by its parent layout), while the Grid will size to its content -- except that it will not get wider than the containing Border. This keeps the second TextBlock visible.

Resources