Strange behaviour of combobox in WinRT - xaml

Comboboxes in WinRT have a default ItemsPanel of type CarouselPanel. This gives Windows 8.1 apps an "infinite loop" when scrolling combobox items.
If you don't want this behaviour, there are a lot of blog posts explaining how to "fix it".
For example this: Cancel WinRT ComboBox infinte scroll effect
or: http://netitude.bc3tech.net/2013/04/12/windows-8s-combobox-and-the-carouselpanel/
The problem with this solution is that you get a weird behaviour on the first item in the combobox.
How to reproduce:
Create a new blank Windows 8.1 app
In mainpage.xaml put:
<TimePicker Time="0" HorizontalAlignment="Center" VerticalAlignment="Center"/>
Create a style.xaml resource dictionary like this:
<Style TargetType="ComboBox">
<Style.Setters>
<Setter Property="ItemsPanel">
<Setter.Value>
<ItemsPanelTemplate>
<StackPanel Orientation="Vertical"/>
</ItemsPanelTemplate>
</Setter.Value>
</Setter>
</Style.Setters>
</Style>
Now start the app, select an item down the list (for example '05' minutes), then select the first item in the same dropdown (for example '00' minutes). The text in the dropdown control will now disappear.
Anyone know how to fix this? If I change the style of combobox itemspanel back to CarouselPanel it works (but with the infinite loop of course).

Just corrected this issue using a VirtualizingStackPanel in place of a StackPanel.
We had to set a size cause otherthise it take all the width of the screen.
<VirtualizingStackPanel HorizontalAlignment="Center" Width="150"/>
We didn't try to get a more flexible solution because we don't need it yet
Hope it will help you

StackPanel just not working with ComoboBox the possible solution is changing it to VirtualizingStackPanel, but you must bind with to the parent, otherthise it will stretch to screen width.
<ComboBox Name="ReasonComboBox"">
<ComboBox.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel Width="{Binding ActualWidth, ElementName=ReasonComboBox}"/>
</ItemsPanelTemplate>
</ComboBox.ItemsPanel>
</ComboBox>

Related

UWP: Transparent Grid with MapControl beneath is flickering

In my Windows 10 UWP app there is a view, where a MapControl is partially (at the top) covered by a Grid. This Grid has cockpit-like elements in it (e.g. speedometer) and has a semi-transparent background-brush (#CC6A6E4D).
The actual problem is, that this background-brush is flickering, whenever one is interacting with the MapControl. Weird thing about this is, that this issue exclusively works on just one of my three test devices (Lumia 550) and only is present in portrait-mode (but not in landscape-mode).
An example-layout, where I've got that issue would be this:
<Grid>
<maps:MapControl
Name="MainMapControl"/>
<Grid
Height="50"
VerticalAlignment="Top">
<Grid.Background>
<SolidColorBrush Color="#CC6A6E4D" />
</Grid.Background>
</Grid>
</Grid>
Any ideas?

Did ScrollViewer change between 8.1 and 10?

I have a Windows 8.1 Store app I am moving to 10 as a Universal app. On 8.1 it works fine. On 10 (both Windows and Phone) it will not scroll. You can see a viewport worth of entries, but it stubbornly refuses to show a scrollbar on mouseover, move if you drag with your finger on a touch screen, scroll when I use the down arrow key to move from item to item, or respond to mouse wheel if there's a mouse - all of which the 8.1 version does.
Has something happened between 8.1 and 10 that might cause this?
There are a number of ScrollViewers in the system and they all do this. Here is one, implicitly on a gridview:
<GridView
x:Name="itemListViewSnapped"
AutomationProperties.AutomationId="ItemListView"
AutomationProperties.Name="Grouped Items"
Grid.Row="5"
Margin="20,5,10,0"
Padding="10,0,0,60"
Background="{StaticResource TimeBucketsSections}"
ItemsSource="{Binding Source={StaticResource ItemsViewSource}}"
ItemTemplate="{StaticResource Bucket80ItemTemplate}"
SelectionMode="Single"
SelectedItem="{Binding SelectedBucketViewModel}"
SelectionChanged="ItemGridViewSelectionChanged"
IsItemClickEnabled="True"
ItemClick="ItemView_ItemClick"
Visibility="{Binding BucketsVisable}"
ScrollViewer.HorizontalScrollMode="Disabled"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
ScrollViewer.VerticalScrollBarVisibility="Visible"
ScrollViewer.VerticalScrollMode="Enabled"
ScrollViewer.BringIntoViewOnFocusChange="False">
I'm leaving all the binding and background and whatnot in there on the offchance they're relevant. The ScrollViewer. parts are what matter, imo.
Not sure this will help but I have had issues with ScrollViewer when in a GridView. I usually wrap the element in a ScrollViewer and turn the one in the GridView off for more stable behaviour.
<ScrollViewer ScrollViewer.HorizontalScrollMode="Disabled"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
ScrollViewer.VerticalScrollBarVisibility="Visible"
ScrollViewer.VerticalScrollMode="Enabled">
<GridView ScrollViewer.HorizontalScrollMode="Disabled"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
ScrollViewer.VerticalScrollBarVisibility="Disabled"
ScrollViewer.VerticalScrollMode="Disabled">
</GridView>
</ScrollViewer>

How to manipulate items in C#

I'm making a Windows Store App using C# and XAML. How can I manipulate one single item in a GridView or a ListView?
According to certain logical conditions, I need to load or not the item in these containers. I have already tried using the property Visibility.Collapsed and Visibility.Visible of the item, but this just hides or shows the item and it is still loaded in the GridView/ListView, and is selectable.
Thanks for your help.
I reckon you meant to hide your GridViewItem without keeping space in view.
You just need to replace GridView's ItemsPanel with StackPanel or VirtualizingStackPanel.
<GridView>
<GridView.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel />
</ItemsPanelTemplate>
</GridView.ItemsPanel>
</GridView>

How to rearrange WrapGrid contents when zoom level changes?

I am developing a Windows 8 Metro application whose layout is pretty simple. It consists of a single page with a WrapGrid enclosed in an ItemsControl, which is in turn enclosed in a ScrollViewer. This is the XAML code of the application main page:
<Page ...>
<Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
<Grid x:Name="MainGrid" Margin="120,140,32,0">
<ScrollViewer x:Name="ScrollView"
VerticalScrollBarVisibility="Auto"
HorizontalAlignment="Stretch">
<ItemsControl x:Name="itemsControl" HorizontalAlignment="Stretch">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapGrid Orientation="Horizontal"
HorizontalChildrenAlignment="Stretch"
Margin="0"
HorizontalAlignment="Center">
<WrapGrid.ChildrenTransitions>
<TransitionCollection>
<EntranceThemeTransition />
<RepositionThemeTransition />
</TransitionCollection>
</WrapGrid.ChildrenTransitions>
</WrapGrid>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</ScrollViewer>
</Grid>
<Page.BottomAppBar>
...
</Page.BottomAppBar>
</Page>
There is also an user control of which new instances are created and added to the ItemsControl programmatically when the user clicks on a certain button in the application bar. As expected by the fact of using a WrapGrid, the control instances are stacked sequentially in a single row until there is no more room in the screen, at which point they appear in a new row and it is necessary to scroll down in order to see them. So far so good.
Now I want to implement a feature and I don't know how to achieve it. What I want is the following: when the user zooms out in the application, causing the controls to appear smaller, I want the new available space to be used so that more controls can be displayed per row; instead, the current behavior is that the ItemsControl itself is reduced and the extra surrounding space is unused.
For example, imagine that the user adds 10 controls. There is room for 4 controls in one row, so that 3 rows of controls are displayed, with 4, 4 and 2 controls. If the user zooms out and now there is room for 7 controls in a row, I want the ItemsControl to rearrange itself so that now there are only two rows with 7 and 3 controls. How could I achieve this?
I hope I have explained myself properly. Please don't hesitate to ask if my question is not clear enough. Thank you very much!

Performance with XAML binding one value to many elements in GridView (Windows 8)

I have a Windows 8 XAML page with a grid in it that shows sample text in 100+ different fonts. The sample text is the same in each grid view item and can be changed using a textbox at the top of the page.
Every time you type a character all the grid view items are updated. The problem is that this is noticeably slow. Particularly if you type quickly.
I'm not sure what is making it so slow. Is it updating all the grid view items including the ones not on screen? Is something else causing the problem and this particular binding is just a red herring?
Here is my binding code (I've removed some xaml from my data template to make it clearer):
<ScrollViewer>
<GridView x:Name="FontGridView" ItemsSource="{Binding Fonts}" SelectionMode="Multiple" Margin="116,0,40,46">
<GridView.ItemTemplate>
<DataTemplate>
<Grid Width="600" MinHeight="100" MaxHeight="120">
<TextBox Text="{Binding ElementName=pageRoot, Path=DataContext.SampleText, Mode=OneWay}"
FontFamily="{Binding FamilyName}" FontSize="32" Background="Transparent" />
</Grid>
</DataTemplate>
</GridView.ItemTemplate>
</GridView>
</ScrollViewer>
Is there a better way to do this, or are there any other performance tuning things I can turn on?
UPDATE: You're less likely to make this mistake since Visual Studio 2012 RC came out. The templates for WinRT apps no longer use a ScrollViewer in this way. I'm keeping the question here for those that have ported apps they created using Visual Studio 2011.
Try removing the ScrollViewer.
Because the GridView is inside a scrollviewer, it is effectively given an infinite width. That might kill the virtualization of the WrapGrid in the GridView.
Furthermore, the GridView internally contains a ScrollViewer already. Obviously, you don't need two of them. But the inner ScrollViewer will also eat mouse wheel events, leaving no events for the outer ScrollViewer to react to. As a result scrolling with the mouse will not work.
Visual Studio 11 (bèta 1) templates contain code like this, to set a margin on the GridView. However, it's better to set a margin on the GridView's ItemsPanel, like this:
<GridView x:Name="FontGridView" ItemsSource="{Binding Fonts}" SelectionMode="Multiple">
<GridView.ItemTemplate>
<DataTemplate>
<Grid Width="600" MinHeight="100" MaxHeight="120">
<TextBox Text="{Binding ElementName=pageRoot, Path=DataContext.SampleText, Mode=OneWay}"
FontFamily="{Binding FamilyName}" FontSize="32" Background="Transparent" />
</Grid>
</DataTemplate>
</GridView.ItemTemplate>
<GridView.ItemsPanel>
<ItemsPanelTemplate>
<WrapGrid x:Name="itemGridViewPanel" Margin="116,53,116,46"/>
</ItemsPanelTemplate>
</GridView.ItemsPanel>
</GridView>
Your original code did not include the Margin that you set on the GridView. But whatever it was, set the same Margin on the WrapGrid.
Notice also that I gave the WrapGrid a name. You can use that name to change the Margin when the screen orientation changes, typically as follows:
<VisualStateManager.VisualStateGroups>
<VisualStateGroup>
<VisualState x:Name="FullScreenLandscape"/>
<VisualState x:Name="Filled"/>
<VisualState x:Name="FullScreenPortrait">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="itemGridViewPanel"
Storyboard.TargetProperty="Margin">
<DiscreteObjectKeyFrame KeyTime="0"
Value="96,53,96,46"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="Snapped"/>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
UPDATE:
I had done this before, but with a VariableSizedWrapGrid. That produces the correct layout, but unfortunately, I'm afraid that VariableSizedWrapGrid is not a virtualizing panel.
WrapGrid is virtualizing, but the behavior at the left margin seems wrong when scrolling. It is correct at the right margin though.
Oh well, in two weeks time we should have the release candidate available. Hopefully things will have improved...
UPDATE:
It seems that Microsoft is aware of this. See http://social.msdn.microsoft.com/Forums/en-US/winappswithcsharp/thread/17385f7d-aadc-4edc-bbff-8738a2f0c917.
UPDATE:
It seems that the WrapGrid has not been fixed in the Release Candidate.
Simplify your data template.
<DataTemplate>
<TextBlock Text="{Binding ElementName=pageRoot, Path=DataContext.SampleText}"
Width="600" MinHeight="100" MaxHeight="120"
FontFamily="{Binding FamilyName}" FontSize="32" />
</DataTemplate>
You don't need the Grid. And it looks like you don't need a (complex) TextBox either, just a (simple) TextBlock.
Also, fixing the height of those text blocks (Height="120") might help (optimize) the layout process.
UPDATE:
I understand you're code is simplified from "the real thing". But that might hide the real problem for us. Remember, the data template is intantiated for every item that is on screen. The more complex it is, the more objects need to be instantiated (CPU and memory usage), possibly need to databind (CPU), need to be measured and laid out (CPU), and need to be rendered (CPU and GPU).
Just do a test with a very simple data template. If your program is faster now, or not, you know whether the data template is the performance problem or not.
Note that the complexity of the data template is not measured by the number of xaml elements you need to describe it, as those elements may have very different internal complexities. For example, do prefer a TextBlock over a TextBox if all you need to do is display text, not allow editing.
Also, if some of these elements have a lot of properties set, do use styles to set them. Using a style on many objects is more efficient than setting many properties on many objects, especially when it come to memory usage. And the less memory you use, the faster your program will be (due to modern CPU multilevel caching architectures).
For example:
<GridView x:Name="FontGridView" ItemsSource="{Binding Fonts}" SelectionMode="Multiple">
<GridView.Resources>
<Style TargetType="TextBlock">
<Setter Property="Width" Value="600" />
<Setter Property="MinHeight" Value="100" />
<Setter Property="MaxHeight" Value="120" />
<Setter Property="FontSize" Value="32" />
</Style>
</GridView.Resources>
<GridView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding ElementName=pageRoot, Path=DataContext.SampleText}"
FontFamily="{Binding FamilyName}" />
</DataTemplate>
</GridView.ItemTemplate>
</GridView>
Try using a VirtualizingStackPanel
<GridView.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</GridView.ItemsPanel>