Search code examples
c#wpftimerperformancecounter

C# WPF MVVM | Use Performancecounter with Timer


I try to set up a very simple application. The application should display the current CPU Usage.

My view:

    <Grid>
        <Label Content="{Binding CpuUsage}" />
    </Grid>

My MainWindow.xaml.cs

        public MainWindow()
        {
            InitializeComponent();
            this.DataContext = new ViewModel();
        }

My Viewmodel:

public partial class ViewModel : ObservableObject
    {
        [ObservableProperty]
        private string _cpuUsage;
        public ViewModel()
        {
            SetTimerActions();
        }

        private void SetTimerActions()
        {
            var dispatcherTimer = new DispatcherTimer();
            dispatcherTimer.Tick += new EventHandler(SetCpuUsageVariable);
            dispatcherTimer.Interval = new TimeSpan(0, 0, 0, 1);
            dispatcherTimer.Start();
        }

        private void SetCpuUsageVariable(object sender, EventArgs e)
        {
            var systemCpuUsage = Utils.GetCPUUsage();
            CpuUsage = $"CPU: {systemCpuUsage}";
        }
    }

My Utils:

        public static string GetCPUUsage()
        {
            PerformanceCounter cpuCounter = new PerformanceCounter("Process", "% Processor Time", Process.GetCurrentProcess().ProcessName);

            var CPUUsagePercentage = cpuCounter.NextValue() / Environment.ProcessorCount;

            Trace.WriteLine($"CPU Usage: {string.Format("{0:N2}", CPUUsagePercentage)}");

            return Convert.ToString(CPUUsagePercentage);
        }

The output is always 0. The reason is because .NextValue() need to compare to the "old" value but I invoke the method every second.

What is a good way to solve it?

@Answer to mike: Yes, it's possible but the values are still wrong.

I changed my code to your suggested solution but the values are wrong / nonsense.
I started CPU Stress and my CPU load is: ~80%.
The output is:

...
CPU Usage: 0,00
CPU Usage: 0,00
CPU Usage: 0,35
CPU Usage: 0,36
CPU Usage: 0,35
CPU Usage: 0,00
CPU Usage: 0,37
CPU Usage: 0,68
CPU Usage: 0,00
CPU Usage: 0,00
...

Solution

  • I'd make the cpuCounter private and static within your utils so that the new object is created only once within the whole Utils:

    private static PerformanceCounter _cpuCounter = new PerformanceCounter("Process", "% Processor Time", Process.GetCurrentProcess().ProcessName);
    

    And then your GetCPUUsage looks like:

    public static string GetCPUUsage()
    {
        var CPUUsagePercentage = _cpuCounter.NextValue() / Environment.ProcessorCount;
        Trace.WriteLine($"CPU Usage: {string.Format("{0:N2}", CPUUsagePercentage)}");
        return Convert.ToString(CPUUsagePercentage);
    }
    

    And, in general, I'd make GetCPUUsage a float or double and take care of the formatting in SetCpuUsageVariable in the view model.