Reputation: 1620
I am having a strange problem in my UWP application.
I have a ListView
bound to an ObservableCollection<SomeInterface>
. I am changing one property of all the items in the ObservableCollection
. The problem is that because of the ObservableCollection
does not take a class as the type argument, rather it takes an interface
, I cannot figure out how to implement INotifyCollectionChanged
on the interface
.
So I went ahead and changed the property of all items in the collection ( without implementing INotifyPropertyChanged
). This is giving weird behavior. When I change the property ( I do this as soon as I navigate to the page containing the ListView
) It only affects only those ListView
items that are not in view currently ie, if there are 100 items in the ListView
and I can see the first 10 without scrolling down then those 10 items are unchanged but when I scroll down, I see that other (other than the first 10) ListViewItem
s are reflecting the changes that were made. And to add to this, when I scroll up again ( to the first 10 items ), I see that now they are also changed.
to summarize, only the items that are not currently in the view get updated.
here's my code to update the ObservableCollection
:
class SomePage : Page
{
private ObservabeCollection<SomeInterface> SomeObservableCollection { get; set; } = new ObservabeCollection<SomeInterface>();
...
private async Task ModifyObservableCollection()
{
var response = await MakeApiCall();
var facets = response.ListOfItems;
foreach (var item in SomeObservableCollection.ToList())
{
var fromApi = facets.author.FirstOrDefault(i => i.key == item.key);
if (fromApi == null) continue;
var itemInList = SomeList.FirstOrDefault(i => i.key == fromApi.key);
itemInList.read = fromApi.read;
itemInList.num = fromApi.num;
//here!!
itemInList = SomeObservableCollection.FirstOrDefault(i => i.key == fromApi.key);
itemInList.read = fromApi.read;
itemInList.num = fromApi.num;
}
}
}
This is my ListView:
<ListView ItemsSource="{x:Bind AuthorFacets, Mode=OneWay}"
ItemTemplate="{StaticResource ListViewDataTemplate}"
SelectionMode="Multiple">
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
</Style>
</ListView.ItemContainerStyle>
</ListView>
My itemtemplate:
<DataTemplate x:Key="ListViewDataTemplate"
x:DataType="local:ISomeInterface">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"></ColumnDefinition>
<ColumnDefinition Width="Auto"></ColumnDefinition>
</Grid.ColumnDefinitions>
<TextBlock Text="{x:Bind read}"/>
<TextBlock Text="{x:Bind num}"/>
</Grid>
</DataTemplate>
Upvotes: 0
Views: 1528
Reputation: 1460
Change
<TextBlock Text="{x:Bind read}"/>
<TextBlock Text="{x:Bind num}"/>
to
<TextBlock Text="{x:Bind read, Mode=OneWay}"/>
<TextBlock Text="{x:Bind num, Mode=OneWay}"/>
And implement INotifyPropertyChanged, and it should work. By default, x:Bind is OneTime unlike traditional binding (because performance / memory) so your items in view won't update.
Without INPC? You could possibly try calling Bindings.Update() on the parent view after changing the properties, though you may lose scroll position.
Upvotes: 2