Image flickering in Windows RT App

2019-05-28 15:53发布

I have a Windows RT app where I programmatically change the Bitmap in the Image component. All works well with the XAML and the code below except the flickering we see when the image is changed.

What should I change to get rid of the flickering?

XAML:

<Page
x:Class="iSurfBrainViewProto01.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:iSurfBrainViewProto01"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Grid HorizontalAlignment="Left" VerticalAlignment="Top" Margin="0">
    <Grid.RowDefinitions>
        <RowDefinition Height="*"/>
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="8*"/>
        <ColumnDefinition Width="1*"/>
        <ColumnDefinition Width="4*" />
    </Grid.ColumnDefinitions>
    <Grid HorizontalAlignment="Center" VerticalAlignment="Top"
                                                         Margin="20,20,0,20">
        <Grid.RowDefinitions>
            <RowDefinition Height="8*"/>
            <RowDefinition/>
        </Grid.RowDefinitions>
        <Grid HorizontalAlignment="Left" Height="768" 
              VerticalAlignment="Top" Width="768">
            <Image x:Name="image1" Source="BrainImg/axis/ax-128.jpg"/>
            <Image x:Name="image2" Source="BrainImg/axis/ax-128.png"/>
        </Grid>
        <Slider HorizontalAlignment="Left" VerticalAlignment="Top" 
               Width="768" Grid.Row="1" Maximum="255" Value="128" 
               x:Name="slider1"  ValueChanged="Slider_ValueChanged_1"/>
    </Grid>
    <Grid HorizontalAlignment="Left" VerticalAlignment="Top" 
                        Grid.Column="1" Margin="0,10"  MinHeight="768">
        <Grid.RowDefinitions>
            <RowDefinition/>
            <RowDefinition/>
            <RowDefinition/>
            <RowDefinition/>
            <RowDefinition/>
            <RowDefinition/>
            <RowDefinition/>
            <RowDefinition/>
            <RowDefinition/>
        </Grid.RowDefinitions>
        <Button HorizontalAlignment="Left" VerticalAlignment="Top" Width="85" 
          Height="100" BorderThickness="0">
            <Image Source="ax-1.jpg" />
        </Button>
        <Button HorizontalAlignment="Center" VerticalAlignment="Top" 
             Grid.Row="1" Width="85" Height="100" BorderThickness="0">
            <Image Source="ax-2.jpg" />
        </Button>
        <Button HorizontalAlignment="Right" VerticalAlignment="Top" 
             Grid.Row="2" Width="85" Height="100" BorderThickness="0">
            <Image Source="ax-3.jpg" />
        </Button>
        <Button HorizontalAlignment="Left" VerticalAlignment="Top" 
             Grid.Row="3" Width="85" Height="100" BorderThickness="0">
            <Image Source="ax-4.jpg" />
        </Button>
        <Button HorizontalAlignment="Center" VerticalAlignment="Top" 
             Grid.Row="4" Width="85" Height="100" BorderThickness="0">
            <Image Source="ax-5.jpg" />
        </Button>
        <Button HorizontalAlignment="Right" VerticalAlignment="Top" 
             Grid.Row="5" Width="85" Height="100" BorderThickness="0">
            <Image Source="ax-6.jpg" />
        </Button>
    </Grid>
    <Grid HorizontalAlignment="Left" VerticalAlignment="Top" 
         Grid.Column="2" Margin="10,10,0,0">
        <Grid.RowDefinitions>
            <RowDefinition Height="1*" />
            <RowDefinition Height="7*"/>
        </Grid.RowDefinitions>
        <TextBlock Text="Structure Selected: This Struct" 
         HorizontalAlignment="Left" MinHeight="50" FontSize="26" />
        <WebView Source="http://www.mywebsite.com" 
         HorizontalAlignment="Left" 
         Grid.Row="1" MinWidth ="500" MinHeight="760" />
    </Grid>
</Grid>
</Page>

Code:

namespace Test01
{
public sealed partial class MainPage : Page
{
    int currentSlice = 128;
    String axis = "ax-";
    public MainPage()
    {
        this.InitializeComponent();
    }

    public void displayImages()
    {
        BitmapImage bitmapImage = image1.Source as BitmapImage;
        bitmapImage.UriSource = null;
        image1.Source = null;

        BitmapImage bitmapImage2 = image2.Source as BitmapImage;
        bitmapImage2.UriSource = null;
        image2.Source = null;
        Uri image1Uri = new Uri(this.BaseUri,
           "BrainImg/axis/" + axis + currentSlice + ".jpg");
        image1.Source = new BitmapImage(image1Uri);
        image2.Source = new BitmapImage(new Uri(this.BaseUri,
           "BrainImg/aseg/" + axis + currentSlice + ".png"));
    }

    protected override void OnNavigatedTo(NavigationEventArgs e)
    {
    }

    private void Slider_ValueChanged_1(object sender, 
                               RangeBaseValueChangedEventArgs e)
    {
        if (slider1 != null) {
            currentSlice = (int) slider1.Value;
            displayImages();
        }
    }
 }
}

2条回答
一纸荒年 Trace。
2楼-- · 2019-05-28 16:32

The first thing I see is that you unnecessarily set the image source to null before setting it to a new value, though it might not matter actually. The problem is that downloading/decoding an image takes a moment. So you should either preload all images before you start using them (which might use too much memory and thus not be feasible) or use two image controls in place of one and use them as a sort of swap chain where you have one visible image and one that is hidden and when you want to switch the displayed image - update the source of the hidden image and only switch visibilities of images once the bitmap is loaded. It might not be straightforward though since the BitmapImage might not start loading until the hosting image control is visible, so you might need to set opacity to 0.01 instead of hiding it completely or try to make it visible and then immediately invisible until the bitmap is loaded. If the bitmap is already loaded - its PixelWidth would be > 0.

查看更多
一纸荒年 Trace。
3楼-- · 2019-05-28 16:42

I've found a solution.

IRandomAccessStream stream = await storageFile.OpenAsync(FileAccessMode.Read);
BitmapImage bitmapImage = new BitmapImage();

if (await bitmapImage.SetSourceAsync(stream))
{
    image1.source = bitmapImage;
}

There's no flickering this way.

查看更多
登录 后发表回答