1

I have a circle on canvas and my animation rotates a line to right and left,which is the circle's Radius, with A and D keys. But while it is being rotated, it has too lag and it freezes for some time. Here my code:

CameraView.xaml:

<UserControl x:Class="IKA.Views.CameraView"
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
  xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
  mc:Ignorable="d" 
    xmlns:mui="http://firstfloorsoftware.com/ModernUI"
    xmlns:cal="http://www.caliburnproject.org"
    xmlns:model="clr-namespace:IKA.ViewModels"
    xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
    xmlns:ika="clr-namespace:IKA"
    d:DataContext="{x:Type model:CameraViewModel}"
    d:DesignHeight="300" d:DesignWidth="300"
    PreviewKeyDown="Move"     
         >
<Grid x:Name="grid">
    <Grid.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="/Resources/DirectionControl.xaml" />
                <ResourceDictionary Source="/Resources/MediaPlayer.xaml" />
            </ResourceDictionary.MergedDictionaries>
            <ControlTemplate  x:Key="PlayStyle" TargetType="Button">
                <Button Style="{StaticResource PlayButtonStyle}"  Width="100" Height="100" HorizontalAlignment="Center" />
            </ControlTemplate>
            <ControlTemplate x:Key="StopStyle" TargetType="Button">
                <Button Style="{StaticResource StopButtonStyle}"  Width="100" Height="100" HorizontalAlignment="Center" />
            </ControlTemplate>
        </ResourceDictionary>
    </Grid.Resources>
    <Grid.RowDefinitions>
        <RowDefinition Height="*"/>
        <RowDefinition Height="*"/>
        <RowDefinition Height="*"/>
        <RowDefinition Height="*"/>
        <RowDefinition Height="*"/>
        <RowDefinition Height="*"/>
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="2*" />
        <ColumnDefinition Width="*" />
    </Grid.ColumnDefinitions>
    <Rectangle x:Name="BeforeVideo" Fill="Black" Grid.Row="0" Grid.RowSpan="6" />
    <MediaElement x:Name="myControl"  Grid.Row="0" Grid.RowSpan="6" Stretch="Fill"  LoadedBehavior="Manual" UnloadedBehavior="Stop" />
    <Button x:Name="PlayButton" Grid.Row="0"  Grid.RowSpan="6" Click="OnPlayButtonClick" Template="{StaticResource PlayStyle}">Play</Button>
    <Button x:Name="StopButton" Grid.Row="0" Grid.RowSpan="6" Click="OnStopButtonClick" Template="{StaticResource StopStyle}">Stop</Button>
    <Label x:Name="Degree" Grid.Column="1" Grid.Row="3" HorizontalAlignment="Center" VerticalAlignment="Bottom"  Content="0"/>
    <Canvas x:Name="canvas" Grid.Column="1" Grid.Row="4" Grid.RowSpan="2" Height="100" Width="100" Focusable="True">
        <Ellipse  Stretch="Fill" Fill="White" StrokeThickness="3" Stroke="Black" Width="100" Height="100"/>
        <Line Name="CurrentLine" X1="50" Y1="50" X2="50" Y2="0" Stroke="Black" StrokeThickness="1" RenderTransformOrigin="1,1">
            <Line.RenderTransform>
                <RotateTransform x:Name="LineRotateTransform" Angle="0" ></RotateTransform>
            </Line.RenderTransform>
        </Line>
        <Line  X1="0" Y1="50" X2="10" Y2="50" Stroke="Black" StrokeThickness="1" RenderTransformOrigin="1,1" />
        <Line  X1="90" Y1="50" X2="100" Y2="50" Stroke="Black" StrokeThickness="1" RenderTransformOrigin="1,1" />
    </Canvas>
</Grid>

And my CameraView.xaml.cs:

    public partial class CameraView : UserControl
{
    public Line currentLine { get; set; }
    public DoubleAnimation myDoubleAnimation { get; set; }
    public Storyboard myStoryboard { get; set; }

    private void Animation(object sender,RoutedEventArgs e)
    {
        canvas.Focus();
        myDoubleAnimation = new DoubleAnimation();
        myDoubleAnimation.To = 0;
        myDoubleAnimation.Duration = new Duration(TimeSpan.FromMilliseconds(10));
        // Create the storyboard.
         myStoryboard = new Storyboard();
        myStoryboard.Children.Add(myDoubleAnimation);
        Storyboard.SetTarget(myDoubleAnimation,CurrentLine);
        Storyboard.SetTargetProperty(myDoubleAnimation,
            new PropertyPath("RenderTransform.(RotateTransform.Angle)"));
    }

    public CameraView()
    {
        InitializeComponent();
        this.DataContext = ViewModelsContainer.CameraViewModel;
        myControl.Visibility = Visibility.Visible;
        StopButton.Visibility = Visibility.Hidden;
        PlayButton.Visibility = Visibility.Visible;
        //string source = "http://" + ConnectionTemp.IPAdress + ":8080";
        string source = "http://192.168.1.159:8080/";
        //string source = "http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4";
        myControl.Source = new Uri(source);
        this.Loaded += Animation;
    }

    private void OnPlayButtonClick(object sender, RoutedEventArgs e)
    {
        BeforeVideo.Visibility = Visibility.Hidden;
        PlayButton.Visibility = Visibility.Hidden;
        myControl.Visibility = Visibility.Visible;
        PlayVideo();
        StopButton.Visibility = Visibility.Visible;
        canvas.Focus();
    }

    private void OnStopButtonClick(object sender, RoutedEventArgs e)
    {
        myControl.Pause();
        StopButton.Visibility = Visibility.Hidden;
        PlayButton.Visibility = Visibility.Visible;
        canvas.Focus();
    }

    private async void PlayVideo()
    {
        await PlayAsync();
    }

    private Task PlayAsync()
    {
        Task task = Task.Run(() => this.Dispatcher.Invoke(new Action(() => { myControl.Play(); })));
        return task;
    }
    public  void Move(object sender, KeyEventArgs e)
    {
        if(e.IsDown) {
            if (e.Key == Key.D)
            {
                hareket(true);
            }
            if (e.Key == Key.A)
            {
                hareket(false);
            }
        }
    }

    private void hareket(bool IncreaseOrDecrease)
    {
        if ((IncreaseOrDecrease)&&(myDoubleAnimation.To<= 90 ))
        {
            myDoubleAnimation.To++;
        }
        else if ((!IncreaseOrDecrease) && (myDoubleAnimation.To >= -90))
        {
            myDoubleAnimation.To--;
        }
        myStoryboard.Children.Add(myDoubleAnimation);
            myStoryboard.Begin();
            Degree.Content = myDoubleAnimation.To;
    }

}
Kerem Zaman
  • 529
  • 1
  • 5
  • 18
  • Perhaps it's because you are effectively spamming the `haraket` method. Which creates a brand new `DoubleAnimation` every time it's called. As you can expect, this might not be very efficient. – Mike Eason Jul 24 '15 at 11:11
  • @MikeEason I think so, but how can I rotate the line with key events with something else? – Kerem Zaman Jul 24 '15 at 11:15
  • What are you trying to achieve by this: `Task task = Task.Run(() => this.Dispatcher.Invoke(new Action(() => { myControl.Play(); })));` ? It doesn't make sense to me. Perhaps, you wanted `Task task = Dispatcher.InvokeAsync(() => myControl.Play()).Task` ? – noseratio Jul 24 '15 at 11:33
  • @Noseratio it is for play asynchronously video. They are almost same. – Kerem Zaman Jul 24 '15 at 11:59
  • Maybe you could start your animation on keydown and stop it onkeyup? – Sebastian L Jul 24 '15 at 12:30
  • @SebastianL I have just tried it, pausing storyboard onkeyup. But the problem happens when the key is hold. So, I don't think it is about keyup. – Kerem Zaman Jul 24 '15 at 13:00
  • My point is that `myControl.Play()` is still executed on the main UI thread. Whatever is going on there is probably the reason for lagging. You can probably offload some non-visual work to a worker thread (with `Task.Run`), but you still need to draw video frames on the main thread. Check [this](http://stackoverflow.com/a/21592778/1768303). – noseratio Jul 24 '15 at 13:11
  • My problem happens when myControl.Play() doesn't run, too. It is not about it. Also, while it is working I can run other UI works well @Noseratio – Kerem Zaman Jul 24 '15 at 13:15
  • @KeremZaman this is because as long as the key is down you are changing a value which is used by the GUI and so you cause the GUI to be invalid every time you access the keyevent – Sebastian L Jul 24 '15 at 14:26

1 Answers1

0

I have solved the problem so:

       public  void Move(object sender, KeyEventArgs e)
    {
        if(e.IsDown && !isPressed)
        {
            isPressed = true;
            if (e.Key == Key.D)
            {
                hareket(true);
            }
            if (e.Key == Key.A)
            {
                hareket(false);
            }
        }
        else
        {
            isPressed = false;
        }
    }
    private void hareket(bool IncreaseOrDecrease)
    {
        myStoryboard.Children.Remove(myDoubleAnimation);
        if ((IncreaseOrDecrease)&&(myDoubleAnimation.To < 90 ))
        {
            myDoubleAnimation.To++;
        }
        else if ((!IncreaseOrDecrease) && (myDoubleAnimation.To > -90))
        {
            myDoubleAnimation.To--;
        }
        myStoryboard.Children.Add(myDoubleAnimation);
            myStoryboard.Begin();
            Degree.Content = myDoubleAnimation.To;
    }

The real fact solving my problem is that adding myStoryboard.Children.Remove(myDoubleAnimation) to hareket method. I assume that it was trying to begin all MyDoubleAnimations, so it got more laggy after each keydown.

Thanks everybody for their helps and reccomendations.

Kerem Zaman
  • 529
  • 1
  • 5
  • 18