Setting Width of ComboBox Drop Down to Exclude Scrollviewer Width - wpf

Is there an elegant way to set the width of the combobox drop down to exclude the width of the scrollviewer scroll bar and get rid of that annoying overhang?
I've tried ScrollViewer.VerticalScrollBarVisibility="Hidden" and ScrollViewer.VerticalScrollBarVisibility="Disabled" but can't seem to get rid of the overhang.
I really don't want to hard code the width. I currently have my DataTemplate object (grid) width binding to the Actual Width of the Combobox.
Example of Overhang
<ComboBox x:Name="cboActiveLocation" Margin="25,10,25,0" Grid.Row="1" FontSize="72" VerticalAlignment="Top" MaxDropDownHeight="450" ScrollViewer.VerticalScrollBarVisibility="Hidden">
<ComboBox.ItemTemplate>
<DataTemplate>
<Grid Margin="0 20" Width="{Binding ActualWidth, ElementName=cboActiveLocation}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
// Display Info
</Grid>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
Here is the link to a similar question a few years back suggesting to bind the width like I show above but the update on that question remains unanswered.
Setting MaxWidth of ComboboxItem such that Items width don't exceed ComboboxWidth

Related

Sharing column width between grids defined in a template

I am trying to layout a couple of controls:
The light gray vertical lines are grid splitters. Each line in this table is a grid with three columns, the label on the left, the splitter in the middle and the control on the right, including the text boxes and the image.
I want all columns to be aligned. Here is the data template I use for each line:
<DataTemplate x:Key="PropertyLineTemplate">
<Grid Margin="0,0,0,1">
<Grid.ColumnDefinitions>
<ColumnDefinition SharedSizeGroup="Name"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition SharedSizeGroup="Value"/>
</Grid.ColumnDefinitions>
<TextBlock
Grid.Column="0"
VerticalAlignment="Center"
Text="{Binding Title}" />
<GridSplitter Grid.Column="1" Width="2"/>
<SomeUserControl
Grid.Column="2"
Content="{Binding}"
Margin="4, 0, 0, 0"/>
</Grid>
</DataTemplate>
and the template for the view itself:
<DataTemplate DataType="{x:Type vm:PropertiesViewModel}">
<DockPanel>
<!-- Properties -->
<ScrollViewer>
<StackPanel Margin="10">
<ItemsControl ItemsSource="{Binding Properties}"
ItemTemplate="{StaticResource PropertyLineTemplate}" />
</StackPanel>
</ScrollViewer>
</DockPanel>
</DataTemplate>
and the usage of both:
<ContentControl Content="{Binding SelectedItem}" Grid.IsSharedSizeScope="True">
</ContentControl>
where SelectedItem is of type PropertiesViewModel.
I also tried to place Grid.IsSharedSizeScope="True" in each individual grid directly and on the panels containing the control, without effects. How can I achieve that all columns share the width?
Grid.IsSharedSizeScope should be set on the first parent ItemsControl of a Grid, in your case it would be the ItemsControl in the ViewModel template. Then the columns width will be adjusted.
However, if you move one GridSplitter, then it will only adjust that row, not the others (See WPF SharedSizeGroup GridSplitter Issue for a potential solution, if you need resizing.)
Other stuff: you don't need the Stackpanel wrapper around the ItemsControl, since the ItemsControl is the only child. If you need to adjust the panel the ItemsControl uses, then set it on the Property ItemsPanel, like this:
<ItemsControl ItemsSource="{Binding Properties}"
Grid.IsSharedSizeScope="True"
ItemTemplate="{StaticResource PropertyLineTemplate}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel/> <!-- Or <WrapPanel/> or <UniformGrid/> etc. -->
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
However, the Stackpanel is the default panel of the ItemsControl.
Based on Nautious' answer I've solved the problem by defining two ColumnDefinitions as resources and binding the Width property of all columns in question to the Width property of these 'master column definitions':
<ColumnDefinition x:Key="MasterColumnDefinition" />
<ColumnDefinition x:Key="MasterColumnDefinition2" />
<DataTemplate x:Key="PropertyLineTemplate">
<Grid Margin="0,0,0,1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="{Binding Source={StaticResource MasterColumnDefinition}, Path=Width, Mode=TwoWay}"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="{Binding Source={StaticResource MasterColumnDefinition2}, Path=Width, Mode=TwoWay}"/>
</Grid.ColumnDefinitions>
...
</Grid>
</DataTemplate>
Might be a little hacky, but it's simple and works. Not, however, that the shared size scope of this solution is the scope in which the resources are defined. I.e. placing these template in the app's resources will lead to all columns in the application being resized synchronously.

Stop TextBlock from resizing container WPF

I have a listbox that changes size based on the size of the window. For each item in the listbox, it contains (via DataTemplate):
<Grid Height="20" HorizontalAlignment="Stretch">
<ProgressBar HorizontalAlignment="Stretch" Height="20" Value="{Binding Path=Progress, Mode=OneWay}" />
<TextBlock Margin="7,0,0,0" Text="{Binding Path=OperationTitle}" />
</Grid>
The progress bars are supposed to expand to the size of the listbox, which they do unless the text in the textblock is longer than the listbox. In that case, the textblock and the progressbar become wider than the listbox and a horizontal scroll bar appears at the bottom of the list box.
I want the progressbar and textblock to be as wide as the listbox allows and the text in the textblock to be cut off if it's longer than the listbox.
At the moment, the progress bar width is controlled by its container in one case, and its contents in another. I want it to always be controller by its container.
Thanks!
Hi if i didnt misinterpreted your question try this
<Grid Height="20" HorizontalAlignment="Stretch">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto" MaxWidth="100"/>
</Grid.ColumnDefinitions>
<ProgressBar HorizontalAlignment="Stretch" Height="20" Value="{Binding Path=Progress, Mode=OneWay}" Grid.Column="0" />
<TextBlock Margin="7,0,0,0" Text="OperationTitle" Grid.Column="1" />
</Grid>
I hope this will help and dont forget to set maxWidth of second column of the Grid accordingly.
try to add next property to listbox
HorizontalContentAlignment="Stretch"

Stretching the items of an ItemsControl

I'm bulding a small WPF app over here. It's all built strictly with MVVM, using nothing but DataTemplates linked to view model types.
I've seen alot of questions about how to stretch and clip the contents of ListBoxes so that the items fill its parent. After alot of experimenting I managed to get my head around that but now I find myself in the same scenario with the ItemsControl but the same tricks doesn't seem to work.
Here's one of the DataTemplates in use (a simple TextBox). Note how I tried setting the HorizontalAlignment ...
<DataTemplate DataType="{x:Type vm:OneOfMyViewModelTypes}">
<TextBox
Text="{Binding Path=Value}"
HorizontalAlignment="Stretch"
/>
</DataTemplate>
Here's the ItemsControl inside a Grid ...
<Grid Background="Gray">
<Grid.Margin>
<Thickness
Left="{StaticResource ConfigurationDefaultMargin}"
Right="{StaticResource ConfigurationDefaultMargin}"
Bottom="{StaticResource ConfigurationDefaultMargin}"
Top="{StaticResource ConfigurationDefaultMargin}"
/>
</Grid.Margin>
<Grid.ColumnDefinitions>
<ColumnDefinition SharedSizeGroup="_key" Width="Auto"/>
<ColumnDefinition SharedSizeGroup="_value" Width="*"/>
</Grid.ColumnDefinitions>
<ItemsControl
Background="DimGray"
Grid.IsSharedSizeScope="True"
ItemsSource="{Binding Path=Configuration, Mode=OneWay}"
HorizontalAlignment="Stretch"
HorizontalContentAlignment="Stretch"
>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition SharedSizeGroup="_key"/>
<ColumnDefinition SharedSizeGroup="_value"/>
</Grid.ColumnDefinitions>
<TextBlock
Style="{StaticResource ExtensionConfigurationLabel}"
Grid.Column="0"
Margin="5,5,5,0"
Text="{Binding Path=Caption}"
/>
<ContentPresenter
Grid.Column="1"
HorizontalAlignment="Stretch"
Margin="5,5,5,0"
Content="{Binding}"
/>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
I've used colors to see how the controls sizes. The Grid is gray and the ItemsControl is dark gray.
This is the result ...
As you can see from the colors the containing Grid stretches while the ItemsControl does not. I did set its HorizontalAlignment property to Stretch but it seems it has no effect. Is there anything else I need do?
Thanks
You have two columns in your main (outer) grid, yet you use only the first column.
The second column uses all the remaining space.

Which ItemControl should I choose and Why?

I have an arbitrary count of ViewModels to display and I want that ViewModels to be displayed in two columns. The first column mostly should display a name/description and the content of the second column varies. I would prefer a Grid-like layout with a Width = "auto" for the first column and Width = "*"for the second column.
I tried a ListView with a GridView but that has some flaws.
I can select the ListViewItems(not necessary)
GridViewColumns have headers(wasted space/ not necessary)
GridViewColumns don’t support Width = "*" like a Grid and therefore doesn’t use all the available space
I could use a Grid, but than I would have to add Grid.RowDefinitions for every ViewModel and wouldn’t be possible to set the Grid.Row Property via Binding.
I also thought about using a StackPanel, but that doesn’t support Templating and I don’t know how to sync the Width for the first column.
So, does anybody know which ItemControl is best suited for this purpose?
Without testing it I would expect an ItemsControl with a data template to be a suitable solution.
You can use Grid.IsSharedSizeScope="true" on a parent element, in this case the ItemsControl, and then synchronize the width of the first column using SharedSizeGroup="somename".
<Grid>
<Grid.Resources>
<DataTemplate x:Key="itemTemplate" DataType="{x:Type MyItemType}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition SharedSizeGroup="column1" Width="Auto"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding Title}"/>
<!-- More stuff here -->
</Grid>
</DataTemplate>
</Grid.Resources>
<ItemsControl Grid.IsSharedSizeScope="True" ItemTemplate="{StaticResource itemTemplate}" />
</Grid>
I would use a ListBox with a Grid as template like this:
<ListBox ItemsSource="{Binding SomeData}" HorizontalContentAlignment="Stretch">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding Data1}" Grid.Column="0"></TextBlock>
<TextBlock Text="{Binding Data1}" Grid.Column="1"></TextBlock>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>

Silverlight control not stopping at container bottom

I have a grid that hosts a stackpanel that hosts a listbox. The Listbox once filled from the itemssource is stretching out of the visible area of the stackpanel. I have tried limiting the grid and stackpanel in size and the listbox continues to stretch out of the visible range (it just goes to edge and continues as if nothing was there to stop it instead of limiting it's size and bringing up a vertical scrollbar). The only thing that seems to help is setting the MaxHeight on the listbox, the issue is I can't tell what that height should be for different clients. I have tried different VerticalAlignments and I have the bottom margin set to 5 to try and get it to stop at the edge but nothing has had an effect yet.
Snip: Edit to add full hierarchy:
<UserControl>
<Grid x:Name="LayoutRoot" Background="White" Margin="0,0,0,0">
<Grid.ColumnDefinitions>
<ColumnDefinition MinWidth="230"/>
<ColumnDefinition d:DesignWidth="500"/>
<ColumnDefinition MinWidth="300" />
</Grid.ColumnDefinitions>
<StackPanel x:Name="ContentHolder" Grid.Column="0" DataContext="{Binding}" VerticalAlignment="Top">
<ListBox Name="lst" ItemsSource="{Binding}" Margin="5,0,15,5" VerticalAlignment="Stretch">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Name}" />
<TextBlock Text="{Binding Number}" Margin="15,0,0,0" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</StackPanel>
</grid>
</usercontrol>
I have removed most of the names and such from the code to just use this as an example.
Answering this for anyone confused and looking for an answer in the future. Basically stackpanels step to a vertical orientation do not limit the size of their child controls vertically so anything with a scroll bar (datagrid, listbox, etc) probably shouldn't be used with them.

Resources