8

我发现了一个有趣的程序,它可以让你在桌面和窗口上覆盖雪花。作为一项编程挑战,我有兴趣自己尝试弄清楚如何做到这一点。更不用说这个程序有点占用内存(如果它没有内存泄漏的话)。下面是我的开始。我正在尝试用一张图片来了解基础知识,然后再进行扩展。

我真正需要帮助的是使图像移动更流畅自然。


编辑:

我在答案部分的下方发布了一个解决方案,但它比我想要的 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

    Class MainWindow
        Dim bw As BackgroundWorker = New BackgroundWorker
        Dim flake0 As New flake

        Private Sub Window_Loaded(sender As System.Object, e As System.Windows.RoutedEventArgs) Handles MyBase.Loaded
            grid1.DataContext = flake0
            AddHandler bw.DoWork, AddressOf backgroundMover
            bw.RunWorkerAsync()
        End Sub

        Private Sub backgroundMover(ByVal sender As Object, ByVal e As System.ComponentModel.DoWorkEventArgs)
            While (True)
                flake0.move()
                System.Threading.Thread.Sleep(100)
            End While
        End Sub
    End Class

薄片类:

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
4

2 回答 2

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
于 2012-12-05T00:20:37.630 回答
1

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

如果你使用 WPF 的动画(这在 Expression Blend 中很容易做到),我认为你会得到你想要的平滑度,并且你可以获得一些运动变化,使它更真实。

WPF 表达式混合视频

基础动画

于 2012-12-04T03:35:29.577 回答