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();
}
}
}
}
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.
I've found a solution.
There's no flickering this way.