Silverlight: Set MaxWidth of a textblock to containing column width - silverlight

in my Silverlight 4 App, I have a simple 3-columns Grid, that contains 3 Textblocks.
<Grid Background="{StaticResource BrushCharacteristicListBoxItemBackground}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.5*"/>
<ColumnDefinition Width="10"/>
<ColumnDefinition Width="0.5*"/>
</Grid.ColumnDefinitions>
<TextBlock x:Name="TextBlockCharacteristicName" Text="{Binding Property1}" HorizontalAlignment="Left" TextTrimming="WordEllipsis" ToolTipService.ToolTip="{Binding Text}" Margin="6,0,0,0" />
<TextBlock x:Name="TextBlockSeperator" Text="=" Grid.Column="1" />
<TextBlock x:Name="TextBlockCharacteristicValue" Text="{Binding Property3}" Grid.Column="2" HorizontalAlignment="Right" Margin="0,0,6,0" />
</Grid>
The width of the Grid depends on the containing user control. Now I want to cap the size of the first and the third textblock to the current size of their containing column, probably using MaxSize and bind it somehow to the size of the Column of the Grid.
Can anyone here tell me how to do this?
Thanks in advance,
Frank

By default the HorizontalAlignment property of the TextBlock is set to "Stretch" so it will fill the available size of the column its in, regardless of its content. Is that what you want?
Perhaps for some reason you do not want the TextBlock to be as wide as the Column it is in if its content does not need all the available space?
If so set the TextBlock.HorizontalAlignment to "Left". The TextBlock will then be only as wide as it needs to be until it reaches the width of the column, then its width will be constrained by the column.

Related

WPF: Calculating the size of a Grid Column

I have a grid that contains three columns.
<Grid Background="AliceBlue">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="8*" />
<ColumnDefinition Width="5" />
<ColumnDefinition Width="2*" Name="ManualControlsSplit" />
</Grid.ColumnDefinitions>
The first column contains a Grid and a chart.
The second column contains a GridSplitter.
The third column contains a StackPanel which contains a number of TextBlocks, Buttons and Grids containing TextBlocks and Buttons. Text size is dynamic and based on translation resources.
I need to calculate the minimum width that the contents of the third column would ideally like to be able to be drawn into so that the contents are not clipped.
My knowledge of WPF is limited to what I can google so any help would be appreciated.
With layout in WPF, you can allow one if not more of the Grid.Columns to be <ColumnDefinition Width="Auto"/>. This essentially tells WPF to allow as much space as the contained controls want. The use of Auto cascades too, so in StackPanel you refer to, you can make that controls width Auto as well, likewise with the items it contains; if the stack panel merely contains a TextBlock (via some template or whatever), then you can also set this width to Auto and the width with set itself according to the contained text.
<Grid Background="AliceBlue">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="5"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
...
<StackPanel Grid.Column=2
Width="Auto">
<TextBlock Width="Auto"
Text="This is TextBlock"/>
...
</StackPanel>
...
</Grid>
In this case the Text of the TextBlock sets the width of the StackPanel, which in turn sets the width of the 3rd grid column.
I hope this helps.
My WPF XAML setup is as follows (bits removed to keep this simple):
<UserControl ....>
<Grid Background="AliceBlue" Name="TopGrid">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="12*" Name="Graph" />
<ColumnDefinition Width="5" Name="GridSplitter" />
<ColumnDefinition Width="2*" Name="ManualControlsSplit" />
</Grid.ColumnDefinitions>
<Grid Grid.Column="0" Background="AliceBlue"
HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<!-- A Graph and simple controls -->
</Grid>
<!-- GRID SPLITTER -->
<GridSplitter Grid.Column="1" Width="5"
HorizontalAlignment="Stretch" Name="Splitter" />
<Label Grid.Column="1" Content="⁞" Foreground="White"
Background="DarkGray"
VerticalAlignment="Center" FontSize="26" FontWeight="Bold"
IsHitTestVisible="False"/>
<!-- end GRID SPLITTER -->
<StackPanel Grid.Column="2" Grid.Row="0" Margin="5"
Name="TemperatureControls">
<!-- Load of Controls -->
</StackPanel>
</Grid>
</UserControl>
To calculate the desired width I use the following code:
// get my UserControl object
var manualControlView = userControl as HeatingController.Views.ManualControlView;
// Query the current width of THIRD column
double actualWidth = manualControlView.ManualControlsSplit.ActualWidth;
// Set up a BIG size (this has to be bigger size than the contents of the
// THIRD column would ever need)
Size size = new Size(400, manualControlView.TopGrid.ActualHeight);
// Ask WPF layout to calculate the Desired size.
manualControlView.TemperatureControls.Measure(size);
double width = manualControlView.TemperatureControls.DesiredSize.Width;
if (actualWidth <= width)
{
// Too small - do something
}
else
{
// big enough - do something else.
}
The variable 'width' now contains the value I wanted to calculate.

WPF/XAML Layout of two Labels containing different length text whilst maintaining equal size Font Scaling

I'm trying position two labels, one right next to the other (with a small amount of spacing).
e.g.
Label 1 Label 2
the content of each label will always be different, most often Label 2 will have more characters but I want the content to scale as the window is resized and I want the font sizes in Label 1 and Label 2 to remain consistent.
I don't care if the contents of Label 2 are cropped if too long.
I've tried using a grid with two columns and placed the Label inside a ViewBox:
<Viewbox Margin="0,0,0,0" VerticalAlignment="Top" HorizontalAlignment="Left">
<Label Margin="0,0,0,0" Content="{Binding Path=Suburb}"/>
</Viewbox>
Problem with this is, the positioning is never right and the font sizes don't remain consistent.
What is the best layout method to achieve this? Can I synchronise the font sizes through binding? I've tried binding Label 2's FontSize property to Label 1's FontSize but that doesn't work as it just returns 12 every time no matter how big/small the font really is (I'm presuming the actual FontSize isn't being calculated because the Label is inside a ViewBox).
Any suggestions?
Thanks
You can use the following approach:
<Viewbox VerticalAlignment="Top">
<DockPanel>
<TextBlock Text="Second" DockPanel.Dock="Right" />
<TextBlock Text="First" />
</DockPanel>
</Viewbox>
Note that the second label would never get cropped since the Viewbox would allow the content to render to any size and then scale it. You can specify MaxWidth on the second TextBlock which would limit its size in pixels.
Instead of a DockPanel you can use a Grid with different ColumnDefinitions to achieve the same effect.
The important thing is that they're all in the same Viewbox (which, consequently, doesn't synchronize the FontSize but performs a visual scaling of everything it contains).
The following markup seems to be ok:
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Viewbox>
<Label Content="Label 1" Width="{Binding ActualWidth, ElementName=label2}"/>
</Viewbox>
<Viewbox Grid.Column="1">
<Label Name="label2" Content="Label 2 Label 2 Label 2"/>
</Viewbox>
</Grid>
Im not 100% sure of what 'content scale as the window resizes' and 'font sizes remain consistent' actuall means, but I guess you want each label to trim depending on available space.
So why not use TextBlock as below
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding Path=Suburb}" TextWrapping="NoWrap" TextTrimming="CharacterEllipsis" Margin="0,0,5,0" />
<TextBlock Text="{Binding Path=Area}" TextWrapping="NoWrap" TextTrimming="CharacterEllipsis" Grid.Column="1"/>
</Grid>
I realize this question is old, but one of the more correct ways to do this is to use Runs.
Runs are sections of text within a TextBlock.
<TextBlock Margin="0,0,0,0" VerticalAlignment="Top" HorizontalAlignment="Left">
<Run Text="{Binding Suburb}" />
<Run Text="{Binding Area}" />
</TextBlock>
Keep in mind that everything within a TextBlock is whitespace-sensitive, so if you wanted to have two Runs back-to-back without any space in between, you would do something like this:
<TextBlock Margin="0,0,0,0" VerticalAlignment="Top" HorizontalAlignment="Left">
<Run Text="Foo" /><Run Text="bar" />
<!-- Prints 'Foobar' -->
</TextBlock>
It's similar to how HTML is rendered, if there is whitespace between the tags, a single space is rendered on the page between those elements. This rule only applies to items within a TextBlock, not the entire XAML page.

Vertical gridlines in a ListView

I've got a WPF ListView that I'm using as a GridView. Is there any way I can get vertical gridlines in there?
The ListView has a MinHeight specified, so I'd like the GridLine to go all the way to the bottom of the grid, so it'll fill the empty space.
This seems to be a rather tricky problem. Is is possible to solve?
This is how I do it.
<ListView Grid.IsSharedSizeScope="True"
ItemsSource="{Binding Path=MyList,FallbackValue='12345'}" >
<ListView.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="3*" SharedSizeGroup="col0"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="1*" SharedSizeGroup="col2"/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Margin="10,0"
Text="{Binding Path=Name, FallbackValue='Name goes here'}"/>
<Border Grid.Column="1" Margin="0,-2"
BorderBrush="DarkGray"
BorderThickness="0,0,1,0" />
<TextBlock Grid.Column="2" Margin="10,0"
Text="{Binding Path=DateModified, FallbackValue='Date goes here'}"/>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
The SharedSizeGroup and Grid.IsSharedSizeScope properties are key to this way of doing it. The Margin="0,-2" property on the Border makes sure the dividing line looks like a continuous vertical line. If you add vertical margin to the two textblocks, you will need to increase the negative vertical margin of the border.
This will take care of lining things up into two uniformly sized columns with a vertical line between them, but it won't extend into areas where there is no data. A ListView might not be the best option if you want that functionality.
Adding some data to the MyList property in the ViewModel gives this as a result:
Of course, the MyList property needs to be a list or collection of a class that has Name and DateModified as properties.

WPF ListView TextBlock TextWrapping

I am building a ListView that needs to have five columns - the first one needs to have text that can be any length and needs to wrap whenever the window size changes (in addition to changing the row height so the wrapped text is visible) and the other four columns are a static width of 45. I've been searching for hours on this and every solution I come across either requires a static width or doesn't work.
Solutions tried:
Column widths of auto, 1*, 2*, etc. (settings ignored)
DockPanel (settings ignored)
WrapPanel (ignored)
Setting Width to RelativeSource of parent for ActualWidth (ignored)
Any ideas? It seems like a significant number of people have had this same problem, but I would highly prefer to not have to go the static width route for this column. Especially since the content just gets cut off when I do that anyway (even with height="Auto" for the row). The width of the overall window could be as small as 1024, but could also be 1600+ which is why I want dynamic sizing. That way smaller screens will have the content wrap and larger screens will just show the one line since the content fits.
Here is the XAML:
<ListView.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition Width="45" />
<ColumnDefinition Width="45" />
<ColumnDefinition Width="45" />
<ColumnDefinition Width="45" />
</Grid.ColumnDefinitions>
<!-- This is the TextBlock that needs to wrap its content (and
change the height of the row (so the full content is still
visible) to whatever the available space is, but should not
make overall ListView wider than the parent's width. -->
<TextBlock Text="{Binding Content}" Padding="20,6,6,6" />
<!-- These four blocks will have other content eventually, but only need
to be 45 wide -->
<TextBlock Text="X" Grid.Column="1" HorizontalAlignment="Center" />
<TextBlock Text="X" Grid.Column="2" HorizontalAlignment="Center" />
<TextBlock Text="X" Grid.Column="3" HorizontalAlignment="Center" />
<TextBlock Text="X" Grid.Column="4" HorizontalAlignment="Center" />
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
Not so easy...but it can be done.
I wrote a solution for you. In short, use Expression Blend to create a copy of the ListView Template and delete the ScrollViewer surrounding the ItemPresenter.
Here is a more indepth explanation:
How to have the TextBlock in a left column of a Grid in a ListView Template expand or shrink with text wrapping?
<ListView HorizontalContentAlignment="Stretch" ScrollViewer.HorizontalScrollBarVisibility="Disabled">
<ListView.ItemTemplate>
...
</ListView.ItemTemplate>
</ListView>
I'd add TextWrapping="Wrap" to the first TextBlock element.

Image Stretch programmatically in WPF

In a WPF Application using XAML,
I created a stackpanel(width 1030) and I have 2 Images.
1. imgClient width = 784 Height = 66 and 2. imgClientExtra width =1 and Height = 66
imgClientExtra will be right end and imgClient will start at leftend.
so, the images will fit to 784 + 1 when the application is not running, the total image width is 785(784+1)..
but, wen the application is running.. the image has to stretch to 1030... with imgClientExtra will be at 1030 and imgClient will have to stretch to 1029 only..
I used stretch.fill ... but didn't work.
Currently I am using this way... is this needs to be modified?
<StackPanel Name="stkpnlHeader" Margin="0,0,0,0" Width="1254.662" Height="auto" HorizontalAlignment="Left" VerticalAlignment="Top">
<StackPanel Name="imgStkPnl"Orientation="Vertical" Width="1253.511" HorizontalAlignment="Left">
<Image Name="imgClientPhoto" HorizontalAlignment="Left" VerticalAlignment="Top" Width="784" Height="66"
Source="D:\ehtmp_top_left.gif" Stretch="Fill" StretchDirection="Both">
</Image>
<Image Name="imgExtraImg" Width="1" Height="66" Margin="0,-66,0,0" HorizontalAlignment="Right"
Source="D:\ehtmp_top_right.gif"
></Image>
</StackPanel> </StackPanel>
Change from a stackpanel to a Grid.
Set the Grid.Column definitions.
Create 2 column definitions
You can use Width to set a 'ratio' width.
For example, colA Width="5*" and colB Width="3*" means that colA gets 5/8 of the grid and colB gets 3/8 of the grid.
Combine this concept with also setting MinWidth and MaxWidth and you should be good to go.
Also, when setting widths in code, you often need to check an existing controls width by using the 'ActualWidth' property rather than 'Width' (which sometimes returns NaN).
I would think that a DockPanel in your case would work, since it automatically stretches the last element (I didn't try building this code so let me know if it doesn't work):
<DockPanel Height="66">
<Image Name="imgExtraImg" Source="D:\ehtmp_top_right.gif" DockPanel.Dock="Right"/>
<Image Name="imgClientPhoto" Source="D:\ehtmp_top_left.gif"/>
</DockPanel>
<Grid HorizontalAlignment="Left" Height="66" Name="imgGrid">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"></ColumnDefinition>
<ColumnDefinition Width="Auto"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="66"/>
</Grid.RowDefinitions>
<Image Name="imgClientPhoto" Grid.Column="0" Stretch="Fill"Source="D:\eHTMP\Exclusively_My_Work\UI_Application\Images\ehtmp_top_left.gif" ></Image>
<Image Name="imgExtraImg" Grid.Column="1"Source="D:\eHTMP\Builds\output\WPF_Example\UI_eHTMP\UI_eHTMP\Icons\ehtmp_top_right.gif"></Image></Grid>

Resources