Chen
Chen

Reputation: 41

UI performance issue when I try to change the width of the ItemsControl in WPF

I'm making a dynamic lyrics player using the ItemsControl from the answer to this question.

I use two ItemsControls that are stacked on top of each other and both are placed in different Canvas (to get the actual width of the text currently being displayed), Canvas are placed in the Grid to ensure that the Canvas will appear in the correct position in the window, like this:

<Grid>
    <Canvas x:Name="MainBackLineCanvas" Grid.Column="0" Grid.Row="0">
        <ItemsControl x:Name="MainBackLine" ItemsSource="{Binding}">
        ...
        </ItemsControl>
    </<Canvas>
    <Canvas x:Name="MainColorLineCanvas" Grid.Column="0" Grid.Row="0">
        <ItemsControl x:Name="MainColorLine" ItemsSource="{Binding}">
        ...
        </ItemsControl>
    </Canvas>
</Grid>

The effect of this window is as follows:
enter image description here

The MainBackLine(the blue text) will be fully displayed at the beginning, the width of the MainColorLine(the yellow text) is set to 0 at the beginning, and the width will increase as the song time increases.

I used a DispatcherTimer to change its width. My code is as follows:

DispatcherTimer TextFlashTimer = new DispatcherTimer();
TextFlashTimer.Interval = new TimeSpan(0, 0, 0, 0, 100);
TextFlashTimer.Tick += TextFlash;

private void TextFlash(object? sender, EventArgs e)
{
    //playTimePercent is the percentage of the playback progress of the current sentence, which is a Double variable
    MainColorLine.Width = ((playTimePercent > 0 && playTimePercent <1) ? playTimePercent : 1) * MainBackLine.ActualWidth;
}

When I run this code, the width of the MainColorLine will change very slowly and not smoothly. I've tried changing the DispatcherTimer's Interval, or using DoEvents, but nothing works.

Is there any way to make it smoother please.

Upvotes: 2

Views: 79

Answers (1)

mm8
mm8

Reputation: 169420

Try to use a DoubleAnimation to animate the width, e.g.:

double width = ((playTimePercent > 0 && playTimePercent < 1) ? playTimePercent : 1) * MainBackLine.ActualWidth;
DoubleAnimation doubleAnimation = new DoubleAnimation(width, new Duration(TimeSpan.FromMilliseconds(100)));
MainColorLine.BeginAnimation(FrameworkElement.WidthProperty, doubleAnimation);

Upvotes: 2

Related Questions