I have created a Winforms App that uses the Open Hardware Monitor to display PC temps in a gauge format using Live Charts. I am aware that the following code causes the UI to become unresponsive as the charts are updated but I am not able to figure out how to implement any form of threading to work with this or how to change how I have coded the application to keep the UI responsive. The timer will tick every two seconds which fetches the values and updates the gauges.
References added to the project are:
- OpenHardwareMonitorLib
- LiveCharts.Winforms + Dependencies
See my code below, any advice would be appreciated.
UserControls.TempGauge
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Windows.Media;
namespace PCDashboard.UserControls
{
public partial class TempGauge : UserControl
{
public TempGauge(string name)
{
try
{
//Initialize
InitializeComponent();
//Gauge Properties
this.Name = name;
gaugeName.Text = name;
gauge.Uses360Mode = true;
gauge.From = 0;
gauge.To = 110;
gauge.Value = 0;
gauge.HighFontSize = 60;
gauge.Base.Foreground = System.Windows.Media.Brushes.White;
gauge.InnerRadius = 0;
gauge.GaugeBackground = Classes.Colours.Blue;
}
catch (Exception)
{
}
}
}
}
MainForm
using OpenHardwareMonitor.Hardware;
using PCDashboard.Classes;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace PCDashboard.Forms
{
public partial class MainForm : Form
{
public MainForm()
{
InitializeComponent();
}
private void MainForm_Load(object sender, EventArgs e)
{
try
{
GetSystemTemps(false);
timer.Enabled = true;
}
catch (Exception)
{
}
}
private void exitToolStripMenuItem_Click(object sender, EventArgs e)
{
Close();
}
private void GetSystemTemps(bool UpdateGauge)
{
try
{
UpdateVisitor updateVisitor = new UpdateVisitor();
Computer computer = new Computer();
computer.Open();
//Which components to read?
computer.CPUEnabled = true;
computer.GPUEnabled = true;
computer.MainboardEnabled = true;
computer.RAMEnabled = true;
computer.Accept(updateVisitor);
foreach (IHardware hardware in computer.Hardware)
{
foreach (ISensor sensor in hardware.Sensors.Where(
x => x.SensorType == SensorType.Temperature))
{
if (UpdateGauge)
{
UserControls.TempGauge tempGauge =
((UserControls.TempGauge)gaugeContainer
.Controls[sensor.Name]);
if (tempGauge != null)
{
tempGauge.gauge.Value = Math.Round(
double.Parse(sensor.Value.ToString()), 0);
}
}
else
{
UserControls.TempGauge tempGauge =
new UserControls.TempGauge(sensor.Name);
gaugeContainer.Controls.Add(tempGauge);
}
}
}
computer.Close();
}
catch (Exception)
{
}
}
private void timer_Tick(object sender, EventArgs e)
{
try
{
GetSystemTemps(true);
}
catch (Exception)
{
}
}
}
}

My suggestion is to separate the data retrieval from the presentation. This way you will be able to offload the heavy work of data retrieval to a background thread, without having to worry how you will update the UI controls at the same time. Here is how you could make a
GetSensorDatamethod that fetches the data as an array ofValueTuple<string, double>elements, representing the name and the value of each sensor:Then you could use the
Task.Runmethod to offload the heavy work of retrieving the data to a background thread (aThreadPoolthread). This method returns aTask, that could be awaited asynchronously so that the code below theawaithas available data to work with.Finally you'll have to make the event handlers
async: