TextBlock Wrapping Property Doesn't Work - wpf

In the following XAML, I am trying to wrap the TextBlock which binds to "PortfolioCodes" and "CommentaryText" but it seems that "Wrapping" doesn't work for TextBlock. I tried every possible suggestion I could find on this web site but all in vain. Can someone please help.
<Grid>
<ListBox ItemsSource="{Binding Path=Summaries}" ScrollViewer.HorizontalScrollBarVisibility="Disabled">
<ListBox.ItemTemplate>
<DataTemplate>
<Border CornerRadius="5" BorderBrush="LightGray" BorderThickness="1" Padding="4" Margin="4">
<Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"></ColumnDefinition>
<ColumnDefinition Width="15"></ColumnDefinition>
<ColumnDefinition Width="Auto"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
</Grid.RowDefinitions>
<TextBlock Grid.Column="0" Grid.Row="0">No Of Security</TextBlock>
<TextBlock Grid.Column="2" Grid.Row="0" Text="{Binding Path=PortfolioSecurityCount}"></TextBlock>
<TextBlock Grid.Column="0" Grid.Row="1">Portfolio Code(s)</TextBlock>
<Grid Grid.Column="2" Grid.Row="1" >
<TextBlock TextWrapping="Wrap" Text="{Binding Path=PortfolioCodes}"></TextBlock>
</Grid>
<TextBlock Grid.Column="0" Grid.Row="2">Commentary Text</TextBlock>
<Grid Grid.Column="2" Grid.Row="2" >
<TextBlock Grid.Column="2" Grid.Row="2" TextWrapping="Wrap" Text="{Binding Path=CommentaryText}"></TextBlock>
</Grid>
</Grid>
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
Based on Guge response, I have changed xaml as below and now its working.
<Grid x:Name="LayoutRoot">
<ListBox x:Name="SummaryListBox" ItemsSource="{Binding Path=Summaries}" ScrollViewer.HorizontalScrollBarVisibility="Disabled">
<ListBox.ItemTemplate>
<DataTemplate>
<Border CornerRadius="5" BorderBrush="LightGray" BorderThickness="1" Padding="4" Margin="4">
<Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"></ColumnDefinition>
<ColumnDefinition Width="15"></ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
</Grid.RowDefinitions>
<TextBlock Grid.Column="0" Grid.Row="0">No Of Security</TextBlock>
<TextBlock Grid.Column="2" Grid.Row="0" Text="{Binding Path=PortfolioSecurityCount}"></TextBlock>
<TextBlock Grid.Column="0" Grid.Row="1">Portfolio Code(s)</TextBlock>
<TextBlock Grid.Column="2" Grid.Row="1" TextWrapping="Wrap" Text="{Binding Path=PortfolioCodes}" ></TextBlock>
<TextBlock Grid.Column="0" Grid.Row="2">Commentary Text</TextBlock>
<TextBlock Grid.Column="2" Grid.Row="2" TextWrapping="Wrap" Text="{Binding Path=CommentaryText}"></TextBlock>
</Grid>
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>

Change the width of your third ColumnDefinition from "Auto" to "*", that way it only takes up whatever is left of your horizontal space.
To try to explain this:
Screen area in WPF is distributed in a two pass algorithm. First each visual element asks each child how much space it needs, with an indication of how much is available. These children do the same for their children.
Then each visual element tells each child how much they are actually going to get. These children, again, do the same for their children.
Your code failed to do what you wanted because the Grid in the DataTemplate told its third column children they could have all the horizontal space they wanted ("auto") in the first run. Those textboxes then thought that they wouldn't have to wrap. So they just reported back their desired width, and one line worth of height.
In the second run the Grid found that "auto" turned out to be a little less than what those children wanted. And the Grid still only gave them one line worth of height, so wrapping was out of the question. The children then had no other option left to them but to truncate the text.
When the third column width is set to "*", the grid will tell the children in the that column exactly how many horizontal pixels are left after the first column got their "auto" and the second column got their 15. Now the textboxes can figure out that they may want to wrap, and they report back "Ok, Dad, I'll make do with those measly horizontal pixels, but at least give me what I want in verticals". There is no limit to the vertical space, so they get what they need to present all their glorious content.

Try to give width to your TextBlock, by default TextBlock takes all available space and doesn't wrap text

Related

How to align to a control in the same screen?

In XAML, we typically have <Grid> layout which contains different elements. How do I align a control in one cell of grid to a control in a different cell like below?
(This used to be rather common in traditional applications where controls maybe in different group boxes etc but we still want to align them horizontally in one plane)
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width=".5*"/>
<ColumnDefinition Width=".5*"/>
</Grid.ColumnDefinitions>
<StackPanel Grid.Column ="0">
<TextBox x:Name="name" Height="50"/>
<Label Content="John"/>
</StackPanel>
<StackPanel Grid.Column ="2">
<RadioButton Content="Option1"/>
</StackPanel>
</Grid>
The result is below which is ugly:
In this case, I just want to option1 to aligned centered with the TextBox (which does have custom height).
I can use margins to bring it to the desired position but that's kind of hard coded and not too WPFish.
Should I use binding to tie them directly? Is there a better way? Another way I can think of is to keep making grids within grids but seems like that will over complicate for this simple thing?
Try putting them both in another Grid or a horizontal StackPanel, and put that in one of the parent Grid cells.
The following did the trick, basically wrap the <RadioButton> around in <Border>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width=".5*"/>
<ColumnDefinition Width=".5*"/>
</Grid.ColumnDefinitions>
<StackPanel Grid.Column ="0">
<TextBox x:Name="name" Height="50"/>
<Label Content="John"/>
</StackPanel>
<StackPanel Grid.Column="1" VerticalAlignment="Top">
<Border BorderBrush="{x:Null}" Height="50">
<RadioButton Content="Option1" Margin="10,0,0,0" VerticalAlignment="Center"/>
</Border>
</StackPanel>
</Grid>
This answer helped.
Now the result is:
Three variants.
The first - I will supplement #zar: I use size binding instead of explicitly assigning a value to the size.
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width=".5*"/>
<ColumnDefinition Width=".5*"/>
</Grid.ColumnDefinitions>
<StackPanel Grid.Column ="0">
<TextBox x:Name="name" Height="50"/>
<Label Content="John"/>
</StackPanel>
<StackPanel Grid.Column="1" VerticalAlignment="Top">
<Border BorderBrush="{x:Null}" Height="{Binding ActualHeight, ElementName=name, Mode=OneWay}">
<RadioButton Content="Option1" Margin="10,0,0,0" VerticalAlignment="Center"/>
</Border>
</StackPanel>
</Grid>
Second - I am implementing #Mark Feldman proposal: Delete StaskPanel and add lines to the grid.
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width=".5*"/>
<ColumnDefinition Width=".5*"/>
</Grid.ColumnDefinitions>
<TextBox x:Name="name" Height="50"/>
<Label Content="John"
Grid.Row="1"/>
<RadioButton Content="Option1" Margin="10,0,0,0" VerticalAlignment="Center"
Grid.Column="1"/>
</Grid>
The third - analogous to the first, but without the Border.
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width=".5*"/>
<ColumnDefinition Width=".5*"/>
</Grid.ColumnDefinitions>
<StackPanel Grid.Column ="0">
<TextBox x:Name="name" Height="50"/>
<Label Content="John"/>
</StackPanel>
<StackPanel Grid.Column="1" VerticalAlignment="Top">
<RadioButton Content="Option1" Margin="10,0,0,0" VerticalAlignment="Center" VerticalContentAlignment="Center"
Height="{Binding ActualHeight, ElementName=name, Mode=OneWay}"/>
</StackPanel>
</Grid>

WPF Grid ColumnSpan content dynamic width reformating other content

I know the title of this question is really confusing and also it is pretty hard to explain so I painted the following picture to explain what I am trying to reach.
My layout has to have three columns with the same width (*). In each column there are going to be many different groups with static content. I want the group title to extend over all three column if it is too long. Then there is also the checkbox on the right of every group title in each column that is then supposed to displayed under the title but still on the right side.
I've tried many different ways to achieve this and even ended up trying out datatriggers to set the grid row.
My current approach was having the subtitle columnspan on 3 again and try to have the checkboxes move out of the way if there's no space.
<Grid ShowGridLines="True">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBlock Grid.Column="0" Text="Title 0"/>
<TextBlock Grid.Column="1" Text="Title 1"/>
<TextBlock Grid.Column="2" Text="Title 2"/>
<TextBlock Grid.ColumnSpan="3" Background="LawnGreen" Grid.Row="1"
HorizontalAlignment="Left" Text="Subtitle 1"/>
<CheckBox Grid.Row="1" HorizontalAlignment="Right" Content="Check"/>
<CheckBox Grid.Row="1" Grid.Column="1" HorizontalAlignment="Right" Content="Check"/>
<CheckBox Grid.Row="1" Grid.Column="2" HorizontalAlignment="Right" Content="Check"/>
</Grid>
Thanks for the help, even if the answer is that this isnt possible. ^^
There isn't any straight forward solution that I know of. One workaround is to have the group title TextBlock and CheckBox in different Grid.Row
<TextBlock Grid.ColumnSpan="3" Background="LawnGreen" Grid.Row="1"
HorizontalAlignment="Left" Text="Subtitle 1"/>
<CheckBox Grid.Row="2" HorizontalAlignment="Right" Content="Check"/>
<CheckBox Grid.Row="2" Grid.Column="1" HorizontalAlignment="Right" Content="Check"/>
<CheckBox Grid.Row="2" Grid.Column="2" HorizontalAlignment="Right" Content="Check"/>

Textblock apply linebreak for each item in listbox item template

I have the following xaml code for a list box. Thing is I want to apply a line break at the end of each textblock after it is rendered. Currently I am only getting a linebreak at the end of first item. But I dont get the line break for the remaining items. Please help. Dont worry about the Itemsource for the list box its being bound from the cs.
<ListBox Name="lstreviews" ScrollViewer.VerticalScrollBarVisibility="Auto" Height="470">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition Height="Auto"></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"></ColumnDefinition>
<ColumnDefinition Width="Auto"></ColumnDefinition>
</Grid.ColumnDefinitions>
<TextBlock Grid.Row="0" Grid.Column="0" Text="Name:"></TextBlock>
<TextBlock Grid.Row="0" Grid.Column="1" Text="{Binding author_name}"></TextBlock>
<TextBlock Grid.Row="1" Grid.Column="0" Text="Rating:"></TextBlock>
<TextBlock Grid.Row="1" Grid.Column="1" Text="{Binding rating}"></TextBlock>
<TextBlock Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="2" TextWrapping="Wrap" Width="360" Text="{Binding text}">
<LineBreak></LineBreak>
</TextBlock>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
A line break is just empty space. Just add a bottom margin to your Grid. You are making it too complicated with the line break :).
You just need to specify a margin like was suggested
<TextBlock Grid.Row="0" Grid.Column="0" Margin="10" Text="Name:"></TextBlock>

Telerik Silverlight RadPanelBar Hierarchical Data Template

I need to display the following layout with a telerik PanelBar.
With the code below I was able to achieve everything except the 92% stuff in each panel.
XAML:
<UserControl.Resources>
<DataTemplate x:Key="PanelBarItemTemplate">
<Grid x:Name="grdCategory" ShowGridLines="True">
<Grid.RowDefinitions>
<RowDefinition Height="30"></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="60*"></ColumnDefinition>
<ColumnDefinition Width="40*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Grid x:Name="grdSubCategory" Grid.Column="0" Style="{StaticResource CategoryLeftStyle}" >
<Grid.RowDefinitions>
<RowDefinition Height="20"></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="50*"></ColumnDefinition>
<ColumnDefinition Width="25*"></ColumnDefinition>
<ColumnDefinition Width="25*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding CategoryTitle}" Grid.Row="0" Grid.Column="0"/>
<HyperlinkButton Grid.Row="0" Grid.Column="1" Style="{StaticResource DetailLinkStyle}" Content="Details" Click="Home_Click"></HyperlinkButton>
<TextBlock Text="{Binding Score}" Grid.Row="0" Grid.Column="2"/>
</Grid>
<TextBlock Text="92%" Grid.Column="1" Grid.Row="0" Grid.RowSpan="2" FontSize="32" FontWeight="Bold"/>
</Grid>
</DataTemplate>
<telerik:HierarchicalDataTemplate x:Key="PanelBarHeaderTemplate"
ItemsSource="{Binding SubReports}"
ItemTemplate="{StaticResource PanelBarItemTemplate}">
<TextBlock Text="{Binding CategoryTitle}" />
</telerik:HierarchicalDataTemplate>
</UserControl.Resources>
<Grid x:Name="LayoutRoot">
<telerik:RadPanelBar x:Name="radPanelBar"
ItemTemplate="{StaticResource PanelBarHeaderTemplate}"
IsSingleExpandPath="False" >
</telerik:RadPanelBar>
</Grid>
in the xaml.cs file I provided the ItemsSource.
Can somebody help me out?
All that code works perfectly well for the individual items, but to place the 92% relative to those items (somewhat outside of the sub-items) you would need to also modify the ItemContainerStyle of RadPanelBar. Easiest way is to extract it in Blend, then look for the section under PanelBarItemTopLevelTemplate named ItemsContainer. This is a somewhat crude version, but I made a public property on my item called CalcInt that calculates the sum of a property on the SubReport items so it can be bound from the base item level. My modified code looks like so:
<Grid x:Name="ItemsContainer" Grid.Row="1" Visibility="Collapsed">
<telerik:LayoutTransformControl x:Name="transformationRoot">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<ItemsPresenter/>
<TextBlock Text="{Binding CalcInt}" FontSize="48" Grid.Column="1" HorizontalAlignment="Center" VerticalAlignment="Center" />
</Grid>
</telerik:LayoutTransformControl>
</Grid>
I basically changed it from just containing an ItemsPresenter to a grid with some layout to display my extra-large TextBlock.
If you need a sample of the code or have any other questions feel free to hit me up on Twitter - #EvanHutnick.
Cheers!
-Evan
Hi I think you need to define a converter : IValueConverter and bind to the Label so you can calculate the percentual.
Mario

How to limit column height to another one's?

I have a grid in WPF which is made of 4 rows along 2 columns where column 1 holds an Image control and column 2 holds 4 Textblocks. Problem is, the Image control sizes itself to the Image size and extends the listbox's entry too much [Its in a DataTemplate] and makes everything look distorted. I dont want to manually set a max height/width because i want the Image to size itself to the size of the 4 textblocks that are alongside it. Any ideas?
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Image Source="{Binding Logo, Converter={StaticResource BSConverter}}" Grid.Row="0" Grid.RowSpan="4"
Grid.Column="0" Stretch="Uniform" SnapsToDevicePixels="True"/>
<TextBlock Text="{Binding Name}" Grid.Row="0" Grid.Column="1"/>
<TextBlock Text="{Binding Author}" Grid.Row="1" Grid.Column="1"/>
<TextBlock Text="{Binding Version}" Grid.Row="2" Grid.Column="1"/>
<TextBlock Text="{Binding Description}" Grid.Row="3" Grid.Column="1"/>
</Grid>
</DataTemplate>
Thanks in advance
You can use Grid.IsSharedSizeGroup on the Parent ListBox to make sure all of your items get the same Width for the first Column like this
<ListBox ...
Grid.IsSharedSizeScope="True">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition SharedSizeGroup="GroupA"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
...
For the Image height problem, you could bind Height to the ActualHeight of the Parent Grid with a FallbackValue of 1.0 (to ensure the Height of the Image doesn't effect the Height of the Grid)
<Image Source="{Binding Logo, Converter={StaticResource BSConverter}}"
Grid.Row="0"
Grid.RowSpan="4"
Grid.Column="0"
Stretch="Uniform" SnapsToDevicePixels="True"
Height="{Binding RelativeSource={RelativeSource AncestorType=Grid},
Path=ActualHeight,
FallbackValue=1.0}"/>
Modifying your containers slightly to make use of a StackPanel in conjunction with a Grid and referencing the StackPanel via ElementName binding should provide you the visuals you are looking for...
<DataTemplate>
<Grid HorizontalAlignment="Left" VerticalAlignment="Top">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Image VerticalAlignment="Top" HorizontalAlignment="Right" Margin="0,0,8,0" Source="{Binding Logo, Converter={StaticResource BSConverter}}"
Grid.Column="0" Stretch="Uniform" SnapsToDevicePixels="True"
Height="{Binding ElementName=Contents, Path=ActualHeight}"/>
<StackPanel VerticalAlignment="Top" Name="Contents" Grid.Column="1" Orientation="Vertical">
<TextBlock Text="{Binding Name}"/>
<TextBlock Text="{Binding Author}"/>
<TextBlock Text="{Binding Version}"/>
<TextBlock Text="{Binding Description}"/>
</StackPanel>
</Grid>
</DataTemplate>

Resources