Если вы обновляете пользовательский интерфейс, это необходимо сделать в основном потоке пользовательского интерфейса.
Когда вы вызываете
await Task.Run( () => AddRow() );
Это означает, что AddRow (и любые вызываемые им методы) не работают в потоке пользовательского интерфейса и вызовет сбой.
Что выможет попробовать что-то вроде этого (не проверено):
private async void OnScrolled(object sender, ScrolledEventArgs e)
{
await Task.Run(async () =>
{
ScrollView scroller = (ScrollView)sender;
//threshhold == bottom of scrollveiw + height of one image (aka just before it's visible)
double threashold = (e.ScrollY + scroller.Height) + preview_size;
//if we touch the threshhold...
if (threashold > scroller.ContentSize.Height)
{
//one row of images
int TilePreload = (Tiles.Count + ColCount);
//if the next row exceeds the total available post count, download and append more posts
if (TilePreload >= Posts.Count)
{
//we have reached the end of our postlist, we must get more!
var results = await Task.Run(()=>FetchResults<List<CPost>>()).ConfigureAwait(false);
Posts.AddRange( results);
}
}
});
//then, add the tiles to UI
AddRow();
}
Кроме того, почему GetResponse не является асинхронным методом ?? (использование .Result
блокирует поток) И, таким образом, почему FetchResults> () не асинхронен?
Чтобы сделать GetResponse асинхронным:
public static async Task<string> GetResponse(string page, Dictionary<String, String> arguments, bool IsPost = false)
{
HttpMethod Method = IsPost ? HttpMethod.Post : HttpMethod.Get;
var request = new HttpRequestMessage(Method, page)
{
Content = new FormUrlEncodedContent(arguments)
};
HttpResponseMessage httpResponse = await Client.SendAsync(request).ConfigureAwait(false);
if (httpResponse.IsSuccessStatusCode)
{
return await httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false);
}
return null;
}
В том виде, как у вас это было, у вас было много потоков, которые прыгают вокруг и блокируют потоки кода из-за использования .Result
Итак, поместив всекод, который не требует выполнения в потоке пользовательского интерфейса внутри Задачи, вы можете избежать любого кода, выполняющегося в потоке пользовательского интерфейса, до тех пор, пока он вам не понадобится, т.е. при добавлении элементов пользовательского интерфейса.
Использование .ConfigureAwait(false)
означает, что когда эта задача завершится, следующий код не будет маршалирован обратно в вызывающий поток, сохраняя маршалинг некоторого потока, который занимает время. Когда .ConfigureAwait(false)
не вызывается, по умолчанию используется значение .ConfigureAwait(true)
, что означает «Когда эта задача выполнена, направьте следующий код обратно в поток, из которого была вызвана эта задача. Поэтому, выполнив вышеописанное, вы должны избежать некоторых задержек потоков и, надеюсь, эторазрешит скачок.
Хотя вам может потребоваться выполнить тест, потому что с учетом вышеизложенного событие OnScrolled будет по-прежнему запускаться, пока эта работа завершается. Поэтому вы можете установить флажок только для запуска кодачтобы получить новые предметы один раз, например:
bool _isGettingNewItems;
private async void OnScrolled(object sender, ScrolledEventArgs e)
{
// Don't run the code to get new items if it is already running
if (_isGettingNewItems)
return;
_isGettingNewItems = true;
await Task.Run(async () =>
{
...
});
//then, add the tiles to UI
AddRow();
// finished getting new items, so set the boolean back to false
_isGettingNewItems = false;
}