Canvas as ListBox ItemTemplate - c#

My environment is windows phone 7.1.
I have the following code:
<ListBox ItemsSource="{Binding Path=Items}">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<Canvas Background="Black" />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<Canvas Width="200" Height="400"
Canvas.Top="400"> <====== This is not working
... Some content ...
</Canvas>
</DataTemplate>
</ListBox.ItemTemplate>
There is a ListBox that has a Canvas as ItemsPanel.
The ListBoxItems itself are also of type Canvas. For the ListBoxItems I set Canvas.Top =400, i expect the items to show with an offset of 400 in the ItemsPanel.
Unfortunately this doesn't work, the items are rendered at an offset of 0 as shown in this image (the ItemsPanel is black, the colorful rectangle is a listitem):
Why arent the ListBoxItems rendered at an offset of 400?

You are setting the Canvas.Top on the contents of the ListBoxItems not the actual items
When using a canvas as item panel you have to remember that your datatemplated objects are wrapped in ListboxItems
ListBox
Canvas <- your itemtemplate
ListBoxItem
Canvas <- your datatemplate
solution:
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="Canvas.Top" Value="400"/>
</Style>
</ListBox.ItemContainerStyle>

Try adding this to your ListBox
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
</Style>
</ListBox.ItemContainerStyle>
Because you see, the Black Area is the ListBox, but not your ListBoxItem. Due a "commonly known bug", if we still can call it that, the ListBoxItem doesn't stretch, unless you add the code above.

Related

Accurate scrollbar control in an ItemsControl with a VirtualizingStackPanel

I have an Itemscontrol using a VirtualizingStackPanel to display a huge (and growing) list of items:
<ItemsControl Grid.Row="1" Name="ConversationItemsControl" VirtualizingStackPanel.VirtualizationMode="Recycling">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel Orientation="Vertical" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.Template>
<ControlTemplate TargetType="ItemsControl">
<ScrollViewer>
<ItemsPresenter />
</ScrollViewer>
</ControlTemplate>
</ItemsControl.Template>
<ItemsControl.ItemTemplate>
<DataTemplate>
<local:Message />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
The virtualization is working like a charm, but i cannot get the management of the scrollbar right. If I try to programmatically (e.g. on load) scroll to the bottom like i do in non-virtualized StackPanels:
var scrollViewer = VisualTreeHelper.GetChild(ConversationItemsControl, 0) as ScrollViewer;
scrollViewer.ChangeView(null, double.MaxValue, 1f, true);
the scrollviewer tries to scroll to the bottom, but does not do so completely - it always stops a bit before the "real" bottom. This makes sense in a way since VirtualizingStackPanels are using the scroll value to determine which items to render, but it is totally grinding my gears and unacceptable for end users.
How can I scroll to the "real" bottom? What do I have to do if i want to scroll exactly so far down that the top of a certain item is at the top of the viewport (unless the "real" bottom is too close, naturally)?
This is because the built-in ItemsControl class doesn't support virtualization. You can try a ListBox instead, which uses UI virtualization by default.
If you don't want to have selection behaviour, just set:
<ListBox x:Name="lbCustom">
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<ContentPresenter/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
and then something like:
lbCustom.ScrollIntoView(lbCustom.Items[lbCustom.Items.Count - 1]

How to remove rerendering during Windows UWP ScrollIntoView

When I use ScrollIntoView for my listview, The page goes blank for a moment and then rerenders, how can I make this more smooth?
Here is my current code:
<ListView Name="MessageList" Margin="0,82,0,45"
SelectionMode="None"
IsItemClickEnabled="True"
ItemClick="FileMessage_Click"
HorizontalAlignment="Stretch"
ItemTemplateSelector="{StaticResource MsgDataTemplateSelector}"
ItemsSource="{x:Bind messages}" >
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
</Style>
</ListView.ItemContainerStyle>
</ListView>
And in the code-behind I have this each time a new message is added to the observable collection that feeds into the listview:
MessageList?.ScrollIntoView(MessageList.Items[MessageList.Items.Count -1]);
I didn't reproduced your problem completely. On my PC, this problem only occurs at the first time I add item to ListView. ListView use ItemsStackPanel as its default panel, which supports UI Virtualization. After changing the default panel to StackPanel which has no support for UI Virtualization, the problem doesn't appear.
You can change the ItemsPanel of ListView like below:
<ListView Name="MessageList" Margin="0,82,0,45"
SelectionMode="None"
Height="300"
IsItemClickEnabled="True"
HorizontalAlignment="Stretch"
ItemsSource="{x:Bind messages}" >
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel></StackPanel>
</ItemsPanelTemplate>
</ListView.ItemsPanel>
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
</Style>
</ListView.ItemContainerStyle>
</ListView>
Update: To scroll to the last Item, you need to set the height of ListView and call ListView.UpdateLayout before ScrollIntoView:
MessageList.UpdateLayout();
MessageList.ScrollIntoView(MessageList.Items[MessageList.Items.Count - 1]);

Xaml Listview Windows-Universal Horizontal Scroll Mode

I coded a list that has as an Itemsource an Observable Collection, which is of type Grids. So the listview is containing 4 Items (Grids). I want the Grids to be like horizontal next to each other, so I tried this in Xaml.
<StackPanel Orientation="Horizontal">
<ListView ScrollViewer.HorizontalScrollBarVisibility="Visible" ScrollViewer.HorizontalScrollMode="Enabled" ItemsSource="{Binding DropGrids, Source={StaticResource view}}" Height="100" x:Name="DropList" RenderTransformOrigin="0.5,0.5" >
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"></StackPanel>
</ItemsPanelTemplate>
</ListView.ItemsPanel>
</ListView>
<AppBarButton Icon="MapPin" Label="Go!" HorizontalAlignment="Right"></AppBarButton>
</StackPanel>
But when I try scrolling the list to the left it is instantly going back (If you want to simulate is use WGA resolution 4 Inch Emulator) and I can't see the fourth Grid on the screen. How do I fix this?
The ListView.ItemsPanel property I got from this post:
Stackoverflow Post - Horizontal Mode
Not sure on the Grid part in your ListView itemsource, but I blogged about how to create a Horizontal ListView here
http://depblog.weblogs.us/2015/03/25/show-items-scrolling-horizontally-with-listview-in-winrt/
I hope this helps...
The complete style is set as
<Style x:Name="BaseListViewStyle" TargetType="ListView">
<Setter Property="ScrollViewer.HorizontalScrollMode" Value="Enabled" />
<Setter Property="ScrollViewer.VerticalScrollMode" Value="Disabled" />
<Setter Property="VerticalAlignment" Value="Top" />
<Setter Property="ItemsPanel">
<Setter.Value>
<ItemsPanelTemplate>
<VirtualizingStackPanel Orientation="Horizontal"
ScrollViewer.HorizontalScrollMode="Enabled"
ScrollViewer.VerticalScrollMode="Disabled"/>
</ItemsPanelTemplate>
</Setter.Value>
</Setter>
</Style>

Databind DockPanel

I'm trying to databind a Dockpanel in wpf to a viewmodel collection. I'm using this in order to create a customizable form and so I will not know how many children should be in the dockpanel until runtime.
The problem that I am having is that the attached property DockStyle.Dock doesn't seem to be getting applied when I set it from within a data template. The following xaml is a simplified version of what I am doing. I would expect the first button to fill up the top portion of the screen but what really happens is that they are stacked horizontally. Even hardcoding the DockPanel.Dock property has no effect on the layout of the buttons. When I look at the Visual Tree in XAMLPad I notice that there are ContentPresenters as children of the DockPanel instead of the buttons. Do ContentPresenters get layed out differently then other elements? Is there another technique to databinding to DockPanels?
<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" >
<Grid>
<ItemsControl >
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<DockPanel LastChildFill="True"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button DockPanel.Dock="{Binding}" Content="{Binding}"></Button>
</DataTemplate>
</ItemsControl.ItemTemplate>
<sys:String>Top</sys:String>
<sys:String>Bottom</sys:String>
<sys:String>Left</sys:String>
<sys:String>Right</sys:String>
<sys:String>Top</sys:String>
<sys:String>Top</sys:String>
<sys:String>Top</sys:String>
</ItemsControl>
</Grid></Page>
The reason that the items aren't docked is because the control in the DataTemplate is not a direct child of the DockPanel. I believe that the ItemsControl creates one ContentPresenter for each item, just like how a ListBox creates one ListBoxItem for each item.
You could try using the ItemContainerStyle to dock the controls. I think that any properties set on it should be set on the ContentPresenter. Something like this might work:
<ItemsControl>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<DockPanel />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button Content="{Binding}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemContainerStyle>
<Style>
<Setter Property="DockPanel.Dock" Value="{Binding}" />
</Style>
</ItemsControl.ItemContainerStyle>
...
</ItemsControl>
I'm not sure if binding a string to the Dock property will work or not, though. You might try using the values in the enum directly to see if that helps as well.
This is because your Button is wrapped by ItemsControl in ContentPresenter which does not have DockPanel.Dock set. Try setting ItemContainerStyle to something like this:
<ItemsControl.ItemContainerStyle>
<Style TargetType="{x:Type ContentPresenter}">
<Setter Property="DockPanel.Dock" Value="{Binding}"/>
</Style>
</ItemsControl.ItemContainerStyle>

Resize my border when a VerticalScrollBar appear

Let me show you part of my XAML code :
<ListBox Grid.Row="1" ScrollViewer.HorizontalScrollBarVisibility="Disabled"
ScrollViewer.IsDeferredScrollingEnabled="True"
HorizontalAlignment="Stretch" ItemsSource="{Binding}" Margin="1,1,0,0"
Name="listBox_Faits" Width="290" VerticalAlignment="Stretch"
SelectionChanged="listBox_Faits_SelectionChanged">
<ListBox.ItemTemplate>
<DataTemplate>
<Border BorderBrush="SlateGray" BorderThickness="0.5" Margin="1,2,1,1"
Width="{Binding ElementName=listBox_Faits, Path=Width}">
When too much borders are created (it is linked with an ObservableCollection), a vertical scroll bar appears, and my border doesn't resize on its own. (I would like to see the complete border, I don t want it to be cut at the end)
If anyone has an idea, thanks!
Don't hesitate to ask, if you need more information!
Rgds,
Flo
You can make ListBoxItem stretch by adding this, and then you can remove the Width binding for the Border
<ListBox ...>
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
</Style>
</ListBox.ItemContainerStyle>
<!-- ... -->
The problem is that you are setting the Width of the Border. This means it will be a fixed size, even if the visible are is smaller than the size of the list item. If you don't set the Border.Width, it will resize to fit within the scroll bar.

Categories

Resources