Width of child control should match width of parent container - wpf

I'm pretty new to WPF. I often find my self struggling with getting a bunch of child controls combined width to match a given parent container.. As in the following:
<ListBox x:Name="BrugereListBox" Grid.Column="0" Grid.Row="3" DataContext="{DynamicResource Brugere}"
ItemsSource="{Binding}"
PreviewMouseLeftButtonDown="BrugereListBox_MouseLeftButtonDown"
PreviewMouseMove="BrugereListBox_PreviewMouseMove"
>
<ListBox.ItemTemplate >
<DataTemplate >
<Border BorderBrush="Black" BorderThickness="1" Margin="2">
<StackPanel Orientation="Vertical" IsEnabled="True"
PreviewMouseLeftButtonDown="StackPanel_PreviewMouseLeftButtonDown">
<StackPanel Orientation="Horizontal" >
<Label>Navn</Label>
<TextBox Text="{Binding Name}"></TextBox>
</StackPanel>
<StackPanel Orientation="Horizontal">
<Label>Password</Label>
<TextBox Text="{Binding Password}"></TextBox>
</StackPanel>
<StackPanel Orientation="Horizontal">
<Label>Email</Label>
<TextBox Text="{Binding Email}"></TextBox>
</StackPanel>
</StackPanel>
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
In this case I'm interested in getting the width of the children of the stackpanel:
<StackPanel Orientation="Horizontal" >
<Label>Navn</Label>
<TextBox Text="{Binding Name}"></TextBox>
</StackPanel>
to match the width of
<ListBox x:Name="BrugereListBox"
Any generic solution to scenarios like this?

turns out to be a dupe of:
wpf border control to span the width of listboxItem
and the answer given there:
This is probably more to do with the
ListBoxItems themselves not taking up
the full width of the ListBox. Add the
HorizontalContentAlignment="Stretch"
attribute to your ListBox and see if
it stretches the individual items to
fill the width.
so change to:
<ListBox x:Name="BrugereListBox" Grid.Column="0" Grid.Row="3" DataContext="{DynamicResource Brugere}"
ItemsSource="{Binding}"
PreviewMouseLeftButtonDown="BrugereListBox_MouseLeftButtonDown"
PreviewMouseMove="BrugereListBox_PreviewMouseMove"
HorizontalContentAlignment="Stretch"
>
but as Kent says, using a Grid would be better in my opinion.

Use the right panel and you'll be fine. StackPanel makes its own decisions about its width/height depending on its orientation and its children. Use a Grid and it will just take up the space it is given - no more, no less.

Related

Set Label Content vertical Center in ItemsControl

Got this XAML for my Data Binded Label:
<ItemsControl
Name="itClblArtiksel"
ItemsSource="{Binding ArtikelInfo}"
Margin="925,45,0,0"
Width="89"
Height="31"
HorizontalAlignment="Left"
VerticalAlignment="Top"
BorderThickness="1"
BorderBrush="Black"
FontWeight="Bold"
>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Label
x:Name="lblArtikelNr"
Content="{Binding ArtNr}"
/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
i already tried to set the VerticalContentAlignment of the ItemsControl and Label to Center but the content dont get centered... any ideas?
EDIT
Picture to demonstrate the situation:
as you can see the bold one (so the one with <itemcontrol>) are in the air
EDIT 2
The accepted answer gave me the final solution:
<ItemsControl Name="itClblArtiksel" ItemsSource="{Binding ArtikelInfo}" VerticalContentAlignment="Center" Height="37" Margin="925,45,236,38" BorderThickness="1" BorderBrush="Black" FontWeight="Bold">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid Height="37">
<Label
VerticalAlignment="Center"
x:Name="lblArtikelNr"
Content="{Binding ArtNr}"
/>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
setting a Grid around the Label with the same Height as the ItemsControland setting then the VerticalAlignment to Center was the workaround.
This will center the labels vertically within their parents. In your case, this will have no effect because the items are only as tall as their content.
<DataTemplate>
<Label
VerticalAlignment="Center"
x:Name="lblArtikelNr"
Content="{Binding ArtNr}"
/>
</DataTemplate>
If you want them to be visibly centered vertically, you need to give them room for that to happen:
<DataTemplate>
<Grid Height="100">
<Label
VerticalAlignment="Center"
x:Name="lblArtikelNr"
Content="{Binding ArtNr}"
/>
</Grid>
</DataTemplate>
But since your ItemsControl has a fixed height of 31, this will simply make the items larger than their parent, pushing the label out of sight. You need to remove that. I also urge you to consider getting accustomed to using StackPanel and Grid for layout, rather than setting very large margins on everything. The margins method makes it hard to rearrange your UI.
How about setting the VerticalAlignment property of the Label to Center?
<Label x:Name="lblArtikelNr" Content="{Binding ArtNr}" VerticalAlignment="Center" />
This works for me:
<ItemsControl
BorderThickness="1"
BorderBrush="Black"
FontWeight="Bold">
<ItemsControl.Items>
<system:String>wefwefwefwe</system:String>
<system:String>wefwefwefwe</system:String>
<system:String>wefwefwefwe</system:String>
<system:String>wefwefwefwe</system:String>
</ItemsControl.Items>
<ItemsControl.ItemTemplate>
<DataTemplate DataType="{x:Type system:String}">
<Label Height="50" Foreground="Black" Content="{Binding}" BorderThickness="1"
BorderBrush="Black" VerticalContentAlignment="Center" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>

Dynamically adding controls to View from MVVM

In WPF, I am using the MVVM model.
I have a View with a Dockpanel and I want to add dynamically StackPanels with a Label and TextBox for all Harddisks found over the Binding.
Therefore my XAML looks like:
<DockPanel Grid.Row="1" HorizontalAlignment="Stretch" Margin="5">
<ItemsControl ItemsSource="{Binding Harddisks}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel DockPanel.Dock="Right" HorizontalAlignment="Right" Margin="2.5,0,0,0">
<Label Content="{Binding Path=Label}" />
<TextBox Text="{Binding Path=GB_Free}" Width="100" IsReadOnly="True"/>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
It should be four Labels and TextBoxes, but only the first Label and TextBox are shown.
Why?
Your items in your ItemsControl are not actually direct children of the DockPanel. You need to change the ItemsControl to specify that the DockPanel is the Panel. The following will cause the ItemsControl to create a DockPanel and place all the items inside it (rather than the StackPanel that ItemsControl uses by default).
More Info: MSDN: ItemsControl.ItemsPanel Property
<ItemsControl ItemsSource="{Binding Harddisks}">
<ItemsControl.ItemsPanel>
<DockPanel Grid.Row="1" HorizontalAlignment="Stretch" Margin="5" />
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel DockPanel.Dock="Right" HorizontalAlignment="Right" Margin="2.5,0,0,0">
<Label Content="{Binding Path=Label}" />
<TextBox Text="{Binding Path=GB_Free}" Width="100" IsReadOnly="True"/>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>

What XAML control should I use to keep all child elements within its borders in WPF?

I'm having a UI design issue, this is what I want the contents of my app window to shrink to fit the smallest dimension of the window.
Using the XAML below, when the window is too narrow the contents are shrunk to fit. Perfect. My problem is when the window is too short, the contents fall out the bottom, like this:
<ItemsControl ItemsSource="{Binding GroupStatsDisplayList}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Background="Red" Margin="5" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Viewbox Margin="4" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" Width="Auto" Height="Auto" >
<ListBox>
<StackPanel Orientation="Horizontal" Margin="5" Background="Blue">
<Label Content="{Binding GroupID}" FontWeight="Bold"/>
<Label Content="{Binding GroupName}" Width="100" FontWeight="Bold" />
<Label Content="{Binding CallsInQueue}" FontWeight="Bold" />
<Label Content="{Binding TSF}" FontWeight="Bold" />
</StackPanel>
</ListBox>
</Viewbox>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
I have read in answers to similar questions that the ItemsControl uses a StackPanel as its default itemspanel and that the StackPanel does behave the way I'm seeing. A grid has been recommended to overcome issues like mine.
So I tried telling my ItemsControl to use a Grid:
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Grid Background="Red" Margin="5" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
Better because the contents do resize when constrained in either direction. Worse because it seems like there is only one ViewBox->ListBox element that gets updated with the last item in my collection (I can see the three items in the collection cycle through the display as the app starts up). I don't see all items in my collection on screen, only the last one.
I also read that a DockPanel could save me...
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<DockPanel Background="Red" Margin="5" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
That's when things got crazy and I decided to write this question. Now all items in my collection are there, but they appear one by one when I expand the window horizontally, each new item appears as the existing ones expand to the vertical extent of the window.
How do I get a layout that looks like the first image but will shrink to fit within the smallest dimension of the window?
Why do you have a ListBox in your DataTemplate, when you have only one hardcoded item the StackPanel? To clarify that: The ItemTemplate defines how you want one item to appear in your items Collection. For Example you could create an ItemTemplate which shows an Album Cover on the left, the Artist Name next to it and on the bottom a Star Rating.
A Grid should not be used as an ItemsPanel, because for that you would need to supply a dynamic Grid/Col Definitions collection.
Using a ViewBox is my best advice. But not in the ItemTemplate, this would only size one children, a viewbox around the whole itemscontrol.
This is the XAML that I used based on the answer from dowhilefor.
<Viewbox Margin="3" >
<ItemsControl ItemsSource="{Binding GroupStatsDisplayList}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" Margin="1" Background="LightGreen">
<Label Content="{Binding GroupID}" FontWeight="Bold"/>
<Label Content="{Binding GroupName}" Width="100" FontWeight="Bold" />
<Label Content="{Binding CallsInQueue}" FontWeight="Bold" />
<Label Content="{Binding TSF}" FontWeight="Bold" />
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Viewbox>
I haven't done WPF in a while, and probably it's not considered very good practice, but maybe you could just use a scaletransform on your entire gui ?
I always liked playing around with them.

XAML TextBlock: How to make TextBlock have variable height?

I have a ListBox that contains TextBlocks.
Sometimes the content of a TextBlock is too long and I want the height of this entry to double or triple as needed to accommodate the text.
I tried TextWrapping="Wrap" but it doesn't work. Every TextBlock is still just one line in height.
Is there an easy way to fix the problem in XAML? Thanks.
* Additional info: I tried to simplify the question but perhaps the complete scenario is better.
I have a listbox whose entries are displayed according to a template in code below.
Each entry has 2 pieces of info: a product price followed by product name.
I don't want to use the horizontal scrollbar in the listbox and want the product name to be displayed in 2 or more lines if necessary. The product name is the 2nd TextBlock.
Here's my XAML:
<ListBox Name="listBox1" ItemsSource="{Binding}" Margin="10" ScrollViewer.HorizontalScrollBarVisibility="Disabled">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock MinWidth="40" TextAlignment="Right" Text = "{Binding ProductPrice}" />
<TextBlock Text = "{Binding ProductName}" TextWrapping="Wrap" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Disable the listbox horizontal scrollViewer. This way the textBlock will be forced to wrap.
XAML:
<ListBox ScrollViewer.HorizontalScrollBarVisibility="Disabled">
<TextBlock TextWrapping="Wrap"/>
</ListBox>
Example result:
Edit:
From the XAML you added I'm confident that the problem lays in the StackPanel.
Try replacing it with Grid for example:
<ListBox Name="listBox1" ItemsSource="{Binding}" Margin="10" ScrollViewer.HorizontalScrollBarVisibility="Disabled">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TextBlock MinWidth="40" TextAlignment="Right" Text = "{Binding ProductPrice}" />
<TextBlock Grid.Column="1" Text = "{Binding ProductName}" TextWrapping="Wrap" />
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
StackPanel doesn't limit the content size, therefore the textBlock doesn't knows where the space ends , and the wrapping doesn't happens.
You are using StackPanel. Try using DockPanel:
<DockPanel>
<TextBlock DockPanel.Dock="Left" MinWidth ="40" TextAlignment="Right" Text = "11.12" />
<TextBlock Text = "{Binding LongText}" DockPanel.Dock="Right" TextWrapping="Wrap" />
</DockPanel>
For Example:
this will help you do that. Dont Size the TextBlock just size the scroll viewer because texblock needs to be variable so ScrollViewer will apply Scrollbar once it goes beyond the size of ScrollViewer .
<ScrollViewer HorizontalScrollBarVisibility="Auto"
VerticalScrollBarVisibility="Auto">
<TextBlock/>
</ScrollViewer>
For ListBoxItem
<ListBox ScrollViewer.HorizontalScrollBarVisibility="Disabled">
<ListBox.Items>
<TextBlock Text="{Binding LongText}" TextWrapping="Wrap"/>
</ListBox.Items>
</ListBox>

Tab order and index in WPF using the MVVM pattern

I'm having an issue with tabbing through the controls on a WPF application using the MVVM pattern. I have the following XAML which defines a tree structure
<Grid Background="Transparent" Margin="10">
<TreeView ItemsSource="{Binding FirstLevelNavigableViewModels}" Background="Transparent"
HorizontalContentAlignment="Stretch"
HorizontalAlignment="Stretch"
BorderThickness="0"
ItemContainerStyle="{StaticResource TreeViewItemStyle1}">
<TreeView.Resources>
<HierarchicalDataTemplate DataType="{x:Type ViewModel:VendorViewModel}" ItemsSource="{Binding Children}">
<View:VendorView HorizontalContentAlignment="Stretch" />
</HierarchicalDataTemplate>
<DataTemplate DataType="{x:Type ViewModel:ProductViewModel}">
<View:ProductView HorizontalContentAlignment="Stretch" />
</DataTemplate>
</TreeView.Resources>
</TreeView>
</Grid>
When the treeview is loaded, the XAML for the "ProductView" is as follows
<Border Margin="0,2,2,2" CornerRadius="3" Background="#3FC7B299" DockPanel.Dock="Right" HorizontalAlignment="Right" Width="109">
<StackPanel Orientation="Vertical" Margin="6,4">
<DockPanel>
<TextBlock DockPanel.Dock="Left" FontFamily="Segoe" FontSize="10" FontWeight="Medium"
Foreground="Black" Opacity="0.75"
Text="CALC. REG. PRICE"></TextBlock>
<Button Width="10" Height="10" Background="Transparent" BorderBrush="Transparent" BorderThickness="0" Padding="-4" Margin="0" Command="{Binding UserDefinedRetailPriceCommand}" Visibility="{Binding UserDefinedRetailPriceButtonView}">
<Image Width="10" Height="10" Source="/Arhaus.Pricing.Client;component/Styles/Images/error.png"></Image>
</Button>
</DockPanel>
<TextBox FontFamily="Segoe" FontSize="16" FontWeight="Medium" KeyboardNavigation.IsTabStop="True" KeyboardNavigation.TabIndex="{Binding RegularPriceTabIndex}"
Foreground="Black" Opacity="0.9" KeyboardNavigation.TabNavigation="Continue"
ebf:LostFocusBehaviour.LostFocusCommand = "{Binding LostFocusSugg}"
Text="{Binding NewSuggestedRetailPrice,Converter={StaticResource FormattingConverter}, ConverterParameter=' \{0:C\}', Mode=TwoWay, UpdateSourceTrigger=LostFocus}" Background="#FFE6DED3" BorderBrush="#FFE6DED3" DataContext="{Binding StringFormat=\{0:c\}, NotifyOnValidationError=True}" Padding="0" TabIndex="1"></TextBox>
</StackPanel>
</Border>
I have the Tab Index bound to an integer that is ever increasing and bound as the treeview is loaded (I.E. I have it setup as tab index 1, 2, 3 etc. as each successive model is loaded).
I would like to be able to hit tab and jump to the next textbox in the treeview but when I click the TAB key, nothing happens. I'm not sure if I have the tabbing setup correctly but I'm very new to WPF and at a loss as to where and how to set the tabbing to make it work. I'm used to WinForms where you just set the tab index and go from there.
Thank you for your assistance, I apologize for the large code block.
I don't have a solution ready but some thoughts that maybe may help:
I don't know what RegularPriceTabIndex returns but probably it begins for each new TreeViewItem at the same index?
The same tab-index is given then multiple times because of repeating use of ProductView. Perhaps this leads to a problem. You can try setting FocusManager.IsFocusScope="true" for the ProductView. Maybe this helps.
Try also to set Control.IsTabStop="true" on the TextBox.

Resources