Bound ListView displaying wrong items - caliburn.micro

I have a simple ListView bound to a BindableCollection (async ObservableCollection). I am populating the BindableCollection in an async method. After a refresh, the collection contains about 130 unique items. However, the ListView displays many of the items repeatedly. Checking the actual contents of the collection, I can see they are definitely unique. The contents are something like the following
mazzy star
neil young
the babies
haunted leather
alice boman
compilations
richard swift
rolling stones
fleetwood mac
future islands
lily & madeleine
darlenya
darlenya (different from last)
father john misty
eels
sharon van etten
feeding people
helado negro
neil young first repeat
the babies
haunted leather
alice boman
compilations
richard swift
rolling stones
fleetwood mac
future islands
lily & madeleine
darlenya
darlenya (different from last)
father john misty
eels
sharon van etten
feeding people
helado negro
neil young second repeat
the babies
...
eels
The ViewModel
private readonly BindableCollection<Track> _tracks = new BindableCollection<Track>();
private readonly ITrackFeedService _feedService;
public ICollection<Track> Tracks
{
get { return _tracks; }
}
public async void UpdateTracksAsync()
{
IsBusy = true;
_tracks.Clear();
var tracks = await _feedService.LoadAsync();
_tracks.AddRange(tracks);
IsBusy = false;
}
The View (bound through caliburn.micro convention)
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}" Margin="10">
<Grid.RowDefinitions>
<RowDefinition Height="auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<ListView Name="Tracks"
ItemTemplate="{StaticResource TrackDataTemplate}"
Grid.Row="1">
</ListView>
</Grid>
<DataTemplate x:Key="TrackDataTemplate">
<Grid cm:Bind.Model="{Binding}" Margin="0 0 0 5">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="10" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Image Name="Artwork" Height="100" Width="100"/>
<Grid Grid.Column="2">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<TextBlock Name="Title" Style="{StaticResource TrackTextStyle}" />
<TextBlock Name="Artist" Grid.Row="1" Style="{StaticResource TrackTextStyle}" />
<TextBlock Name="Album" Grid.Row="2" />
<TextBlock Name="ReleaseYear" Grid.Row="3" />
<TextBlock Name="Label" Grid.Row="4" />
</Grid>
</Grid>
</DataTemplate>
Feed Service
public Task<IEnumerable<Track>> LoadAsync()
{
var scraper = new TrackWebScraper(URL);
return scraper.Scrape();
}
I've tried replacing BindableCollection with the standard ObservableCollection with the same result. I'm certain my service is returning a collection of unique items. I can see the ListView clearing when the collection is cleared before grabbing the new items. What am I missing?

Try this
_tracks = null;
var tracks = await _feedService.LoadAsync();
_tracks = tracks;

Related

Is this TalkBack path through Xamarin.Android UI expected?

Say I create the following shared XAML:
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Button Grid.Row="0" Text="One" />
<Grid Grid.Row="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Button Grid.Column="0" Text="Two First" />
<Button Grid.Column="1" Text="Two Second" />
</Grid>
<Button Grid.Row="2" Text="Three" />
</Grid>
I then run this on an Android device and run the TalkBack screen reader. As I swipe forward through the UI, TalkBack moves from button "One", to button "Three", and then to buttons "Two First" and "Two Second". This doesn't match the order in which I've defined the UI, so is this expected? I get what I consider the expected navigation of moving through the buttons in order of "One"->"Two First"->"Two Second"->"Three", when running the same UI as a Xamarin.UWP app and using the Narrator screen reader.
I've found I can avoid the unexpected TalkBack navigation if I update the UI such that certain parts of the UI are balanced in how deep the UI is defined in the XAML hierarchy. For example, if I wrap button "Three" in a Grid, then I get the expected navigation path.
I can also avoid the unexpected TalkBack navigation if I add a TabIndex to everything that I want TalkBack to reach, but that'll need maintaining as the app UI evolves over time, and as I understand things, not all types of Xamarin.Forms control support TabIndex.
not sure if it's a problem from designs of Grid .From shared code , I think Grid maybe set the second Row as the low level of priority .Because the second Row define the Column individually .
If that is the logic about the design of Grid . You can have a try with define the Row and Column at the same level of priority .
Code as follow :
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Button Grid.Row="0"
Grid.ColumnSpan="2"
Text="One" />
<Button Grid.Row="1"
Grid.Column="0"
Text="Two First" />
<Button Grid.Row="1"
Grid.Column="1"
Text="Two Second" />
<Button Grid.Row="2"
Grid.Column="0"
Grid.ColumnSpan="2"
Text="Three" />
</Grid>

Can you define RowDefinition in style xamarin forms

I have the following
<Grid >
<Grid.RowDefinitions>
<RowDefinition Height="1.5*"></RowDefinition>
<RowDefinition Height="7.5*"></RowDefinition>
</Grid.RowDefinitions>
and I would like to define the Height in a Style or in a variable in the app.xaml.
<Grid.RowDefinitions>
<RowDefinition Height="{StaticResource myHeight}"></RowDefinition>
<RowDefinition Height="{StaticResource myHeight2}"></RowDefinition>
</Grid.RowDefinitions>
Is this possible? I have tried but I get an error.
The reason I want to achieve this is that on small devices I need to change the row height.
I would appreciate any tips or suggestions.
You can bind a model to ContentPage , then Grid can use binded data by model and row height can be setted by model data (contain row height paramaters).
For example , create a sample ViewModel(RowHeightClass) as follow :
using Xamarin.Essentials;
public class RowHeightClass
{
public GridLength rowFirstHeight { set; get; }
public GridLength rowSecondHeight { set; get; }
public RowHeightClass()
{
// here can add code set by device screen
var mainDisplayInfo = DeviceDisplay.MainDisplayInfo;
double screenheight = mainDisplayInfo.Height;
rowFirstHeight = new GridLength(DeviceDisplay * 0.2);
rowSecondHeight = new GridLength(DeviceDisplay * 0.4);
}
}
Binding it in ContentPage :
RowHeightClass rowHeightClass = new RowHeightClass();
BindingContext = rowHeightClass;
Used in XAML :
<Grid VerticalOptions="FillAndExpand"
HorizontalOptions="FillAndExpand">
<Grid.RowDefinitions>
<RowDefinition Height="{Binding rowFirstHeight}" />
<RowDefinition Height="{Binding rowSecondHeight}" />
<RowDefinition Height="100" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<BoxView Grid.Row="0"
Grid.Column="0"
BackgroundColor="Blue" />
<BoxView Grid.Row="1"
Grid.Column="0"
BackgroundColor="Red" />
<Button Grid.Row="2"
Grid.Column="0"
BackgroundColor="Yellow"
Clicked="Button_Clicked" />
</Grid>
Note : You can modify the constructor method of RowHeightClass to add method to set needed height by the size of device screen .
==================================Update=====================================
Using StaticResource also can set the heigh of row . Add a Resources for Grid or Application as follow :
<Grid VerticalOptions="FillAndExpand"
HorizontalOptions="FillAndExpand">
<Grid.Resources>
<ResourceDictionary>
<x:Double x:Key="SmallScreenRowheight">200</x:Double>
<x:Double x:Key="LargeScreenRowheight">400</x:Double>
</ResourceDictionary>
</Grid.Resources>
<Grid.RowDefinitions>
<RowDefinition Height="{StaticResource SmallScreenRowheight}" />
<RowDefinition Height="{StaticResource LargeScreenRowheight}" />
<RowDefinition Height="100" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<BoxView Grid.Row="0"
Grid.Column="0"
BackgroundColor="Blue" />
<BoxView Grid.Row="1"
Grid.Column="0"
BackgroundColor="Red" />
<Button Grid.Row="2"
Grid.Column="0"
BackgroundColor="Yellow"
Clicked="Button_Clicked" />
</Grid>

CustomView not rendered if I put inside a grid with RowDefinitions in Xamarin.Forms

I have loaded the views inside a grid as below,
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Entry x:Name="SearchTextBox"
Grid.Row="0"
HorizontalOptions="Fill"
Placeholder="Search"
VerticalOptions="Fill" />
<ListView x:Name="listView"
Grid.Row="1"
HorizontalOptions="Fill"
VerticalOptions="Fill" />
<local:CustomListView x:Name="customView"
Grid.Row="0"
ItemsSource="{Binding Items}">
</local:CustomListView >
</Grid>
Out of 3 views in the above code snippet, first two views are rendered properly. But the 3rd view(custom view) not rendered. CustomViews are not rendered only if I set RowDefinition as "Auto". So, anyone please tell why the custom view is not loaded if I set "Auto".
your CustomListView probably doesn't request a minimum size correctly, and as the middle row has a height of *, it takes all of the available space minus the minimum size requests.

How to setup Row/Column Definitions in Xamarin.Forms Xaml?

I managed to setup rows and columns from the code but couldn't move this settings to xaml:
grid.RowDefinitions = new RowDefinitionCollection {
new RowDefinition { Height = new GridLength(1, GridUnitType.Star) }
};
grid.ColumnDefinitions = new ColumnDefinitionCollection {
new ColumnDefinition { Width = new GridLength(1, GridUnitType.Star) }
};
The following doesn't work:
<Grid x:Name="grid" VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
...
</Grid>
From the documentation I managed to fetch only c# implementation
I also get the same behaviour (does not fill and expand) for a grid with a single cell (1 row / column, although I am not sure why we would ever need a grid with a single cell full size of screen), but it seems to work fine for a 2 x 2, 3 x 3 cell grid (have not tried others yet).
The Height="" and Width="" attributes are required in Xamarin Forms although I "think" they are not needed in WPF as the default assumes this is the case.
<ContentPage.Content>
<Grid VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand">
<Grid.RowDefinitions>
<RowDefinition Height="*"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"></ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Button Grid.Row="0" Grid.Column="0" Text="1"></Button>
<Button Grid.Row="1" Grid.Column="1" Text="2"></Button>
</Grid>
</ContentPage.Content>
Here is a sample
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Label Text="Top Left" Grid.Row="0" Grid.Column="0" />
<Label Text="Top Right" Grid.Row="0" Grid.Column="1" />
<Label Text="Bottom Left" Grid.Row="1" Grid.Column="0" />
<Label Text="Bottom Right" Grid.Row="1" Grid.Column="1" />
</Grid>

Windows Phone 8 - ASP.Net Master Page Equivalent

I'm new to Windows Phone 8 Development. I have developed ASP.NET websites before.
My pages (In WP8 Application) share the same headers and footers.
So what is the best method to implement a Master Page like in windows phone 8 ?
I've came across a few solutions that use Frame tag ; but they were not applicable.
Any help is highly appreciated.
PS: I'm using MVVM Light Toolkit
I came across this solution but it is a work around:
1- defining <ControlTemplatex:Key="Decorator" TargetType="ContentControl"> in App.xaml
2- in each page i want that template i just add <ContentControl Template="{StaticResource Decorator}">
Here is a little detailed sample:
App.xaml
<ControlTemplate x:Key="Decorator" TargetType="ContentControl">
<Grid x:Name="LayoutRoot">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="5*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid x:Name="HeaderPanel" Grid.Row="0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="4*" />
</Grid.ColumnDefinitions>
<Button x:Name="BackBtn" Grid.Column="0" />
<TextBlock Grid.Column="1" Text="{Binding Title}" />
</Grid>
<ContentPresenter Grid.Row="1" />
<Grid x:Name="BottomPanel" Grid.Row="2" Height="50">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Button Grid.Column="0" />
<Button Grid.Column="1" />
<Button Grid.Column="2" />
<Button Grid.Column="3" />
</Grid>
</Grid>
</ControlTemplate>
Now in any xaml page i want to embed that content template i just add the following:
<ContentControl Template="{StaticResource Decorator}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="5*" />
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Text="Grid Title" />
<Grid x:Name="ContentGrid" Grid.Row="1">
</Grid>
</ContentControl>
Resource: http://www.codeproject.com/Articles/82464/How-to-Embed-Arbitrary-Content-in-a-WPF-Control

Resources