<TextBlock Text="Random" width="*"/> gives an error - wpf

I know for certain objects, the width can be specified as width="*", so that the width is as large as possible. However when I tried it with TextBlock, it gave an error.
Is there any way of specifying the width of a textblock to be as large as possible?

"*" is only valid for grid row/column sizing, AFAIK. You want HorizontalAlignment="Stretch".
UPDATED: Since your comment indicates you're doing this in a ListBox, you also need to set the ListBoxItem's HorizontalContentAlignment to "Stretch". Put this in your element:
<ListBox ...>
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
</Style>
</ListBox.ItemContainerStyle>
</ListBox>

The "*" syntax is only supported by RowDefinition and ColumnDefinition in the Grid. You can use "Auto" in XAML to have it automatically determine the best Width/Height. Or in code-behind you can assign the Width/Height to double.NaN.

Have you tried placing the TextBox within a panel type that autoexpands (i.e. Grid). There is a fairly decent example here.

Related

How do I stop a WPF DataGrid TextColumn cell from growing taller due to newlines?

Background:
I have a DataGrid with multiple TextColumns. One column is read-only, and bound to the text of a TextBox that's outside of the DataGrid. This TextBox is a multi-line textbox, meaning that AcceptsReturn = true and TextWrapping = Wrap.
Problem:
When a user enters multiple lines in the multi-line TextBox, the bound DataGridCell (and its row) vertically grow so all the text appears.
Questions:
Is there a way to get a vertical scrollbar to appear within the cell, when multiple lines should appear?
Generally, what are other techniques to circumvent the growth of a DataGridCell, and its row, due to multi-line content?
Research:
I know I can prevent a DataGridRow's growth by forcibly setting its Height. However, that doesn't trigger a scrollbar.
And I confirmed that WordWrap is off for the TextBlock within the DataGridCell.
Thanks
Have you tried to use a DataGridTemplateColumn and a ScrollViewer inside it? For example:
<DataGridTemplateColumn Header="MyText">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ScrollViewer MaxHeight="30" VerticalScrollBarVisibility="Auto">
<TextBlock TextWrapping="Wrap" Text="{Binding YourText}" />
</ScrollViewer>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
I ended up being a bit flexible with my requirements and came up with this style:
<Style
TargetType="{x:Type DataGridCellsPresenter}"
BasedOn="{StaticResource {x:Type DataGridCellsPresenter}}"
>
<Setter
Property="MaxHeight"
Value="25"
/>
</Style>
By setting MaxHeight on my DataGridCellsPresenters, I can trigger vertical scrollbars without directly interfering with row heights. And I can apply it consistently across my application, rather than per column.

WPF ComboBox: How to you utilise a generic ItemContainerStyle with binding

I want to utilise a generic style for my ComboBoxItem content and have the text content bound to different properties on my underlying class. So this is the best I can come up with but the bindings are hard coded. So for every class bound to a combobox using this ItemContainerStyle I'd have to implement a "MainText" and "SubText" property.
Question is, is there a way to have the binding soft coded so where the style referenced from a combobox I can specify which string properties of the underlying class are used.
<Style TargetType="{x:Type ComboBoxItem}" x:Key="ComboBoxItemStyleA1">
<Setter Property="Template" >
<Setter.Value>
<ControlTemplate TargetType="ComboBoxItem">
<Border x:Name="BB" Padding="8,3,8,3" Background="DarkGreen">
<StackPanel Margin="0">
<TextBlock Foreground="White" FontSize="16" Text="{Binding MainText}"/>
<TextBlock Foreground="White" FontSize="8" Text="{Binding SubText}"/>
</StackPanel>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Background" TargetName="BB" Value="#FF256294"/>
<Setter Property="Foreground" Value="White"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
And to use the style...
<ComboBox ItemsSource="{Binding Items}"
ItemContainerStyle="{StaticResource ComboBoxItemStyleA1}" />
Further to dowhilefor's answer (many many thanks - WPF is great but sure is a voyage of discovery)
I used a data template to define the cell look originally - and then wanted to use a comboboxitem based style with a control template defined where I could specify the onmouseover triggers. i.e. these were to change the background color etc.
Butj
a) I couldn't remove the Border section of the template above - the triggers are tied to it by targettype="BB". so I kind of wanted to get the trigger bound to the container such that the datatemplate would pick up the background from the template binding but not sure how to get this plumbed in.
b) I realised that even if I comment out the BB specific bindings on the triggers just to get it to run - the combobox doesn't find and use the DataTemplate I defined. Seems that defining the controltemplate in my comboboxitemstyle stops it picking up the datatemplate.
I hope I make sense here - bottom line is I just want a style that I can apply with triggers in that set the background color of my cobobox item. It should not know what the data is - i.e. be able to plug in a datatemplate that will (template ?) bind to this background color.
Many thanks for the very fast response.
btw I'm using ItemContainerStyle in conjuction with ItemTemplate so I can have a different representation in the dropdown to what appears in the combobox list
First of all don't use the ItemContainerStyle for that. To be more precise never have any Bindings to the datacontext inside an ItemContainerStyle, at least try not. Why? The Style is used for defining the appearance of a combobox item disregarding the content. If you want to define how the content should look like, you use a DataTemplate for that. There are multiple ways to tell the combobox where he can find a proper DataTemplate for the Data you supply. Checkout the property ItemTemplate, ItemTemplateSelector and search for implicit styles, to find out more about them.
So to your problem, create one ItemContainerStyle for you combobox (if you really have to anymore) which doesn't care about the object that will be put into. Now you still need to provide multiple DataTemplates each and everyone with the knowledge of the data object that you want to be templated. There is no way around it, there is no soft databinding. Just try to keep your templates small and simple. If for some reason you need the exact same template, but your properties are just named differently, why not use a wrapper item for the DataContext with the properties Caption, Description and you can decide in code how these properties are filled with your real data wrapped into this object.

WPF: Programatically adding ListViewItems that expand to the full width of their containing ListView

I have defined a custom ListViewItem contorl in XAML, which we'll call Item.xaml. These custom items are added to a list view using ListView.Items.Add().
How can I add these items so that they will expand horizontally to take up the entire width of their containing ListView? Currently they always remain their original width.
ChrisWue's answer seemed to work but then I noticed that if I had enough ListViewItems to cause the list to scroll horizontally, the items that were invisible before scrolling down did not stretch horizontally.
I found this MSDN thread that gives the correct approach:
<ListView Name="ListView" ScrollViewer.HorizontalScrollBarVisibility="Disabled">
<!-- Stretch the contents to match the columns' width: -->
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
</Style>
</ListView.ItemContainerStyle>
...
The ListView has a HorizontalContentAlignment you need to set to Stretch:
<ListView HorizontalContentAlignment="Stretch" ... >

wpf combobox padding

This is a simple question
How do you remove the space between the content of a combobox and the border of it. E.g. If the selection of a combobox is "Selection 1" then the "S" is drawn at the very top left of the ComboBox control with no whitespace spacing between it and top left portion of the control.
I did this
<ComboBox Padding="0"/>
Even this:
<ComboBox.ItemContainerStyle>
<Style TargetType="ComboBoxItem">
<Setter Property="Padding" Value="0"/>
</Style>
</ComboBox.ItemContainerStyle>
The specified ComboBox above is within a ListView GridViewColumn. Maybe that's messing with something.
This doesn't remove the padding. Any ideas?
You can't. At least, not with the default template. You'd have to write your own. The default template includes this:
<DockPanel Margin="2">
<TextBox .../>
</DockPanel>
That'll be a hard-coded margin. About the best you could do with the default template is use a negative padding to offset the hard-coded margin:
<ComboBox Padding="-2">
<ComboBoxItem >Selected</ComboBoxItem>
</ComboBox>
In Expression Blend this is trivial:
Right-click the ComboBox and select Edit Control Parts (Template) - Edit A Copy.
Remove the Margin="2" from the beginning of the template.

Synchronizing WPF control widths in a WrapPanel

I have this case
<WrapPanel>
<CheckBox>Really long name</CheckBox>
<CheckBox>Short</CheckBox>
<CheckBox>Longer again</CheckBox>
<CheckBox>Foo</CheckBox>
<Slider MinWidth="200" />
</WrapPanel>
I want all the CheckBoxes inside the WrapPanel to be the same width.
Adding the following almost accomplishes the desired effect
<WrapPanel.Resources>
<Style TargetType="CheckBox" BasedOn="{StaticResource {x:Type CheckBox}}">
<Setter Property="MinWidth" Value="75" />
</Style>
</WrapPanel.Resources>
However, I do not want to hardcode a specific width, rather let the largest CheckBox set the width (the above also fails if any width > 75).
The Slider is independent and should be allowed to be larger than the CheckBoxes.
I do not want to use a Grid (with IsSharedSizeScope) since I do not want a hardcoded number of columns.
This article presents an interesting solution, but it would be nice to solve the problem without creating a custom control or using C# code.
What is the best way to do this, preferrably in XAML only?
I originally looked at this using IsSharedSizeGroup but hit a roadblock with making it dynamically apply to things instead of explicitly wrapping items. In this case, creating an AttachedProperty in code or another code based solution may in the long run be better then a XAML only approach. However, to create a purely XAML solution we can make use of the SharedSizeGroup property on a ColumnDefinition to share the sizes of each element and then use set the IsSharedSizeScope property on the WrapPanel. Doing so will make all of the contents in the WrapPanel with the same SharedSizeGroup share their width for columns and height for rows. To wrap the ComboBoxes and possibly ComboBoxes that are not currently in the XAML but will be added to the WrapPanel, we can create a Style and re-template the ComboBox to bassicly wrap it with a Grid.
<WrapPanel Grid.IsSharedSizeScope="True">
<WrapPanel.Resources>
<Style TargetType="{x:Type CheckBox}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type CheckBox}">
<Grid Background="LightBlue">
<Grid.ColumnDefinitions>
<ColumnDefinition SharedSizeGroup="WrapPannelGroup" />
</Grid.ColumnDefinitions>
<CheckBox Style="{x:Null}"
IsChecked="{TemplateBinding IsChecked}">
<!--Other TemplateBindings-->
<CheckBox.Content>
<ContentPresenter />
</CheckBox.Content>
</CheckBox>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</WrapPanel.Resources>
<CheckBox>Really long name</CheckBox>
<CheckBox>Short</CheckBox>
<CheckBox IsChecked="True">Longer again</CheckBox>
<CheckBox>Foo</CheckBox>
<Slider MinWidth="200" />
</WrapPanel>
Here we are re-templating all CheckBoxes without a style inside the WrapPannel to instead be CheckBoxes surrounded by a Grid. However, because of this we need to re-bind all of the CheckBoxes properties that we want to maintain. While that could become burdensome, it also allows for a pure XAML approach.
You can add a property or a converter that does the needed work, then bind each column's width to it. The property or converter can access the entire list of items, finding the widest one, and returning the desired width for all elements.
The best way to do this is to use a CustomControl like the article you posted.
Any solution you come across is going to have to iterate through the list of items and find the maximum width during the measure phase.
Any sort of XAML-only answer would have to be provided OOTB (e.g. IsSharedSizeScope), or would leverage some sort of multi-binding to link the items together. Thus any sort of XAML answer would be full of markup which makes it more verbose (and less elegant).
The only modification that I see to the CodeProject article you posted is adding the ability to "turn-off" consideration of certain elements (like your slider). This could be done as an additional attached property.

Resources