2008-12-26 62 views
0

我正在尝试创建一个移动的矩形(rect)。这是相关的代码:当鼠标在窗口中时WPF动画变慢

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

问题是,如果我将鼠标移动到窗口上,动画会变慢。如果我设置定时器的时间间隔:

timer.Interval <- TimeSpan.FromMilliSeconds(30.0) 

然后动画根本不起作用。我究竟做错了什么?谢谢。

回答

4

我有两个建议:

1)如果您使用F#交互检查已安装了世界粮食计划署的事件循环。 F#交互默认情况下设置了winforms eventloop,在winforms和WFP事件循环之间有一些兼容性,但并非所有工作都能正确执行。要安装事件循环使用下面的脚本:

#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)我没有测试过这太清楚,但我想用一个动画故事板会给浓烟更一致的结果,而不是使用一个计时器。我认为这将看起来像(改变宽度属性还没有计算出如何改变位置):

#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

感谢您的建议。因为你说这可能是F#交互式的问题,我在C#中做了同样的例子。 C#代码也没有工作。我的问题是每个tick的0.01移动太低。我认为1.0将是整个窗口,所以0.01将是窗口的1%。 – Jules 2008-12-26 10:53:58