2013-04-09 2 views
1

В приложении WinRT у меня есть один FlipView myFlipView с изображениями и одним изображением myImage. На событии myFlipView в SelectionChanged есть следующий метод:Ошибка в методе async

async private void myFlipView_SelectionChanged(object sender, SelectionChangedEventArgs e) 
    { 
     if (myFlipView == null) return; 

     Uri newUri = new Uri("ms-appx://" + (((BitmapImage)(((Image)(((ContentControl)(myFlipView.SelectedItem)).Content)).Source)).UriSource.AbsolutePath)); 
     StorageFile file = await StorageFile.GetFileFromApplicationUriAsync(newUri); 
     WriteableBitmap wb = new WriteableBitmap(1, 1); 

     if (file != null) 
     { 
      using (IRandomAccessStream fileStream = await file.OpenAsync(Windows.Storage.FileAccessMode.Read)) 
      { 
       await wb.SetSourceAsync(fileStream); 
      } 
     } 

     wb = ModifyPicture(wb); 
     myImage.Source = wb; 
    } 

Подводя итог он находит УИР текущего изображения в myFlipView и установить этот образ в myImage, но с некоторыми изменениями, определенных в ModifyPicture. Он отлично работает на планшетах, но на компьютерах с мышами есть одна ошибка. Когда я быстро нажимаю стрелки, прикрепленные к FlipView, myImage показывает неправильное изображение. Например, если в myFlipView у меня есть 10 изображений (p1, p2, ..., p10) и в настоящее время p1 выбрано, когда я изменяюсь на p2 на myImage, также появляется p2. Но когда я часто нажимаю очень быстро в FlipView, у меня есть, например, p9 и myImage p8. Я полагаю, это связано с тем, что метод называется много раз, но я не знаю, как его исправить. Заранее благодарю за помощь :)

+0

Можете ли вы дать мне весь проект, чтобы я мог проверить? – Xyroid

ответ

1

В дополнении или вместо отмены внутренних задач, как ma_il упоминает - вы можете разбить/отменить асинхронное выполнение метода, если вы обнаружили, что его следует отменить. Например.

private int myFlipView_SelectionChangedCallId; 
async private void myFlipView_SelectionChanged(object sender, SelectionChangedEventArgs e) 
{ 
    if (myFlipView == null) return; 

    var callId = ++myFlipView_SelectionChangedCallId; 

    Uri newUri = new Uri("ms-appx://" + (((BitmapImage)(((Image)(((ContentControl)(myFlipView.SelectedItem)).Content)).Source)).UriSource.AbsolutePath)); 
    StorageFile file = await StorageFile.GetFileFromApplicationUriAsync(newUri); 

    if (callId != myFlipView_SelectionChangedCallId) return; 

    WriteableBitmap wb = new WriteableBitmap(1, 1); 

    if (file != null) 
    { 
     using (IRandomAccessStream fileStream = await file.OpenAsync(Windows.Storage.FileAccessMode.Read)) 
     { 
      await wb.SetSourceAsync(fileStream); 

      if (callId != myFlipView_SelectionChangedCallId) return; 
     } 
    } 

    wb = ModifyPicture(wb); 
    myImage.Source = wb; 
} 

Кроме того, если ваш метод ModifyPicture делает любую тяжелую обработку пикселей - вы хотите, чтобы запустить его в фоновом потоке и ждать его.

+0

Я использовал решение Filip Skakun, и теперь он работает правильно. Спасибо за помощь :) –

+0

Nie ma za co. :) –

2

Возможно, вам стоит сохранить уже запущенную задачу/IAsyncOperation и отменить ее, если обработчик события снова вызван до его завершения.

See this article on how to cancel running tasks.

Псевдо-код (как я не знаю, C#):

Task loadAndSetImage(uri) { 
    return new Task... 
} 

flipView_SelectionChanged { 
    if (myFlipView == null) return; 
    if (this.runningTask && !this.runningTask.IsCanceled) { 
     this.runningTask.Cancel(); 
    } 
    Uri newUri = new Uri("ms-appx://" + (((BitmapImage)(((Image)(((ContentControl)(myFlipView.SelectedItem)).Content)).Source)).UriSource.AbsolutePath)); 

    this.runningTask = loadAndSetImage(newUri); 
    this.runningTask.ContinueWith((t) => this.runningTask = null;); 
} 
Смежные вопросы