2012-12-03 36 views
8

我找到了a fun program,它允许你overlay snowflakes over your desktop and windows。作为编程挑战,我有兴趣试图弄清楚如何自己做到这一点。更何况这个程序是一个内存猪(如果它没有内存泄漏)。以下是我的开始。我试图让一个图像的基础知识,然后将扩大。移动元素像飘落的雪花

我真正想要的帮助是让图像更流畅自然地移动。


编辑:

我张贴在回答部分楼下的解决方案,但它是更多的CPU比我想,有什么想法?


WPF XAML代码:

<Window x:Class="MainWindow" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    AllowsTransparency="True" 
     WindowStyle="None" 
    Title="MainWindow" Height="350" Width="525" Background="Transparent" Topmost="True" WindowState="Maximized" ResizeMode="NoResize"> 
    <Grid Name="grid1"> 
     <Image Height="26" HorizontalAlignment="Left" Margin="{Binding flakeMargin}" Name="Image1" Stretch="Fill" VerticalAlignment="Top" Width="28" Source="/snowTest;component/Images/blue-pin-md.png" /> 
    </Grid> 
</Window> 

VB代码:

​​

片状类:

Imports System.ComponentModel 

Public Class flake 
    Implements INotifyPropertyChanged 

    Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged 

    Private Sub NotifyPropertyChanged(ByVal info As String) 
     RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(info)) 
    End Sub 

    Private Property startLeft As Integer = 300 
    Private Property left As Integer = left 
    Private Property top As Integer = 100 
    Private Property speed As Integer = 1 

    Public ReadOnly Property flakeMargin As Thickness 
     Get 
      Return New Thickness(left, top, 0, 0) 
     End Get 
    End Property 

    Public Sub move() 
     top += speed 
     left = (Math.Cos(top - 100)) * 6 + startLeft 
     NotifyPropertyChanged("flakeMargin") 
    End Sub 
End Class 
+6

不知道为什么,这让收,好像一个真正的问题给我。我的anser会:因为你试图在WPF中做每帧动画,你应该使用CompositionTarget.Redering事件而不是你自己的时钟。在渲染事件中,你可以调用你的“绘制”代码,这将是移动图像。您可能想要使用画布而不是网格作为主机元素 –

回答

1

你为什么要自己移动它,而不是使用动画?

如果您使用WPF的Animation(在Expression Blend中很容易做到这一点),我认为您将获得您正在寻找的平滑度,并且您可以在运动中获得一些变化,从而使它更真实。

WPF Expression Blend Videos

Basic Animation

+0

感谢您的建议。通过这个练习,我发现了Expression混合的存在。虽然看起来很整洁,但我目前对购买该软件并不特别感兴趣。我会做一些研究如何做没有表达式混合的WPF动画,但当然会感谢任何建议。 – volderArt

+0

你可以在Blend中做任何事情,你也可以在纯XAML中做,所以不需要购买Blend,它只是一个用来直观操纵XAML的GUI。 –

+0

是的,您必须购买Expression Blend,或者如果幸运的话,您可以通过您的工作获得带有MSDN(或Ultimate)的Visual Studio Premium。现在,您可以使用试用版。使用试用版来跟踪视频并了解xaml是完全值得的。 – Rhyous

2

这是我目前提出的解决方案:是什么最终成为最大的修正因子是我用过的画布,这让我在非整数增量移动,我也用cos函数更有效。它比我想要的要多CPU(25-30%)。有没有人有任何想法来减少对CPU的影响?

WPF/XAML:

<Window x:Class="MainWindow" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    AllowsTransparency="True" 
     WindowStyle="None" 
    Title="MainWindow" Height="350" Width="525" Background="Transparent" Topmost="True" WindowState="Maximized" ResizeMode="NoResize"> 
    <Canvas Name="canvas1"> 

    </Canvas> 
</Window> 

VB.NET主窗口:

Imports System.ComponentModel 

Class MainWindow 

    Dim bw As New BackgroundWorker 
    Dim flakes(17) As flake 

    Private Sub Window_Loaded(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs) Handles MyBase.Loaded 
     For i = 0 To flakes.Count - 1 
      flakes(i) = New flake 
      flakes(i).image.DataContext = flakes(i) 
      flakes(i).image.SetBinding(Canvas.LeftProperty, "left") 
      flakes(i).image.SetBinding(Canvas.TopProperty, "top") 
      canvas1.Children.Add(flakes(i).image) 
     Next 

     AddHandler bw.DoWork, AddressOf backgroundMover 
     bw.RunWorkerAsync() 
    End Sub 


    Private Sub backgroundMover() 
     While (True) 
      For Each f In flakes 
       f.move() 
      Next 
      System.Threading.Thread.Sleep(50) 
     End While 
    End Sub 
End Class 

VB.Net片类:

Imports System.ComponentModel 

Public Class flake 
    Implements INotifyPropertyChanged 

    Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged 

    Private Sub NotifyPropertyChanged(ByVal info As String) 
     RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(info)) 
    End Sub 

    Private Property startLeft As Double 
    Private Property _left As Double 
    Private Property _top As Double 
    Private Property speed As Double 
    Private Property amplitude As Double 
    Private Property period As Double 
    Public Property image As New Image 
    Private Shared Property r As New Random 

    Public Sub New() 
     _image.Width = 28 
     _image.Height = 26 
     _image.Source = New System.Windows.Media.Imaging.BitmapImage(New Uri("/snowTest;component/Images/blue-pin-md.png", UriKind.Relative)) 
     startFresh() 
    End Sub 

    Public ReadOnly Property left As Double 
     Get 
      Return _left 
     End Get 
    End Property 

    Public ReadOnly Property top As Double 
     Get 
      Return _top 
     End Get 
    End Property 

    Public Sub startFresh() 
     _top = -30 
     amplitude = r.Next(5, 35) 
     period = 1/r.Next(20, 60) 
     speed = r.Next(15, 25)/10 
     startLeft = r.Next(0, System.Windows.SystemParameters.PrimaryScreenWidth) 
    End Sub 

    Public Sub move() 
     If _top > System.Windows.SystemParameters.PrimaryScreenHeight Then 
      startFresh() 
     Else 
      _top += speed 
      _left = amplitude * Math.Cos(period * _top) + startLeft 
     End If 

     NotifyPropertyChanged("top") 
     NotifyPropertyChanged("left") 
    End Sub 
End Class