<ListBox ScrollViewer.HorizontalScrollBarVisibility="Disabled">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Rows="1" >
</UniformGrid>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBoxItem HorizontalContentAlignment="Stretch">listbox item 1</ListBoxItem>
<ListBoxItem>listbox item 2</ListBoxItem>
<ListBoxItem>listbox item 3</ListBoxItem>
<ListBoxItem>listbox item 4</ListBoxItem>
<ListBoxItem>listbox item 5</ListBoxItem>
</ListBox>
I have added ListBoxItems as above and used UniformGrid to display it. but I can't achieve content based width for each of the list box item. I have tried HorizontalContentAlignment as Stretch and Auto width properties. Nothing happened.
You have to use HorizontalAlignment instead of HorizontalContentAlignment.
<ListBoxItem HorizontalAlignment="Left">listbox item 1</ListBoxItem>
If you want to set the alignment for all items, consider creating an item container style.
<ListBox ScrollViewer.HorizontalScrollBarVisibility="Disabled">
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="HorizontalAlignment" Value="Left"/>
</Style>
</ListBox.ItemContainerStyle>
<!-- ...your code. -->
</ListBox>
Please note that the default value for HorizontalAlignment is already Stretch, so you will not see a difference there. Furthermore, there is no Auto. The possible values are Left, Right, Center and Stretch. All values except for Stretch will size to the content.
Related
<DataTemplate x:Key="dtTeamInGame">
<WrapPanel MaxHeight="20" >
<Label x:Name="txtPath" Content="{Binding Path = FirstName, Mode=TwoWay}" MinWidth="35" FontStretch="Expanded" ></Label>
<Label x:Name="txtPath2" Content="{Binding Path = SurName, Mode=TwoWay}" MinWidth="125" ></Label>
</WrapPanel>
</DataTemplate>
<ListBox x:Name="listBox" ItemTemplate="{DynamicResource dtTeamInGame}" HorizontalAlignment="Left" Height="100" Margin="97,206,0,0" VerticalAlignment="Top" Width="381">
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem" BasedOn="{StaticResource {x:Type ListBoxItem}}">
<EventSetter Event="PreviewMouseLeftButtonDown" Handler="ListViewItem_PreviewMouseLeftButtonDownHome" />
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
I have two labels within my data template and I would like to see all the text within my label but the text is clipping off. I would like to see all the text and the text should be centered. I have increased the height of the labels but the text is not centered. This problem came about when I set the wrap panel max height to 20 and I need it to be 20. I would like to center the text vertically with the same font size. I have set the minimum height of the labels to 30 but the text is not centered vertically.
The clipping of the label within a list box
Set the Padding property of the Label elements to 0 or use TextBlocks:
<DataTemplate x:Key="dtTeamInGame">
<WrapPanel MaxHeight="20">
<Label x:Name="txtPath" Content="FirstName" MinWidth="35" FontStretch="Expanded" Padding="0"></Label>
<Label x:Name="txtPath2" Content="Surname" MinWidth="125" Padding="0"></Label>
</WrapPanel>
</DataTemplate>
I have a ListView using a WrapPanel as its ItemsPanel, and I use ListViewItem directly as content. But when one ListViewItem.Visibility is Collapsed, you can still see the space it's using.
First off, a sample XAML code similar to what I use :
<Grid>
<ListView ScrollViewer.HorizontalScrollBarVisibility="Disabled" ScrollViewer.VerticalScrollBarVisibility="Hidden" ItemContainerStyle="{DynamicResource ContainerStyle}">
<ListView.Resources>
<Style TargetType="{x:Type ListViewItem}" x:Key="ContainerStyle">
<Setter Property="Background" Value="Transparent" />
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListViewItem}">
<ContentPresenter />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListView.Resources>
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel ItemHeight="200" ItemWidth="200"/>
</ItemsPanelTemplate>
</ListView.ItemsPanel>
<ListViewItem Margin="10" Visibility="Visible">
<Border Background="Red"/>
</ListViewItem>
<ListViewItem Margin="10" Visibility="Visible">
<Border Background="Blue"/>
</ListViewItem>
<ListViewItem Margin="10" Visibility="Visible">
<Border Background="Green"/>
</ListViewItem>
</ListView>
</Grid>
For example, when all items are visible (code above) I have this :
But if I change the first item to make it collapsed as follows
<ListViewItem Margin="10" Visibility="Collapsed">
<Border Background="Red"/>
</ListViewItem>
The result is like this :
What I would expect would be the following :
As such I don't understand why it is acting like this, the Collapsedseems to behave just like Hidden. I'm applying it directly to the item and don't see what else to do .
I've tried different solutions I found, most notably this one about binding to Visibility in the style and this one going more or less in the same direction but without success, same results.
The accepted answer actually does not provide a solution, which is instead delivered in its comment section.
If you set ItemWidth, WrapPanel will reserve the ItemWidth for all the items bound to itself, visible or not.
The workaround here is not to set ItemWidth on the WrapPanel but set the Width on the ItemTemplate.
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel MinWidth="96" />
</DataTemaplate>
</ItemsControl.ItemTemplate>
I think that the issue you see is related to the fact that even collapsed, a ListViewItem is still an Item, and the WrapPanel will detect 3 items, not 2.
A good working solution seems to be overriding the "Arrange" methods of Panel, in a custom Panel.
I'm working on the base of this great class AlignableWrapPanel (inheriting from Panel, not WrapPanel), and I got it working by replacing this :
var child = children[i];
if (child == null) continue;
with this :
var child = children[i];
if (child == null) continue;
if (child.Visibility == Visibility.Collapsed) continue;
The methods are ArrangeOverride, ArrangeLine, and MeasureOverride. ArrangeLineis a bit different, but the line with if(child == null) continue;is pretty easy to spot ; just add the one with Collapsed after that.
That solution should work with any
I have an ItemsControl with arbitrary items. Some of the items are wrapped inside a ScrollViewer. The code-behind for these scrollable items makes use of the ViewportWidth (almost equivalent to ActualWidth) and ViewportHeight (almost equivalent to ActualHeight) properties to arrange/size its visual children. This works as long as I don't put the item inside an ItemsControl. When the item appears in an ItemsControl the value of ViewportHeight equals 0 - effectively making my item invisible. Note that I want to arrange the items vertically, giving all items equal height! No fancy stuff, just a regular StackPanel.
The templates are applied automatically using DataType:
<MyControl.Resources>
<DataTemplate DataType="{x:Type MyScrollableItem}">
<MyControlWrappedInScrollViewer Text="{Binding Text}" />
</DataTemplate>
<DataTemplate DataType="{x:Type MyItem}">
<TextBlock Text="{Binding Text}"/>
</DataTemplate>
</MyControl.Resources>
<ItemsControl ItemsSource="{Binding MyCollection}" />
The structure of MyControlWrappedInScrollViewer looks something like this:
<UserControl>
<Grid>
<ScrollViewer CanContentScroll="True">
<Canvas />
</ScrollViewer>
</Grid>
</UserControl>
Why does my ScrollViewer get the height of 0? How can I tell my ItemsControl to size the item appropriately? E.g. One item yields a height of the ItemsControl height. Two items yield half of it, and so on.
This did the trick:
<Style TargetType="{x:Type ItemsControl}">
<Setter Property="ItemsPanel">
<Setter.Value>
<ItemsPanelTemplate>
<UniformGrid Columns="1" IsItemsHost="True"/>
</ItemsPanelTemplate>
</Setter.Value>
</Setter>
</Style>
I've started developing my code using the example from SO WPF: arranging collection items in a grid. Now, to gain cell selection capability, I renamed each ItemsControl to ListBox, because a ListBox is-a ItemsControl (XAMl somewhat simplified):
<ListBox HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch" ItemsSource="{Binding YourItems}">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<Grid/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemContainerStyle>
<Style>
<Setter Property="Grid.Column" Value="{Binding X}"/>
<Setter Property="Grid.Row" Value="{Binding Y}"/>
</Style>
</ListBox.ItemContainerStyle>
<ListBox.ItemTemplate>
<DataTemplate>
<Image RenderOptions.BitmapScalingMode="LowQuality" Source="{Binding ...ImageSource, Mode=OneWay}">
</Image>
</DataTemplate>
</ListBox.ItemTemplate>
The grid is filled with glyph run test imaged, based on the code here.
Surprisingly it worked - kind of. Selection works. However, in the case of the ItemsControl, there was no scroll bar. Everything scaled nicely. When I made the window smaller, the grid cells shrunk and so did the images. When I made the window larger, everything scaled up.
Now, with the ListBox that's not the case. The images size stays fixed. If the window isn't large enough, there's an horizontal scroll bar and when the window isn't large enough, some of the images are hidden and the user needs to scroll to the right.
So, my question is: If a ListBox is-an ItemControl, why don't my images scale the same? What should I do to correct it?
This is because ListBox and ItemsControl use different styles. You might easily apply the ItemControl's default style to your ListBox:
<ListBox Style="{StaticResource ResourceKey={x:Type ItemsControl}}">
I'm trying to create a context menu for a list box which displays elements in the context menu from the list box. I am able to accomplish this by using the following XAML:
<Window.Resources>
<ContextMenu x:Key="contextMenu"
ItemsSource="{Binding Items,
RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListBox}}}" >
<ContextMenu.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Content}"/>
</DataTemplate>
</ContextMenu.ItemTemplate>
</ContextMenu>
<Style TargetType="{x:Type ListBox}">
<Setter Property="ContextMenu" Value="{StaticResource contextMenu}"/>
</Style>
</Window.Resources>
This works great for one list box. However, when I have a second list box, the context menu keeps showing the elements from the first list box. In other words, the ItemsSource of the context menu does not change. Only the first time that the context menu is opened is the ItemsSource property set. For example:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<ListBox x:Name="first" >
<ListBoxItem>First 1</ListBoxItem>
<ListBoxItem>First 2</ListBoxItem>
<ListBoxItem>First 3</ListBoxItem>
<ListBoxItem>First 4</ListBoxItem>
<ListBoxItem>First 5</ListBoxItem>
</ListBox>
<ListBox x:Name="second" Grid.Column="2" >
<ListBoxItem>Second 1</ListBoxItem>
<ListBoxItem>Second 2</ListBoxItem>
<ListBoxItem>Second 3</ListBoxItem>
<ListBoxItem>Second 4</ListBoxItem>
<ListBoxItem>Second 5</ListBoxItem>
</ListBox>
</Grid>
I would like to set the context menu in a Style because I have many instances of a listbox and do not want to define a separate context menu for each listbox.
UPDATE:
I finally figured out how to fix it. I just need to bind to the PlacementTarget.Items and using a self relative source instead of using a find ancestor relative source.
<ContextMenu x:Key="contextMenu"
ItemsSource="{Binding PlacementTarget.Items,
RelativeSource={RelativeSource Self}}" >
Found the answer, I just need to bind to the PlacementTarget.Items and using a self relative source instead of using a find ancestor relative source.
<ContextMenu x:Key="contextMenu"
ItemsSource="{Binding PlacementTarget.Items,
RelativeSource={RelativeSource Self}}" >
I think the issue you're having here is due to the fact that the context menu is part of a different visual tree. That is, you cannot find the ListBox ancestor because it is not actually an ancestor of the context menu.
If you look at the debug panel of Visual Studio, you should see some warnings about the failing binding expression. Do you?