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]);
Related
I have some defined XAML that looks like
<ListView ItemsSource="{Binding ConfigItems,Mode=OneWay}" Margin="5">
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch"></Setter>
</Style>
</ListView.ItemContainerStyle>
<ItemsControl
ItemsSource="{Binding}"
ItemTemplateSelector="{StaticResource ConfigItemDataSelector}"/>
</ListView>
Now I realize that this isn't how it should be but that is the source of the question. As is I get an exception that indicates the ItemsSource should be empty before using it. From a question asked 12 years ago I see that this exception is raised when Items and ItemsSource properties are being used at the same time. So I set out to use one or the other. But I get this error when I define it like above or when I leave ItemsSource out altogether. When I try to use Items I get an error at compile time that indicates the list has to have a setter.
In case there is some confusion the ConfigItemDataSelector looks like basically returns a DataTemplate depending on which view model is being used. But I think looking at the selector is a distraction from the problem.
public sealed class ConfigItemDataSelector : DataTemplateSelector
{
public DataTemplate MeasurementDataTemplate { get; set; }
. . .
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
if (item is MeasurementConfigItemViewModel)
{
return MeasurementDataTemplate;
}
else if (item is LEDFeedbackConfigItemViewModel)
{
return LEDFeedbackDataTemplate;
}
. . .
return null;
}
}
So how should the ListView use the ItemsControl?
You can not put ItemsControl in ListView.Items
Try this
<ListView ItemsSource="{Binding ConfigItems,Mode=OneWay}" Margin="5">
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch"></Setter>
</Style>
</ListView.ItemContainerStyle>
<ListView.ItemTemplate>
<DataTemplate>
<ItemsControl ItemsSource="{Binding}"
ItemTemplateSelector="{StaticResource ConfigItemDataSelector}"/>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
You can see source code in referencesource.microsoft.com
The ItemsControl have DefaultPropertyAttribute("Items"), so if you do not declare what property you used in xaml, it will set to ListView.Items be equal
<ListView ItemsSource="{Binding ConfigItems,Mode=OneWay}" Margin="5">
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch"></Setter>
</Style>
</ListView.ItemContainerStyle>
<ListView.Items>
<ItemsControl
ItemsSource="{Binding}"
ItemTemplateSelector="{StaticResource ConfigItemDataSelector}"/>
</ListView.Items>
</ListView>
And throw exception say "ItemsSource should be empty before using it"
I found through trial and error that the following works
<ListView Margin="5">
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch"></Setter>
</Style>
</ListView.ItemContainerStyle>
<ItemsControl
ItemsSource="{Binding ConfigItems}"
ItemTemplateSelector="{StaticResource ConfigItemDataSelector}"/>
</ListView>
Basically taking the ItemsSource property from the ListView and moving it to the ItemsControl.
I'm working on UWP with ListView and I'm struggling to implement some basic features.
I have a horizontal ListView with items which need to have variable width. And the width needs to be dynamical, because I want to expand it or retract it based on it's content. To be precise, each item has a number of rectangles inside a StackPanel, I want to be able to add more rectangles, and I would expect the width of the item to increase exponentially.
Right now, the items seem the have equal and locked size. If I increase the content of an item, the other items have the same increased width.
I'm new to UWP, and I can't figure out how to implement such a feature.
<ListView Name="Grid"
Grid.Row="0"
HorizontalAlignment="Stretch"
BorderThickness="0"
ItemsSource="{x:Bind Items, Mode=TwoWay}"
ItemTemplateSelector="{StaticResource TemplateSelector}"
ScrollViewer.HorizontalScrollMode="Enabled"
ScrollViewer.VerticalScrollMode="Disabled"
ScrollViewer.HorizontalScrollBarVisibility="Hidden"
IsItemClickEnabled="True"
CanDragItems = "False"
CanDrag = "False"
CanReorderItems = "False"
AllowDrop = "False"
ItemClick="Grid_ItemClick"
SelectionChanged="Grid_SelectionChanged"
SelectionMode="Single">
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<ItemsWrapGrid VerticalAlignment="Stretch" HorizontalAlignment="Left"/>
</ItemsPanelTemplate>
</ListView.ItemsPanel>
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="Padding" Value="0"/>
<Setter Property="Margin" Value="0"/>
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
<Setter Property="HorizontalAlignment" Value="Stretch" />
</Style>
</ListView.ItemContainerStyle>
You'll want to change your ItemsPanel to be an ItemsStackPanel with Orientation set to Horizontal. Here's a quick sample:
XAML
<ListView Height="100"
extensions:ListViewExtensions.AlternateColor="Red"
ItemsSource="{x:Bind Items}"
ScrollViewer.HorizontalScrollBarVisibility="Auto"
ScrollViewer.HorizontalScrollMode="Auto"
ScrollViewer.VerticalScrollBarVisibility="Disabled"
ScrollViewer.VerticalScrollMode="Disabled">
<ListView.ItemTemplate>
<DataTemplate>
<Grid Width="{Binding Width}">
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<ItemsStackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ListView.ItemsPanel>
</ListView>
Code
Items = new ObservableCollection<Item>();
for (int i = 0; i < 20; i++)
{
Items.Add(new Item { Index = i, Width = i * 10 });
}
And you can see that each item has a wider width
That is hardly possible with ListView. Maybe ItemRepeater is control for you. Or you can use StackPanel (with horizontal orientation) inside ScrollViewer.
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>
Ok, I've got a ListView. I've set ItemsSource from code. This ListView has Property SelectionMode="Multiple". But I'd like to disable some items from selecting.
XAML: //not working
<ListView x:Name="MyListView" SelectionMode="Multiple">
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="IsEnabled" Value="{Binding Path=enabled, Mode=TwoWay}" />
</Style>
</ListView.ItemContainerStyle>
<ListView.ItemTemplate>
<!-- my template -->
</ListView.ItemTemplate>
</ListView>
Although, I cannot set each ListViewItem from code...
You can try using a Converter? See this easy tutorial.
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.