2008-12-26 4 views
0

J'essaye de créer un rectangle mobile (rect). Voici le code correspondant:L'animation WPF ralentit lorsque la souris est dans la fenêtre

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

Le problème est que l'animation est plus lente si je déplace la souris sur la fenêtre. Si je règle l'intervalle de la minuterie:

timer.Interval <- TimeSpan.FromMilliSeconds(30.0) 

Ensuite, l'animation ne fonctionne pas du tout. Qu'est-ce que je fais mal? Merci.

Répondre

4

J'ai deux suggestions:

1) si vous utilisez f # interactive vérifier que vous avez installé une boucle d'événements du PAM. F # interactive met en place un eventloop winforms par défaut, il y a une certaine compatibilité entre les winforms et les boucles d'événements WFP, mais tout ne fonctionne pas correctement. Pour installer la boucle d'événements utilisez le script suivant:

#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) Je ne l'ai pas testé cela aussi bien, mais je pense que l'utilisation d'un story-board d'animation donnera ÉTOUFFEZ des résultats plus cohérents, plutôt que d'utiliser une minuterie. Je pense que cela ressemblerait à quelque chose comme (en changeant la propriété de largeur n'a pas fonctionné comment changer la position):

#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() 
+0

Merci pour vos suggestions. Parce que vous avez dit que cela pourrait être un problème avec F # interactif, j'ai fait le même exemple en C#. Le code C# ne fonctionnait pas non plus. Mon problème était que le mouvement de 0,01 par tic est bien trop bas. Je pensais que 1.0 serait la fenêtre entière, donc 0.01 serait 1% de la fenêtre. – Jules

+0

Si je change 0.01 à 1.0 alors l'animation fonctionne! Apparemment, si vous ne définissez pas d'intervalle pour une minuterie, elle exécute des tics aussi rapidement que possible (donc elle bougerait malgré le 0.01 faible). La boucle d'événement WPF est très utile. Jusqu'à présent, je réinitialise F # interactif tout le temps. Merci pour le story board aussi. – Jules

+0

Malheureusement, je ne peux pas utiliser une solution de story-board parce que l'animation n'est pas une ligne droite. J'essaie de créer une simulation de planètes avec gravité pour en savoir plus sur WPF. Merci de votre aide! – Jules

Questions connexes