Wrapping text within a chain of controls - wpf

Here's an image of what I'm trying to achieve within a grid view column:
The text is wrapping as expected and the closing double-quote image is displayed correctly. But if I reduce the column width fractionally I get this:
Notice how the closing double-quote image is being clipped.
The essence of the XAML I'm using is shown below, although it is merely the latest variant in a set of equally inadequate attempts.
<DockPanel LastChildFill="False" MinWidth="50">
<ContentControl
Content="{StaticResource DoubleQuotesOpenImage}"
VerticalAlignment="Top"
MinWidth="16"
DockPanel.Dock="Left" />
<TextBlock
FontSize="13"
TextWrapping="Wrap"
Text="{Binding TextRepresentation}"
VerticalAlignment="Center"
DockPanel.Dock="Left" />
<ContentControl
Content="{StaticResource DoubleQuotesCloseImage}"
MinWidth="16"
VerticalAlignment="Bottom"
HorizontalAlignment="Left"
DockPanel.Dock="Left" />
</DockPanel>
So the question is this: how can I ensure that both (a) the text block wraps in accordance with column width changes, and (b) the closing double-quote symbol is never clipped?
UPDATE
There's one key thing I should have included: the closing double-quote should be flush with the right-hand edge of the TextBlock. It is not acceptable to have the quote image permanently aligned with the right edge of the column.

You could replace the DockPanel with a Grid with 3 columns in a StackPanel:
<Grid HorizontalAlignment="Left">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<ContentControl
Content="{StaticResource DoubleQuotesOpenImage}"
VerticalAlignment="Top"
Grid.Column="0" />
<TextBlock
FontSize="13"
TextWrapping="Wrap"
Text="{Binding TextRepresentation}"
Grid.Column="1" />
<ContentControl
Content="{StaticResource DoubleQuotesCloseImage}"
VerticalAlignment="Bottom"
Grid.Column="2" />
</Grid>
The Width="Auto" setting ensures that the first and third column have the width of the contained element, the middle column would get the rest of the total width.

Reverse the order that you are adding items to your DockPanel so that the last item added is your TextBlock. Then remove the LastChildFill property, and set DockPanel.Dock of your closing quote to Right
<StackPanel>
<DockPanel MinWidth="50">
<ContentControl
Content="{StaticResource DoubleQuotesOpenImage}"
VerticalAlignment="Top"
MinWidth="16"
DockPanel.Dock="Left" />
<ContentControl
Content="{StaticResource DoubleQuotesCloseImage}"
MinWidth="16"
VerticalAlignment="Bottom"
HorizontalAlignment="Left"
DockPanel.Dock="Right" />
<TextBlock
FontSize="13"
TextWrapping="Wrap"
Text="{Binding TextRepresentation}"
VerticalAlignment="Center"
DockPanel.Dock="Left" />
</DockPanel>
</StackPanel>
This will make it so the quotes are positioned first, then your Text will take up all remaining space
You could also use a Grid like Clemens' suggested, although I presonally prefer to use a DockPanel because I hate writing column definitions :)

Related

How to make changing number of columns fill entire width and center horizontally in WPF?

I have a Grid with 3 Columns in WPF. Each column is filled with a Vertical Stackpanel. The first column (and its content) is always visible. the 2. and 3. column are linked to checkboxes.
And i basically want to have the columns fill the entire horizontal space while also having their content centered (the content of each column is the same) . So for example if only the first column is used, its content should be centered over the whole grid width. If the 2. column is used aswell, The whole grid space should be equaly divided for both columns and their content should be centered inside. With also the third column used, the space would be divided by 3 of course.
My idea for now was the following but i cant get the stackpanels to be centered/fill out the horizontal space.
<CheckBox Style="{StaticResource MaterialDesignCheckBox}" Content="2. Durchgang" IsChecked="{Binding RVPDGsecondround}" Margin ="0,0,0,0"/>
<CheckBox Style="{StaticResource MaterialDesignCheckBox}" Content="3. Durchgang" IsChecked="{Binding RVPDGthirdround}" Margin ="0,0,0,0"/>
<Grid HorizontalAlignment="Stretch">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<StackPanel Orientation="Vertical" HorizontalAlignment="Center" Grid.Column="0">
<TextBlock Text="Durchgang 1" Style="{StaticResource MaterialDesignBody2TextBlock}"/>
</StackPanel>
<StackPanel Orientation="Vertical" HorizontalAlignment="Center" Grid.Column="1" Visibility="{Binding RVPDGsecondround, Converter={StaticResource b2v}}">
<TextBlock Text="Durchgang 2" Style="{StaticResource MaterialDesignBody2TextBlock}"/>
</StackPanel>
<StackPanel Orientation="Vertical" HorizontalAlignment="Center" Grid.Column="2" Visibility="{Binding RVPDGthirdround, Converter={StaticResource b2v}}">
<TextBlock Text="Durchgang 3" Style="{StaticResource MaterialDesignBody2TextBlock}" />
</StackPanel>
</Grid>
A UniformGrid may be better suited than a Grid:
<UniformGrid Rows="1" HorizontalAlignment="Stretch">
<StackPanel HorizontalAlignment="Center">
<TextBlock Text="Column 1"/>
</StackPanel>
<StackPanel HorizontalAlignment="Center" Visibility=...>
<TextBlock Text="Column 2"/>
</StackPanel>
<StackPanel HorizontalAlignment="Center" Visibility=...>
<TextBlock Text="Column 3"/>
</StackPanel>
</UniformGrid>

Fit a Textbox and a button in DataGrid Cell

I am trying to fit Textblock and a button in DataGrid Cell. The Textblock holds a portion of my text and when I click the button a dialog is display. I general my code looks like the one below
<DataGridTemplateColumn Header="Message" Width="Auto" MinWidth="60">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<StackPanel Orientetion="Horrizontal">
<TextBlock MinWidth="200" TextTrimming="CharacterEllipsis" Text="{Binding Text}" />
<Button DockPanel.Dock="Right" Width="90" Margin="1" />
</StackPanel>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
I want the Button to be always at righter side of the cell and its width to be fixed. The TextBlock needs to be variable, for example when I resize the window, and so the DataGrid, the TextBlock should stretch also.
The problem is that, I can not achieve this behaviour / view. The TextBlock varies on each DataGrid line and in some case the button is not at the righter of the cell.
I tried to change the StackPanel to Grid or DockPanel but still I can not get the desirable result.
Using Grid
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition MinWidth="100" Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" TextTrimming="CharacterEllipsis" Text="{Binding Text}" />
<Button Grid.Column="1" Margin="1" />
</Grid>
Any thoughts to share?
StackPanel doesn't really have the concept of aligning to the right. It stacks the elements as close as it can. You can get around this in different ways but in this case, use a DockPanel instead:
<DockPanel>
<Button DockPanel.Dock="Right" Width="90" Margin="1" />
<TextBlock MinWidth="200" TextTrimming="CharacterEllipsis" Text="{Binding Text}" />
</DockPanel>
Note that I moved the TextBlock to be the last child element of the DockPanel. DockPanel, after laying out the other child elements, allocates the remaining space to the last child element (unless you specify LastChildFill=false). In this case, we want the TextBlock to take up the remaining space.
UPDATE: based on the comments above, in addition to changing the panel type to a DockPanel (or Grid), you can use DataGridTemplateColumn.Width to a fixed value instead of Auto. This would make the column load with the specified with but the user can still modify the column with if they want to:
<DataGridTemplateColumn Header="Message" Width="60" MinWidth="60">
I'd set a static value to the DataGridTemplateColumn.Width--it can help with rendering performance. Set the size on your buttons too, so it doesn't size to fit text.
This works for me (I used the border for visualization purposes):
<Window ...
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<DataTemplate DataType="{x:Type local:Model}"
x:Key="VmItem">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Border BorderBrush="Black" BorderThickness="1">
<TextBlock Grid.Column="0" TextTrimming="CharacterEllipsis" Text="{Binding Original}" />
</Border>
<Button Grid.Column="1" Margin="1" Content="{Binding Encoded}" MinWidth="90" MaxWidth="90"/>
</Grid>
</DataTemplate>
</Window.Resources>
<Grid>
<DataGrid ItemsSource="{Binding Items}" AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTemplateColumn Header="Message" CellTemplate="{StaticResource VmItem}" Width="300" MinWidth="100"/>
</DataGrid.Columns>
</DataGrid>
</Grid>
</Window>
Proof:

TextBlock not wrapping in Grid

I have the following XAML which is meant to show an Image and two TextBlocks on top of eachother beside it:
<StackPanel Orientation="Horizontal" >
<Image Source="{Binding CoverArt}" Height="150" />
<StackPanel Orientation="Vertical">
<StackPanel>
<TextBlock FontSize="30" Text="{Binding Title}" TextWrapping="Wrap" />
</StackPanel>
<Grid Width="auto">
<TextBlock FontSize="22" Text="{Binding Summary}" TextWrapping="Wrap" />
</Grid>
</StackPanel>
</StackPanel>
My problem is getting the text to wrap. I've tried using a Grid and assigning the columns' width but it didn't work. Neither did setting the width values to auto. The only thing that works is hard-coding the width, but I do not want that. Thanks.
A Stackpanel will stretch to the size of its content, so it's not what I would use. Use a grid, as explained in the following posts:
TextBlock TextWrapping not wrapping inside StackPanel
Text in StackPanel doesn't wrap (wp7)
TextBlock inside stackpanel does not wrap text
A quick comparison:
Before with stackpanel
After with one grid (You might want to rearrange the elements a bit)
The code for the last segment:
<pre>
<Grid Grid.Row="1">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Ellipse Fill="red" Width="150" Height="150" />
<StackPanel Grid.Column="1" Orientation="Vertical">
<StackPanel>
<TextBlock FontSize="30" Text="basdljhba dnaiks d., kasndca casn oiäc cas lkcnaso ca dxjwöbdq wkjöbdqw dkjwqb " TextWrapping="Wrap" />
</StackPanel>
<Grid Width="auto">
<TextBlock FontSize="22" Text="dewdewdewdewdewewd" TextWrapping="Wrap" />
</Grid>
</StackPanel>
</Grid>
Did you try setting the width of the columns to fractions instead? width="2*" That will give you some boundaries without a pixel set size. Some way or another you need to set a constraint for the container. If you have two columns and no size is set they will get 50% each. 2* will make give that column 2/3 of the total column with, see example below.

StackPanel expanding outside size of parent grid

I'm pretty new with WPF, so apologies if I'm missing something obvious. I have this template that is bound to items in an obs. collection. I'm trying to get it so that the 2nd column, the "test test..." part has a variable width that fills all the available space in the parent grid.
What I'm finding though, is that my code automatically shows all the text for that "test test..." text box as opposed to just binding to the available space in the grid, and instead creates the scroll bar that you see below.
I instead, want that "test test" to be cut off so that everything else fits so that no scroll bar appears (that when, if the user resizes the screen then that "test test..." textbox will automatically resize to fit the new space). Is there a way to do that?
My code for that template is as follows:
<DataTemplate x:Key="MainTemplate">
<Grid Margin="4" ClipToBounds="True">
<Grid.Resources>
<local:BooleanToHiddenVisibility x:Key="boolToVis"/>
</Grid.Resources>
<StackPanel Orientation="Vertical" ClipToBounds="True">
<Grid Width="Auto" >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="25"/>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="60" />
<ColumnDefinition Width="40" />
<ColumnDefinition Width="60" />
<ColumnDefinition Width="40" />
<ColumnDefinition Width="60" />
<ColumnDefinition Width="40" />
<ColumnDefinition Width="40" />
</Grid.ColumnDefinitions>
<CheckBox Grid.Column="0" Name="checkViewTextBox"/>
<TextBlock Grid.Column="1" Text="{Binding OriginalQuote}" FontWeight="Bold" TextTrimming="WordEllipsis" FontStyle="Italic" ClipToBounds="True"/>
<TextBlock Margin="10,0,0,0" Grid.Column="2" Text="plane :" FontWeight="SemiBold" Width="60"/>
<TextBlock Margin="5,0,0,0" Grid.Column="3" Text="{Binding Mid}" Width="40"/>
<TextBlock Margin="10,0,0,0" Grid.Column="4" Text="data2 :" FontWeight="SemiBold" Width="60"/>
<TextBlock Margin="5,0,0,0" Grid.Column="5" Text="{Binding MidTwo}" Width="40"/>
<TextBlock Margin="10,0,0,0" Grid.Column="6" Text="data3:" FontWeight="SemiBold" Width="60"/>
<TextBlock Margin="5,0,0,0" Grid.Column="7" Text="{Binding MidThree}" Width="40"/>
<Button Margin="10,0,0,0" Content="History" Grid.Column="8" Click="History_Click" Width="40"/>
</Grid>
<StackPanel Orientation="Horizontal" Visibility="{Binding Path=IsChecked, ElementName=checkViewTextBox, Converter={StaticResource boolToVis}}">
<StackPanel.Resources>
<Style BasedOn="{StaticResource tbstyle}" TargetType="{x:Type TextBlock}" />
</StackPanel.Resources>
<!--Other stuff thats working ok-->
</StackPanel>
</Grid>
</DataTemplate>
Any help is much appreciated!
P.S. I've been adding random proprieties hoping one will work, so if looks like I have random things on there, that's probably why....
Well, not sure it will help you but some words about WPF layout.
It has two steps: measure and arrange.
At the first stage, the control tries to calculate its desired state. StackPanel asks its children about their desired sizes. It does not limit their size. (TextBlock with the binding to OriginalQoute has no explicitly set width!)
At the second stage, control is arranged.
Stack panel is allowed to occupy the whole left space of the column but it arranges its children as if its size was unlimited, so TextBlock shows the text completely.
The question is how to limit the size of the TextBlock?
Try binding
<TextBlock Width="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=StackPanel}, Path=ActualWidth}"/>

Column width issue when displaying table of data in xaml

I'm attempting to display a table of data which looks like this on Windows Phone 7 (thus I don't have the DataGrid control:
(The columns are: Rank, Score, Win-Loss, Name.)
7 43 22-7 Aaron
2 13 4-7 Beth
5 42 3-1 Clark
And so on. I have used a ListBox with an ItemTemplate to query the values and print them out, with a Grid to format the list. However, each grid entry is separate! I want the columns to all line up, but when an element size is not the same size, it isn't aligned.
This is the code I am using:
<ListBox x:Name="MyListBox" ItemsSource="{Binding AllPlayers}">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Margin="10,0,10,0" Text="{Binding Rank}"/>
<TextBlock Grid.Column="1" Margin="10,0,10,0" Text="{Binding Score}"/>
<StackPanel Grid.Column="2" Margin="10,0,10,0" Orientation="Horizontal">
<TextBlock Grid.Column="2" Text="{Binding Wins}"/>
<TextBlock Grid.Column="2" Text="-"/>
<TextBlock Grid.Column="2" Text="{Binding Losses}"/>
</StackPanel>
<TextBlock Grid.Column="3" Margin="10,0,10,0" Text="{Binding Name}"/>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Is there a better way to do this? I could set the pixel width on the "Grid" column manually, but I'd rather have it auto-figure out the width, if possible.
Since WP7 supports one fixed screen pixel width, you can set exact width for each column. What width to use - that's up to you, depending on the content, but that would be the way to keep them all one size.

Resources