Question

In WinRT app I have one FlipView myFlipView with some pictures and one Image myImage. On myFlipView's event SelectionChanged there is the following method:

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;
    }

To sum up it finds uri of current image in myFlipView and set that image in myImage but with some modifications defined in ModifyPicture. It works perfectly on tablets but on computers with mouses there is one error. When I click arrows attached to FlipView very fast then myImage shows wrong picture. For example if in myFlipView I have 10 pictures (p1, p2, ..., p10) and currently p1 is chosen, when I change to p2 on myImage also p2 appears. But when I click very fast sometimes in FlipView I have for example p9 and in myImage p8. I suppose it is connected with fact that method is called many times but I don't know how to fix it. Thank you in advance for help :)

Était-ce utile?

La solution 2

In addition to or instead of cancelling internal tasks as ma_il mentions - you could break/cancel your async method execution if you detect that it should be canceled. E.g.

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;
}

Also if your ModifyPicture method does any heavy pixel processing - you would want to run it on a background thread and await it.

Autres conseils

You should probably save the Task/IAsyncOperation that's already running and cancel it if the event handler is called again before it completes.

See this article on how to cancel running tasks.

Pseudo-code (as I don't know 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; );
} 
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top