WPF animation slowly when the mouse is in a window

I am trying to create a moving rectangle (rect). This is the corresponding code:

let timer = new Threading.DispatcherTimer();
timer.Tick.Add(fun _ -> Canvas.SetLeft(rect, Canvas.GetLeft(rect)+0.01) |> ignore)
timer.Start()

The problem is that the animation is slower if I move the mouse over the window. If I set the timer interval:

timer.Interval <- TimeSpan.FromMilliSeconds(30.0)

Then the animation doesn’t work at all. What am I doing wrong? Thank.

0
source share
1 answer

I have two suggestions:

1) if you use f # interactive check, you have set up a WFP event loop. F # interactive sets the winforms eventloop event by default, there is some compatibility between winforms and WFP event loops, but not everything works correctly. To set the event loop, use the following script:

#light

// When running inside fsi, this will install a WPF event loop
#if INTERACTIVE

#I "c:/Program Files/Reference Assemblies/Microsoft/Framework/v3.0";;
#I "C:/WINDOWS/Microsoft.NET/Framework/v3.0/WPF/";;
#r "presentationcore.dll";;
#r "presentationframework.dll";;
#r "WindowsBase.dll";;

module WPFEventLoop = 
    open System
    open System.Windows
    open System.Windows.Threading
    open Microsoft.FSharp.Compiler.Interactive
    open Microsoft.FSharp.Compiler.Interactive.Settings
    type RunDelegate<'b> = delegate of unit -> 'b 

    let Create() = 
        let app  = 
            try 
                // Ensure the current application exists. This may fail, if it already does.
                let app = new Application() in 
                // Create a dummy window to act as the main window for the application.
                // Because we're in FSI we never want to clean this up.
                new Window() |> ignore; 
                app 
             with :? InvalidOperationException -> Application.Current
        let disp = app.Dispatcher
        let restart = ref false
        { new IEventLoop with
             member x.Run() =   
                 app.Run() |> ignore
                 !restart
             member x.Invoke(f) = 
                 try disp.Invoke(DispatcherPriority.Send,new RunDelegate<_>(fun () -> box(f ()))) |> unbox
                 with e -> eprintf "\n\n ERROR: %O\n" e; rethrow()
             member x.ScheduleRestart() =   ()
                 //restart := true;
                 //app.Shutdown()
        } 
    let Install() = fsi.EventLoop <-  Create()

WPFEventLoop.Install();;

#endif

2) , , , . , ( width , ):

#light

open System
open System.Windows
open System.Windows.Controls
open System.Windows.Shapes
open System.Windows.Media
open System.Windows.Media.Animation


let rect = new Rectangle(Fill = new SolidColorBrush(Colors.Red), Height = 20., Width = 20., Name = "myRectangle")

let canvas = 
    let c = new Canvas()
    c.Children.Add(rect) |> ignore
    c

NameScope.SetNameScope(canvas, new NameScope());
canvas.RegisterName(rect.Name, rect)

let window = new Window(Content = canvas)

let nfloat f = new Nullable<float>(f)

let myDoubleAnimation = new DoubleAnimation(From = nfloat 20.0, To = nfloat 50.0,
                                            Duration = new Duration(TimeSpan.FromSeconds(5.)),
                                            RepeatBehavior = RepeatBehavior.Forever)
let myStoryboard = 
    let sb = new Storyboard()
    sb.Children.Add(myDoubleAnimation)
    sb

Storyboard.SetTargetName(myDoubleAnimation, rect.Name);
Storyboard.SetTargetProperty(myDoubleAnimation, new PropertyPath(Rectangle.WidthProperty))

rect.Loaded.Add(fun _ -> myStoryboard.Begin canvas)

let main() =
    let app = new Application()
    app.Run window |> ignore

[<STAThread>]
do main()
+4

Source: https://habr.com/ru/post/1695740/


All Articles