Stretch WPF ListView Template layout [duplicate] - wpf

I want to have the ListItems to extend with their orange background the full width of the Listbox.
Currently they are only as wide as the FirstName + LastName.
I've set every element I can to: HorizontalAlignment="Stretch".
I want the background of the ListboxItems to expand as the user stretches the Listbox so I don't want to put in absolute values.
What do I have to do so that the background color of the ListBoxItems fill the width of the ListBox?
<Window x:Class="TestListBoxSelectedItemStyle.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:TestListBoxSelectedItemStyle"
Title="Window1" Height="300" Width="300">
<Window.Resources>
<local:CustomerViewModel x:Key="TheDataProvider"/>
<DataTemplate x:Key="CustomerItemTemplate">
<Border CornerRadius="5" Background="Orange" HorizontalAlignment="Stretch" Padding="5" Margin="3">
<StackPanel Orientation="Horizontal" HorizontalAlignment="Stretch" Width="Auto">
<TextBlock HorizontalAlignment="Stretch">
<TextBlock.Text>
<MultiBinding StringFormat="{}{0} {1}">
<Binding Path="FirstName"/>
<Binding Path="LastName"/>
</MultiBinding>
</TextBlock.Text>
</TextBlock>
</StackPanel>
</Border>
</DataTemplate>
</Window.Resources>
<Grid>
<ListBox ItemsSource="{Binding Path=GetAllCustomers, Source={StaticResource TheDataProvider}}"
ItemTemplate="{StaticResource CustomerItemTemplate}"/>
</Grid>
</Window>

I found another solution here, since I ran into both post...
This is from the Myles answer:
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch"></Setter>
</Style>
</ListBox.ItemContainerStyle>
This worked for me.

I'm sure this is a duplicate, but I can't find a question with the same answer.
Add HorizontalContentAlignment="Stretch" to your ListBox. That should do the trick. Just be careful with auto-complete because it is so easy to get HorizontalAlignment by mistake.

If your items are wider than the ListBox, the other answers here won't help: the items in the ItemTemplate remain wider than the ListBox.
The fix that worked for me was to disable the horizontal scrollbar, which, apparently, also tells the container of all those items to remain only as wide as the list box.
Hence the combined fix to get ListBox items that are as wide as the list box, whether they are smaller and need stretching, or wider and need wrapping, is as follows:
<ListBox HorizontalContentAlignment="Stretch"
ScrollViewer.HorizontalScrollBarVisibility="Disabled">
(credits for the scroll bar idea)

Since the border is used just for visual appearance, you could put it into the ListBoxItem's ControlTemplate and modify the properties there. In the ItemTemplate, you could place only the StackPanel and the TextBlock. In this way, the code also remains clean, as in the appearance of the control will be controlled via the ControlTemplate and the data to be shown will be controlled via the DataTemplate.

The fix for me was to set property HorizontalAlignment="Stretch" on ItemsPresenter inside ScrollViewer..
Hope this helps someone...
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBox">
<ScrollViewer x:Name="ScrollViewer" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Foreground="{TemplateBinding Foreground}" Padding="{TemplateBinding Padding}" HorizontalAlignment="Stretch">
<ItemsPresenter Height="252" HorizontalAlignment="Stretch"/>
</ScrollViewer>
</ControlTemplate>
</Setter.Value>
</Setter>

I also had the same problem, as a quick workaround, I used blend to determine how much padding was being added. In my case it was 12, so I used a negative margin to get rid of it. Now everything can now be centered properly

Related

WPF IDataErrorInfo issues

I've used WPF and IDataErrorInfo in the past apps to display errors to the user via a controltemplate by putting an image in the adorner and adding a tooltip to the image like this;
<Style x:Key="textStyle" TargetType="TextBox">
<Setter Property="Validation.ErrorTemplate">
<Setter.Value>
<ControlTemplate>
<DockPanel LastChildFill="True">
<Border BorderBrush="Orange"
BorderThickness="2"
CornerRadius="4"
SnapsToDevicePixels="True">
<Border.Effect>
<DropShadowEffect BlurRadius="10"
ShadowDepth="0"
Color="Orange" />
</Border.Effect>
<DockPanel>
<Image Width="16"
Height="16"
Margin="-20,0,0,0"
HorizontalAlignment="Left"
VerticalAlignment="Center"
RenderOptions.BitmapScalingMode="HighQuality"
Source="{StaticResource imgError}"
ToolTip="{Binding ElementName=adornedElement,
Path=AdornedElement.(Validation.Errors).CurrentItem.ErrorContent}"
ToolTipService.ShowDuration="30000" />
<AdornedElementPlaceholder Name="adornedElement" />
</DockPanel>
</Border>
</DockPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
With the appropriate implementation of IDataErrorInfo in the ViewModel and setting Textbox in the view accordingly the image and tooltip are shown;
<TextBox Name="txt"
Grid.Column="0"
Height="40"
Background="Aqua"
Style="{StaticResource textStyle}"
Text="{Binding Path=Text,
UpdateSourceTrigger=PropertyChanged,
ValidatesOnDataErrors=True}" />
<TextBlock Grid.Column="1"
Height="40"
Background="AliceBlue"
Text="{Binding ElementName=txt,
Path=(Validation.Errors).CurrentItem.ErrorContent}" />
The above code displays correctly in my previous apps and shows the error in the image tooltip as confirmed by the Textblock.
However, in my current app which is built using Prism I can't get the Image to display. The TextBlock updates correctly and I can set the error to the TextBox tooltip via a style trigger without any issue. The problem is I can't seem to get the image (or anything else) to display in the Adorner. The Image is not shown and border is not changed.
The difference between previous apps and this is that the view is in a Region in a ContentControl and I've used dependency injection to inject the viewmodel into the view constructor and set the DataContext.
I can't figure out why this doesn't work when it did previously. I think I may need to include an AdornerDecorator somewhere but I'm perplexed as to where having tried it in a few places without success. Any ideas how I can ensure the Adorner is shown?
Used an AdornerDecorator to wrap the element containing the texbox and all works fine.

Keyboard navigation in WPF Grids

Suppose you have a StackPanel, which contains a ScrollViewer which contains another StackPanel with an ItemsControl with a bound ItemsSource. This ItemsSource is bound to a collection of Grids created at runtime. Each Grid contains a label and a textbox/combobox/a few checkboxes that all have a unique TabIndex value within the StackPanel.
Here is the xaml:
<ScrollViewer Name="scrollViewer" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
<StackPanel Name="stackPanel" MinWidth="500" Width="Auto">
<ItemsControl Name="itemsControl" ItemsSource="{Binding ElementName=SomeWindow, Path=GridsCollection,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"/>
</StackPanel>
</ScrollViewer>
I want to simply tab from one control to the next, but only within the controls in the grids in the grids collection. So far I've tried different KeyboardNavigation.TabNavigation settings but without any luck. What is the best way to do this?
Set TabNavigation to KeyboardNavigationMode.Cycle for each container you want to behave like that, so the focus won't escape it as long as you use Tab and Shift+Tab:
KeyboardNavigation.SetTabNavigation(grid1, KeyboardNavigationMode.Cycle);
If you want to change Ctrl+Tab behaviour, use KeyboardNavigation.SetControlTabNavigation.
You can apply an implicit style that disables tabbing for every Control, then you re-enable it for just what you want to be tab-able:
<ScrollViewer Name="scrollViewer" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
<ScrollViewer.Resources>
<Style TargetType="Control">
<Setter Property="IsTabStop" Value="False" />
</Style>
</ScrollViewer.Resources>
<StackPanel Name="stackPanel" MinWidth="500" Width="Auto">
<ItemsControl Name="itemsControl"
ItemsSource="{Binding ElementName=SomeWindow, Path=GridsCollection,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"/>
</StackPanel>
</ScrollViewer>
Don't forget to set IsTabStop on your dynamically generated Grids to True

Why does this happen with Datagrid?

I've a Silverlight app (Silverlight 4 in VS2010) wherein I've a datagrid. I wanted to set the border for the datagrid rows. So in the <DataTemplate> I wrote this:
<Border BorderBrush="Black" BorderThickness="1"></Border>
This worked. Now I wanted to draw border only in the bottom and right and I did this:
<Border BorderBrush="Black">
<Border.BorderThickness>
<Thickness Bottom="1" Left="0" Top="0" Right="1"/>
</Border.BorderThickness>
</Border>
But this throws a XAML parsing error - Cannot set the read-only property Bottom
Why would this happen? Is there any alternatives to do the same?
<Border BorderBrush="Black" BorderThickness="0,0,1,1" />

Customize WPF databinding: How to add custom logic?

i have a question regarding some complex data-binding.
I want to be able to update a grid (which has the property "IsItemsHost" set to true)
dynamically whenever a data-binding occurs.
Actually i am using a CustomControl which is an ItemsControl and this
has the Grid in its ControlTemplate.
To be more specific, i bind the grid to some items and i want to
change the number of grid rows depending on these items,
add something like a header (one row containing some text),
and set the items' Grid.Row and Grid.Column using some custom logic.
What is the easiest way to apply such behaviour
whenever the bound data is updated?
Do i have to use a viewmodel that also contains the header data?
Thanks in advance.
Code of the CustomControl Generic.xaml:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:TimeTableControl">
<Style TargetType="{x:Type local:TimeTableControl}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:TimeTableControl}">
<Border Width="Auto" Height="Auto" BorderBrush="#FF4B5A9B" BorderThickness="4" CornerRadius="4" Margin="2" Padding="0" Background="White">
<Grid Width="Auto">
<Grid.RowDefinitions>
<RowDefinition Height="0.1*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Viewbox>
<TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" Text="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=DayCaption}"/>
</Viewbox>
<Border Grid.Row="1" BorderThickness="0,2,0,0" BorderBrush="#FF4B5A9B">
<Grid Name="ContentGrid" IsItemsHost="True">
</Grid>
</Border>
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
Grid is used for layout. If you have a changing number of items in some collection, what you really want is ItemsControl, or more specific ListBox (if you want item selection, etc).
If you still want Grid-like behavior of individual rows, you may want to define a Grid in ItemsControl.ItemTemplate and play with Grid.IsSharedSizeScope at ItemsControl level. Alternatively, you may just use ListView instead to get the grid look and item selection in a package.
Update: I got it working by creating a custom panel that uses MeasureOverride and ArrangeOverride to update itself. This lets me adjust the panel to the children and I don't even need to use a grid. This also makes the control lookless.

WPF tab control spacing between headers

The default behavior of the WPF Tabcontrol is to place the Tab Headers adjacent to each other, without any empty space in between. What if I wanted to specify a gap between the headers? Do I have to define a control template for this? I'm relatively new to WFP and any help is appreciated.
Thanks
I believe you will need to define a custom control template for the TabItem, maybe even one for the TabControl. Here is an example of a TabItem that uses a spacer for some separation.
<Style
x:Key="SpacedTab"
TargetType="{x:Type TabItem}">
<Setter
Property="Template">
<Setter.Value>
<ControlTemplate
TargetType="{x:Type TabItem}">
<Border
x:Name="Spacer"
Width="Auto"
Height="Auto"
Padding="0 0 5 0"
Margin="0 0 0 0"
BorderBrush="Transparent"
BorderThickness="0">
<Border
x:Name="Border"
MinWidth="150"
Width="Auto"
Height="30"
Background="Gray"
BorderBrush="DarkGray"
BorderThickness="0,0,0,0"
CornerRadius="6,6,0,0"
Cursor="Hand"
VerticalAlignment="Bottom">
<ContentPresenter
x:Name="ContentSite"
TextElement.FontSize="10pt"
TextElement.FontFamily="Arial"
TextElement.Foreground="Black"
VerticalAlignment="Center"
HorizontalAlignment="Center"
ContentSource="Header"
Margin="8,3,8,3"
Width="Auto"
Height="Auto" />
</Border>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Hopefully that is a nudge in the right direction; you will still need to add that as a style resource and reference it from your TabControl -> TabItem.
It is easy to add space by doing it in the designer. Select the Tab you want to move, by starting with the rightmost tab. Then hold ctrl and use the right arrow key to move the tab to the right. Do the same with the rest of the tabs. Then you can manually adjust the margin in the xaml code.

Resources