WP7 Listbox items out of sync when scrolling - c#

I have a page that has a listbox with the following item template as follows:
<ListBox x:Name="test">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid MaxHeight="108" Margin="0,0,0,10">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="4" />
<ColumnDefinition Width="auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Rectangle Height="108" Grid.Column="0" Fill="{Binding Color}"/>
<Image Source="{Binding Image}" Height="108" Width="108" Grid.Column="1" HorizontalAlignment="Left" Stretch="UniformToFill"/>
<StackPanel Grid.Column="2">
<TextBlock Text="{Binding Title}" TextWrapping="NoWrap" />
<TextBlock Text="{Binding SubHeading}" TextWrapping="NoWrap" />
<TextBlock Text="{Binding Body}" TextWrapping="Wrap" />
</StackPanel>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
On the OnNavigatedTo event of the page, I set the item source of the list box to an observable collection of about 20 items.
All is well and the list is populated, however when I scroll up or down the list, the items appear to look out of sync on the UI. e.g the text that was shown on the first list item appears on the last item in the list box, sometimes there's duplicates, and everytime you swipe up or down the items are different.
I have debugged the listbox items, and I can see that correct objects are being bound to the right items. So it's only what is shown on the UI that is incorrect.
I have also tried explicitly using the standard stackpanel as opposed to a virtualizationstackpanel and that works around the issue by making sure all items are loaded in memory.
I don't believe that removing virtualization is the answer. There must be a root cause. However it may be acceptable as my listbox will never really contain more than 30 items.
On another page, I do the same thing with the silverlight toolkit longlistselector, and have the same issue. However I am not sure of how to remove virtualization on a longlistselector.
So to summarize, what might be the underlying issue that causes the listbox items to not update the UI properly when scrolling? If removing virtualization is the only answer, how may I do this on the longlistselector?
Thanks for anyhelp on this.

Maybe it is some sort this problem? (jumpy ListBox while scrolling)

As it turns out, it was a binding issue, and nothing to to with the listbox whatsoever.
I was (unknowingly) removing the binding of some properties in the item template, after I had bound to them (in some other bit of code) Therefore every time the listbox recycled the containers for new items, it could not update it with the correct info.
Thanks all for your help

Related

Label in ListView not binding on Collection Clear

I have a Xamarin form with a listview. In the view cell I have a label and an Entry which are bound to 2 properties on an object in an observable collection.
When I first load the form and add to the collection this works fine. Then I call Collection Clear(). Then I add a new item to the collection and the Entry shows but the Label does not. But if I change the label to an Entry then it works.
Also, if I add a second item to the collection the label on the second and successive items also display. It is just the first one after calling Clear().
Am I missing something special for a label?
This is the data template in the xaml form
<DataTemplate>
<ViewCell>
<Grid HeightRequest="60">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Label Text="{Binding UpcName}" Grid.Column="0" VerticalOptions="Center" HorizontalOptions="Center"/>
<Entry Keyboard="Numeric"
Text="{Binding Quantity}"
Grid.Column="1"
HorizontalTextAlignment="Center"
WidthRequest="40"
VerticalOptions="Center"
HorizontalOptions="Center"/>
<customControls:ExtendedButton Text="DEL"
Command="{Binding Path=BindingContext.DeleteInventoryCommand, Source={x:Reference UpcListView}}"
CommandParameter="{Binding .}"
Style="{StaticResource SmallDestrutiveButtonStyle}"
Grid.Column="2"
FontSize="12"
VerticalOptions="Center"
HorizontalOptions="Center"/>
</Grid>
</ViewCell>
</DataTemplate>
and this is the property it is bound to
var inventory = new InventoryItemVM
{
Id = upcDetail.Id,
Upc = upcDetail.UPC,
UpcName = upcDetail.Name,
Quantity = 1,
BrandImage = upcDetail.BottleImage
};
Inventories.Add(inventory);
later I call
Inventories.Clear();
Then next time I add the inventory the label does not show the UpcName. But add a second one and it does for that one. Or change the label for an Entry and it works every time.
Any ideas please?
UPDATE AND FIX:
If anyone else has this issue, it is to do with the label sizing (or more specifically NOT resizing on content change).
When I removed an item or cleared the list the label bound to a null value and set it's width to 0. Then when the content changed, it did not resize (I dont see a way to get it to resize - so if someone knows, please let me know).
The way around this was to set the FallbackValue on the label (e.g. Uknown) and set the labels HorizontalOptions to fill. Then it worked.
So it was always binding correctly but not rendering correctly.
It's probably debause of the mode of the binding :
https://learn.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/data-binding/binding-mode
Entry have a two way mode by default, and label does not, so you can't change it's content from the Viewmodel without specifying that you will.
you should try with
<Label Text={Binding Upcname, Mode=TwoWay}/>
I hope this helps.

WPF DataGrid Gives ArgumentOutOfRangeException when clicked

I am fairly new to WPF and MVVM and a newb in general, so thank you in advance for your patience.
I am using a custom class in my model, and I have an ObservableCollection of that custom object in my viewmodel. In the class' constructor, I am adding the object to the collection when it is instantiated. In my view, I am using a DataGrid that is bound to the collection to list all active instances of the class. I am trying to implement a drag-and-drop from the DataGrid onto a trash can icon that would allow a user to dispose of unneeded instances of the class.
The problem is that when you click anything in the DataGrid, the program immediately crashes with an ArgumentOutOfRange exception - ("The given DisplayIndex is out of range. DisplayIndex must be greater than or equal to 0 and less than Columns.Count." "Actual value was 0"). DisplayIndex seems to relate to the DataGrid column, so this exception is probably due to the fact that I am not displaying any columns in the traditional sense - in my DataGrid, AutoGenerateColumns is set to False, and I am displaying everything I need to display using a RowDetailsTemplate. (The reason for this is that the area where I am displaying the DataGrid is narrow, so I need a nested, item-specific grid to represent the item properly.) The DataGrid displays and syncs with the collection fine, but obviously has some issues. I have read dozens of links on DataGrid crashes, and haven't found anything involving this exception.
My desired behavior is to pass the custom object represented by the DataGrid item to a target when I drag and drop it. I don't care which "column" they clicked or anything else - I just need a way to pass either an object reference or a SelectedIndex (the items index in the collection) to a method in the viewmodel.
Thank you in advance for any help! The offending bit of code (XAML) seems to be:
<ScrollViewer DockPanel.Dock="Bottom" Margin="2" Width="180" ScrollViewer.VerticalScrollBarVisibility="Auto">
<DataGrid ItemsSource="{Binding Path=myCollection, Mode=OneWay}" AutoGenerateColumns="False" RowDetailsVisibilityMode="Visible" HeadersVisibility="None">
<DataGrid.RowDetailsTemplate>
<DataTemplate DataType="model:myClass">
<Border CornerRadius="10" Background="AliceBlue">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="50" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Grid.Column="0" Text="{Binding MyString1}" FontSize="21" VerticalAlignment="Bottom" />
<TextBlock Grid.Row="0" Grid.Column="1" Text="{Binding MyCustomProperty, Converter={StaticResource MyIValueConverter}}" VerticalAlignment="Bottom" />
<TextBlock Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2" Text="{Binding MyString2}" TextWrapping="Wrap" />
<Image Source="/Resources/image1.png" Grid.Column="2" Grid.Row="0">
<Image.DataContext>
<Properties:Resources/>
</Image.DataContext>
</Image>
<Image Source="/Resources/image2.png" Grid.Column="2" Grid.Row="1">
<Image.DataContext>
<Properties:Resources/>
</Image.DataContext>
</Image>
</Grid>
</Border>
</DataTemplate>
</DataGrid.RowDetailsTemplate>
</DataGrid>
</ScrollViewer>
The issue was indeed because I am not generating any "traditional" columns. This is apparently a known bug, documented here: Microsoft Bug Report
As a workaround, I just defined an invisible column within the DataGrid and it seems to behave properly now:
<DataGrid.Columns>
<DataGridTemplateColumn Visibility="Hidden" />
</DataGrid.Columns>

LongListSelector - нow to highlight the selected item

I am working on Windows Phone 8. When i tap on the items i need to highlight selected item. I use the LongListSelector with DataTemplate.
<DataTemplate x:Key="mySelector">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*"/>
<ColumnDefinition Width="5*"/>
</Grid.ColumnDefinitions>
<Image Source="{Binding MyImage/>
<TextBlock Grid.Column="1"
TextWrapping="Wrap"
Text="{Binding Caption}"
VerticalAlignment="Center"
HorizontalAlignment="Stretch">
</TextBlock>
</Grid>
</DataTemplate>
.....
<phone:LongListSelector Style="{StaticResource MyTextBlockStyle}" />
I watched this example http://code.msdn.microsoft.com/wpapps/Highlight-a-selected-item-30ced444. There are two ways - use user control(I do not fit) and search for child elements(I can not find my TextBlock). I need a change in the allocation of color foreground in textblock. Give a simple way to do this.
I had once tried using Visual trees and drilling to the specific selected item and changing the background color of the grid inside the data template.
What i observed was that, the larger is the number of items in the LongListSelector, longer is the time taken to highlight the item. A few times i had also seen the screen going white if i select an item and the resuming to original content with the selected item after say 2 to 3 seconds which was BAD. That time i had switched to a ListBox which worked fine for any number of entries in the List. That can't be a solution though, but thats what i had experienced about LongListSelectors and coloring the selected item.

Silverlight: ComboBox Behavior

really simple problem, but I guess I have just the wrong definition of combobox:
I'd like to get a simple thing like:
http://www.c-sharpcorner.com/uploadfile/mahesh/combobox-in-silverlight/
But whenever I add a combobox (or a listbox) and set the itemssource, it shows directly all items and I dont have a textbox-like selection.
My approach was quite simple:
In XAML I define:
<StackPanel Orientation="Horizontal">
<TextBlock VerticalAlignment="Center" Style="{StaticResource styleStdWidth}" Text="Spieler 1:" />
<ListBox x:Name="lsbPlayerOne" ItemTemplate="{StaticResource dtName}" Width="300" />
<TextBox x:Name="txtPlayerOnePoints" Style="{StaticResource stylePlayerWidth}" />
</StackPanel>
<DataTemplate x:Name="dtName">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Name}" TextWrapping="Wrap" FontSize="35" FontWeight="Bold" x:Name="txbname"/>
</StackPanel>
</DataTemplate>
And in Code behind I just set the ItemsSource with a List, which has data.
Since the ListBox gets bigger every time I add a item, it gets uglier and uglier.
Am I missing a property, which I didnt find? I did not see anything...
Sorry for the confusing question :)
P.S.: I tried the same as in the example shown in the link. Sadly I cant open the sample project.
Matthias Müller
Your question is unclear. But you are not implementing a combobox in the code you have shown. Why don't you use a combobox and set your itemsource to the list that contains the fields you want to use?
<ComboBox ItemSource={Binding Names}/>

How do I do this autocompletebox xaml in code?

I have an autocompletebox with these databindings:
<sdk:AutoCompleteBox Height="23" HorizontalAlignment="Left" Margin="80,21,0,0" Name="comboBox_clients" VerticalAlignment="Top" Width="171" ItemsSource="{Binding}" IsTextCompletionEnabled="True" IsDropDownOpen="True" ValueMemberPath="client_code">
<sdk:AutoCompleteBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding client_code}" Name="left" Width="70" />
<TextBlock Text="{Binding client_name}" Name="right" Width="250" />
</StackPanel>
</DataTemplate>
</sdk:AutoCompleteBox.ItemTemplate>
</sdk:AutoCompleteBox>
It works like I want, but it appears on a form that gets loaded a lot, and because the autocompletebox has a few thousand items, it takes two or three seconds at initial load to get all of the strings indexed/in order/whatever once I bind it with the appropriate observablecollection.
Instead I want to keep the autocompletebox object as a global so the few second indexing time only happens on the first load, and then during subsequent openings of the window, the autocompletebox on the form can just be set to the global one. How would I duplicate this databinding structure in code?
Firstly create a AutoComplete and set its DataTemplate (The below links lead you the way).
You can't get an instance of a DataTemplate codebehind side,but...
https://stackoverflow.com/a/7101581/413032
https://stackoverflow.com/a/72158/413032
But if I were you in spite of of creating datatemplate in codebehind creating a small resource and reaching it from code behind make things easier.

Categories

Resources