What I would like to create (it doesn't have to be very precise, it's just for entertainment purposes):
Install WriteableBitmapEx package:
Install-Package WriteableBitmapEx
Code:
<Window x:Class="WpfApp1.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"
mc:Ignorable="d" Width="256" Height="256">
<Grid>
<Image x:Name="Image1" Stretch="Fill" />
</Grid>
</Window>
Code:
#nullable enable
using System;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Threading;
namespace WpfApp1
{
public partial class MainWindow
{
private readonly WriteableBitmap _bitmap;
private readonly DispatcherTimer _timer;
private int _bitmapCursor;
public MainWindow()
{
InitializeComponent();
Loaded = MainWindow_Loaded;
_bitmap = BitmapFactory.New(256, 256);
Image1.Source = _bitmap;
_timer = new DispatcherTimer(
TimeSpan.FromMilliseconds(20),
DispatcherPriority.Render,
Tick,
Dispatcher.CurrentDispatcher
);
}
private void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
_timer.Start();
}
private void Tick(object? sender, EventArgs e)
{
var cy = _bitmap.Height * 0.5;
var y = (int)(cy Math.Sin(DateTime.Now.TimeOfDay.TotalSeconds) * cy);
_bitmap.DrawLine(_bitmapCursor, 0, _bitmapCursor, _bitmap.PixelHeight - 1, Colors.Transparent);
_bitmap.SetPixel(_bitmapCursor, y, Colors.Red);
_bitmapCursor ;
_bitmapCursor %= _bitmap.PixelWidth;
}
}
}
Here I simply I erase a 1 pixel wide rectangle ahead the value I'm drawing, in your case, erase a larger rectangle to get the effect you want.
See that you'll need to keep history of previous value and draw a line from it instead to have a solid drawing.
Also, you may want to look at these libraries as well:
It's not 100% perfect, because your ECG image has blank space to the left and right of it, but if you clip it it'll look better. All you have to do now is bind all those Duration
properties to a value in your view model that you set based on the person's BPM.