Itemscontrol Scrollviewer not working with data - wpf

I have searched all over, and even though everyone seems to be having this problem, I can't find the fix for my specific problem..
Here's the problem.
I want to make a custom Calendar Control. In order to do this I am filling an ItemsControl with TextBlocks, and then putting a scrollviewer around it.
But for some reason the scrollviewer scrollbar seems disabled, and it doesn't seem to recognize that it's filled with data.
Here's my Code
<Grid>
<ScrollViewer>
<ItemsControl ItemsSource="{Binding CalendarDates}" Height="75">
<ItemsControl.ItemTemplate>
<DataTemplate DataType="local:Calender">
<TextBlock Name="CalendarDate" FontSize="12" Text="{Binding}" TextAlignment="Right" VerticalAlignment="Top" Height="Auto"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Rows="1" Columns="7"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</ScrollViewer>
</Grid>
And here's my MainWindow.xaml where I initialize it
<Grid>
<!--Row Definitins -->
<Grid.RowDefinitions>
<RowDefinition Height = "Auto"/>
<RowDefinition Height = "*"/>
<RowDefinition Height = "Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*"/>
<ColumnDefinition Width="25*"/>
<ColumnDefinition Width="10*"/>
</Grid.ColumnDefinitions>
<localControl:Calender Grid.Column="1" Grid.Row="1"/>
</Grid>
The code fills the scrollviewer just fine, but like I said above the scrollbar seems disabled, and even when I hard code the size it still doesn't work!
Also I have already tried to set the SccrollViewer.VerticalScrollBar= Visible, and the height of the scrollviewer, as well as over a dozen of the "fixes" here on Stack Overflow, but none of them work in my case

I found the answer... The ItemsControl template itself does not allow for a scrollviewer.
I found the answer in this magazine on page 38.
https://dncmagazine.blob.core.windows.net/edition20/DNCMag-Issue20.pdf
We need to modify the ItemsControl template as follows:
<ItemsControl.Template>
<ControlTemplate TargetType= "ItemsControl">
<ScrollViewer>
<ItemsPresenter/>
</ScrollViewer>
</ControlTemplate>
</ItemsControl.Template>

Related

WrapPanel not wrapping content

I have the following xaml code in a user control.
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto" />
<ColumnDefinition Width="*" MinWidth="50"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
</Grid.RowDefinitions>
<ScrollViewer VerticalScrollBarVisibility="Auto" x:Name="scEmails">
<ItemsControl Focusable="False" ItemTemplate="{StaticResource UserDataTemplate}">
<ItemsControl.Items>
<system:String>123</system:String>
<system:String>123</system:String>
<system:String>123</system:String>
<system:String>123</system:String>
<system:String>12eee3</system:String>
<system:String>123eee</system:String>
<system:String>123fefef</system:String>
</ItemsControl.Items>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</ScrollViewer>
<TextBox Grid.Column="1" TextWrapping="NoWrap" Margin="0,0,0,0" VerticalAlignment="Center" PreviewKeyDown="txtAuto_PreviewKeyDown" MinWidth="50" />
</Grid>
Here I have a set of items to be shown in the left of a text box. The rendering requirement is:
If there are no or little items, let the items occupy as many as space they needed.
If there are too many, the items should wrap to next line and expand the Height of the control, to ensure the text box get 50 or more pixels width, unless this is impossible (i.e. there is a single item that will use too much space)
If there are too many lines (i.e. exceed the limit set by MaxHeight property), show the vertical scroll bar.
In any cases, the text box shall be given all the space left (in the right hand side!).
I use a ScrollViewer to fulfill #3, and use a WrapPanel to fulfill #2. But the code above does not give the desired result. In design mode it looks like (the item template is a TextBlock inside a Border, should'nt matter here)
It is not fulfill the requirement because it is not wrapping.
What can I do to fix?
Update
If I apply the code in the answer by Raviraj Palvankar and removed all items, the layout in design mode is the following
However, the desired output (according to requirement term #4) is
Where my original code does properly (although fails other requirements)
Here is your code without the ItemTemplate and hence looking like that. I added more strings to show that it does wrap.
<Grid Grid.Column="1" Grid.Row="3">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" MinWidth="50"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
</Grid.RowDefinitions>
<ScrollViewer VerticalScrollBarVisibility="Auto" x:Name="scEmails">
<ItemsControl Focusable="False" >
<ItemsControl.Items>
<system:String>123</system:String>
<system:String>123</system:String>
<system:String>123</system:String>
<system:String>123</system:String>
<system:String>12eee3</system:String>
<system:String>123eee</system:String>
<system:String>123fefef</system:String>
<system:String>123</system:String>
<system:String>123</system:String>
<system:String>123</system:String>
<system:String>123</system:String>
<system:String>12eee3</system:String>
<system:String>123eee</system:String>
<system:String>123fefef</system:String>
</ItemsControl.Items>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</ScrollViewer>
<TextBox Grid.Column="1" TextWrapping="NoWrap" Margin="0,0,0,0" VerticalAlignment="Center" PreviewKeyDown="txtAuto_PreviewKeyDown" MinWidth="50" />

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.

WrapPanel Horizontal orientation doesn't work

With new version of kinect not exist the old kinectScrollviewer so i have used a ScrollViewer with a listView of images. The problem is the unscrollable when hidden ScrollbarVisibility or with horizontal scroll and if i use a SelectionChanged it works fine with mouse, but if i use a hand gesture after first click the selection area not disappear and so i don't select the elements
I would scroll only horizontal (so i have disabled vertical), but also with your code doesn't scroll with gesture. Also the click doesn't works.
If i use orientation="Vertical" it's scroll vertical (although in the example scroll horizontal using this setting), but if i use orientation="Horizontal" it doesn't works :(
<k:KinectRegion x:Name="ChoiceExercise" Background="Black" >
<DockPanel>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<k:KinectUserViewer Grid.Row="0" Height="100"/>
<ContentControl Grid.Row="1" x:Name="navigationRegion">
<Grid x:Name="kinectGrid">
<ScrollViewer Grid.Row="0" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Disabled" k:KinectRegion.IsScrollInertiaEnabled="True">
<ListView Grid.Row="0" x:Name="listViewExercise" SelectionChanged="listViewExercise_SelectionChanged" BorderThickness="0" Background="Black" >
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel VerticalAlignment="Center" Orientation="Horizontal" />
</ItemsPanelTemplate>
</ListView.ItemsPanel>
</ListView>
</ScrollViewer>
</Grid>
</ContentControl>
</Grid>
</DockPanel>
</k:KinectRegion>
ListView already contains ScrollViewer as part of default template and it's this behaviour that you need to disable by setting attached ScrollViewer.VerticalScrollBarVisibility property to Disabled
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<k:KinectUserViewer Grid.Row="0" Height="100"/>
<ContentControl Grid.Row="1" x:Name="navigationRegion">
<Grid x:Name="kinectGrid">
<ListView
Grid.Row="0"
ScrollViewer.VerticalScrollBarVisibility="Disabled"
x:Name="listViewExercise"
SelectionChanged="listViewExercise_SelectionChanged"
BorderThickness="0"
Background="Black" >
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel VerticalAlignment="Center" Orientation="Horizontal" />
</ItemsPanelTemplate>
</ListView.ItemsPanel>
</ListView>
</Grid>
</ContentControl>
</Grid>
Also WrapPanel with horizontal orientation is meant to stack items horizontally until item cannot fit then move to the next row. Since you you want to scroll horizontally I think horizontal StackPanel would suit you better.
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>

WPF layout problems using Grid and ListBox

I'm (sort of) a newbie in WPF. And I'm stuck with this layout. The Viewbox is displayed fine and so is the space (30%) for ListBox but I can't see ListBox in that space. Following is my XAML, just pertaining to the problem.
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="70*"/>
<RowDefinition Height="30*"/>
</Grid.RowDefinitions>
<Viewbox Grid.Row="0" Grid.Column="0" DataContext="{Binding ElementName=thisControl}">
<ItemsControl ItemsSource="{Binding Path=SomeProperty}" ItemTemplate="{StaticResource SomeTemplate}" >
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</Viewbox>
<ListBox Grid.Row="1" Grid.Column="0" ItemTemplate="{StaticResource ListBoxItemTemplate}" ItemsSource="{Binding Path=SomeOtherProperty}" Utils:ListBoxExtenders.AutoScrollToEnd="True"/>
</Grid>
Any help will be greatly appreciated.
It was the DataContext defined at a wrong level. SomeOtherProperty is part of that context without which no data will be bound to the ListBox. But I'm still perplexed as to why there wasn't any binding error in the Output Window for it. Hmmm...

How to create a ListBox that looks like the Windows Live Tiles?

I want to create a ListBox that looks like the Windows Live Tiles.
This is my XAML:
<ListBox Name="listBox"
Grid.Row="1"
Background="Transparent"
BorderBrush="Transparent"
BorderThickness="0"
Width="Auto" Height="Auto"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
ItemsSource="{Binding Path=SomeList,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
VerticalAlignment="Stretch" HorizontalAlignment="Stretch"
VerticalContentAlignment="Stretch" HorizontalContentAlignment="Stretch">
<ListBox.ItemTemplate>
<DataTemplate >
<Grid x:Name="PART_Item" Width="Auto" Height="Auto" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="10">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Image Name="logo" Source="{Binding Path=ImagePath}"
Width="50" Height="50"
Margin="0,0,10,0"
Grid.Column="0" Grid.Row="0" Grid.RowSpan="2"
RenderTransformOrigin="0.5,0.5"
SnapsToDevicePixels="True">
</Image>
<TextBlock Grid.Row="0" Grid.Column="1"
TextAlignment="Left"
FontSize="12"
Text="{Binding Path=SomeName}"
TextTrimming="CharacterEllipsis"/>
<TextBlock Grid.Row="1" Grid.Column="1"
Margin="0,10,0,0"
FontSize="12"
TextAlignment="Left"
Text="{Binding Path=SomeNo}"
TextTrimming="CharacterEllipsis"/>
<TextBlock Grid.Row="0" Grid.Column="2"
TextAlignment="Left"
FontSize="12"
Text="{Binding Path=SomeDescription}"
TextWrapping="Wrap"/>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
How do i change this XAML to look like Windows Live Tiles?
2 Items next to each other for 2 Rows and then 1 Item with a ColumnSpan of 2 and so on it should continue.
I only want to to be in the above mentioned layout.
How would i achieve this?
The image is just for a reference. I want may layout to be like the first 3 Rows.
One easy solution is to use a WrapPanel as the ListBox ItemsPanel. Make your items have the correct dimension (square or rectangle) using DataBinding and give the ListBox the width of two squares.
I'd probably do it with a WrapPanel. Give the ListBox an ItemsPanelTemplate with a WrapPanel in it:
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Horizontal" />
</ItemsPanel>
</ListBox>
Then set your ItemTemplate up so that the size of each item is half the width of the ListBox itself (or the same width, for your example third row). The easiest way to do that is to set the ListBox to a known width, then bind the width of the top-level panel in the DataTemplate to something in the item objects. However, this means the objects need to know how wide they're supposed to be - but if they want to fill the tile sizes properly, maybe that could be seen as a benefit.
Another option is a DataTemplateSelector, but that also needs to have a way of determining if it should deliver a wide or narrow template and it doesn't really have access to information about where in the list it is - it just knows which item to deliver a template for.
If you really want to do it without the items having to know anything about where in the list they're going to appear, I think you're going to have to step back from ListBox and write more of the logic yourself. You might be able to wrangle an ItemsControl into behaving like this, but I think it's more likely you'd need to go back further still and do a full-blown custom control, depending on how much flexibility you actually want.
But judging by your question, I think you'll probably be okay just retemplating the ListBox.

Resources