<Canvas Background="Black">
<ItemsControl ItemsSource="{Binding Molecules}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemContainerStyle>
<Style>
<Setter Property="Canvas.Left" Value="{Binding X}"/>
<Setter Property="Canvas.Top" Value="{Binding Y}"/>
</Style>
</ItemsControl.ItemContainerStyle>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Ellipse Width="{Binding Diameter}"
Height="{Binding Diameter}"
Fill="{Binding Color}">
<Ellipse.Effect>
<DropShadowEffect Color="White"
BlurRadius="10"
Opacity="0.6"/>
</Ellipse.Effect>
</Ellipse>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Canvas>
//
public class MainVM: NotifyBase
{
private readonly DispatcherTimer tmr;
private readonly Random rnd = new Random();
private int maxWidth, maxHeight;
public ObservableCollection<Molecule> Molecules { get; }=new ObservableCollection<Molecule>();
public MainVM(Window win)
{
win.Loaded+=(s, e) =>
{
maxWidth=(int)win.ActualWidth-50;
maxHeight=(int)win.ActualHeight-50;
InitData(100);
StartAnimation();
};
tmr=new DispatcherTimer()
{
Interval=TimeSpan.FromMilliseconds(16),
};
tmr.Tick+=Tmr_Tick;
}
private void Tmr_Tick(object? sender, EventArgs e)
{
foreach (var molecule in Molecules)
{
molecule.X+=molecule.VX;
molecule.Y+=molecule.VY;
if (molecule.X<=0 || molecule.X>=maxWidth)
{
molecule.VX*=-1;
}
if (molecule.Y<=0 || molecule.Y>=maxHeight)
{
molecule.VY*=-1;
}
}
}
private void StartAnimation()
{
tmr.Start();
}
private void InitData(int count)
{
Molecules.Clear();
for(int i=0;i<count;i++)
{
Molecules.Add(new Molecule()
{
X=rnd.Next(0, maxWidth),
Y=rnd.Next(0, maxHeight),
VX=(rnd.NextDouble()-0.5)*5,
VY=(rnd.NextDouble()-0.5)*5,
Diameter=rnd.Next(10, 30),
Color=new SolidColorBrush(Color.FromRgb((byte)rnd.Next(0, 255),
(byte)rnd.Next(0, 255), (byte)rnd.Next(0, 255)))
});
}
}
}
![image]()
![image]()
//xaml
<Window x:Class="WpfApp42.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
WindowState="Maximized"
xmlns:local="clr-namespace:WpfApp42"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Canvas Background="Black">
<ItemsControl ItemsSource="{Binding Molecules}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemContainerStyle>
<Style>
<Setter Property="Canvas.Left" Value="{Binding X}"/>
<Setter Property="Canvas.Top" Value="{Binding Y}"/>
</Style>
</ItemsControl.ItemContainerStyle>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Ellipse Width="{Binding Diameter}"
Height="{Binding Diameter}"
Fill="{Binding Color}">
<Ellipse.Effect>
<DropShadowEffect Color="White"
BlurRadius="10"
Opacity="0.6"/>
</Ellipse.Effect>
</Ellipse>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Canvas>
</Window>
//cs
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Threading;
namespace WpfApp42
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
var vm = new MainVM(this);
this.DataContext=vm;
}
}
public class MainVM: NotifyBase
{
private readonly DispatcherTimer tmr;
private readonly Random rnd = new Random();
private int maxWidth, maxHeight;
public ObservableCollection<Molecule> Molecules { get; }=new ObservableCollection<Molecule>();
public MainVM(Window win)
{
win.Loaded+=(s, e) =>
{
maxWidth=(int)win.ActualWidth-50;
maxHeight=(int)win.ActualHeight-50;
InitData(100);
StartAnimation();
};
tmr=new DispatcherTimer()
{
Interval=TimeSpan.FromMilliseconds(16),
};
tmr.Tick+=Tmr_Tick;
}
private void Tmr_Tick(object? sender, EventArgs e)
{
foreach (var molecule in Molecules)
{
molecule.X+=molecule.VX;
molecule.Y+=molecule.VY;
if (molecule.X<=0 || molecule.X>=maxWidth)
{
molecule.VX*=-1;
}
if (molecule.Y<=0 || molecule.Y>=maxHeight)
{
molecule.VY*=-1;
}
}
}
private void StartAnimation()
{
tmr.Start();
}
private void InitData(int count)
{
Molecules.Clear();
for(int i=0;i<count;i++)
{
Molecules.Add(new Molecule()
{
X=rnd.Next(0, maxWidth),
Y=rnd.Next(0, maxHeight),
VX=(rnd.NextDouble()-0.5)*5,
VY=(rnd.NextDouble()-0.5)*5,
Diameter=rnd.Next(10, 30),
Color=new SolidColorBrush(Color.FromRgb((byte)rnd.Next(0, 255),
(byte)rnd.Next(0, 255), (byte)rnd.Next(0, 255)))
});
}
}
}
public class Molecule:NotifyBase
{
private double x;
public double X
{
get
{
return x;
}
set
{
if (value!=x)
{
x=value;
OnPropertyChanged(nameof(X));
}
}
}
private double y;
public double Y
{
get
{
return y;
}
set
{
if(value!=y)
{
y=value;
OnPropertyChanged(nameof(Y));
}
}
}
public double VX { get; set; }
public double VY { get; set; }
public double Diameter { get; set; }
public Brush Color { get; set; }
}
public class NotifyBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler? PropertyChanged;
public void OnPropertyChanged([CallerMemberName]string propName="")
{
var handler = PropertyChanged;
if(handler!=null)
{
handler?.Invoke(this, new PropertyChangedEventArgs(propName));
}
}
}
}