65.9K
CodeProject 正在变化。 阅读更多。
Home

WPF 内存使用情况图表

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.91/5 (8投票s)

2011年12月17日

CPOL

2分钟阅读

viewsIcon

40519

downloadIcon

3842

一个基于 WPF Toolkit 图表包的 WPF 内存使用图表。

引言

此代码示例演示了如何在 WPF 中创建实时更新的内存使用图表。

背景

WPF Toolkit 提供了一个不错的图表包,它是可定制和可扩展的。 本文演示了如何使用此图表和一个调度计时器来创建一个模块化的内存监控控件。 该控件实时更新,提供当前 .NET 运行时内存使用情况。(注意:这是您的应用程序使用的托管内存的总(估计)量 - 它不包括不安全/本机代码。)

使用代码

您可以在 http://wpf.codeplex.com 获取完整的 WPF Toolkit。 在我的示例中,我只包含了基本的 DLL 和 DataVisualizations 包。

第一步是自定义图表的外观。 创建一个新的用户控件,并引用 WPFToolkit 和 System.Windows.Controls.DataVisualization.Toolkit。 当您粘贴下面的图表 XML 时,WPF 设计器应自动开始显示具有默认外观的图表。

<UserControl x:Class="WpfMemoryChart.MemoryChart"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
         xmlns:Charting="clr-namespace:System.Windows.Controls.
           DataVisualization.Charting;
           assembly=System.Windows.Controls.DataVisualization.Toolkit"
         xmlns:chartingprimitives="clr-namespace:System.Windows.Controls.
           DataVisualization.Charting.Primitives;
           assembly=System.Windows.Controls.DataVisualization.Toolkit"
         mc:Ignorable="d" >
    <Grid>
        <Charting:Chart Name="MemoryChartComponent"></Charting:Chart>  
    </Grid>
</UserControl>

我选择使用 AreaSeries,但您也可以使用折线图系列(例如,如果您希望图表看起来更像 Windows 任务管理器)。

默认情况下,WPF Toolkit 图表为系列中的每个数据点显示物理点。 您可以通过设置数据点样式来关闭此功能

<Charting:AreaSeries>
    <Charting:AreaSeries.DataPointStyle>
        <Style TargetType="Charting:AreaDataPoint">
            <Setter Property="Opacity" Value="0" />
            <Setter Property="Background" Value="Navy" />
        </Style>
    </Charting:AreaSeries.DataPointStyle>
</Charting:AreaSeries>
<Charting:Chart.Axes>
    <Charting:LinearAxis Orientation="Y" ShowGridLines="False" 
            Visibility="Hidden" Width="0" />
    <Charting:DateTimeAxis Orientation="X" Visibility="Hidden" 
            Height="0"></Charting:DateTimeAxis>
</Charting:Chart.Axes>

要更改颜色,请删除图表图例和轴标签。 我已经像这样覆盖了控件

<ControlTemplate TargetType="{x:Type Charting:Chart}">
    <Border Background="{TemplateBinding Background}" 
            BorderBrush="{TemplateBinding BorderBrush}" 
            BorderThickness="{TemplateBinding BorderThickness}" Padding="0">
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="*" />
            </Grid.RowDefinitions>
            <chartingprimitives:EdgePanel Name="ChartArea" 
                   Style="{TemplateBinding ChartAreaStyle}" 
                   Grid.Row="0" Margin="0">
                <Grid Panel.ZIndex="-1" Style="{TemplateBinding PlotAreaStyle}" />
                <Border Panel.ZIndex="10" BorderBrush="#FF919191" BorderThickness="0" />
            </chartingprimitives:EdgePanel>
        </Grid>
    </Border>
</ControlTemplate>

在 XAML 中以您喜欢的方式显示图表后,您可以创建一个调度计时器来更新其绑定的数据源。 在此项目中,我将图表绑定到 Florian Reischl 最初创建的 RingBuffer<T> 实现:http://florianreischl.blogspot.com/2010/01/generic-c-ringbuffer.html

我稍微修改了它,以便它实现 INotifyPropertyChanged。 这是为了它可以向任何绑定的 WPF 组件触发通知事件。 我首先创建一个表示数据点的对象,称为 MemorySample

public class MemorySample
{
    public long ByteCount { get; set; }
    public DateTime Timestamp { get; set; }
}

然后我们创建一个容量为 60 个项目的 RingBuffer(1 分钟的内存数据)。 我们启动一个调度计时器以每秒触发一次

public void InitMemoryWatch()
{
    // keep 60 seconds worth of memory by default
    const int memorySamples = 60;
    MemoryStats = new RingBuffer<MemorySample>(memorySamples);

    var dispatcherTimer = new System.Windows.Threading.DispatcherTimer();
    dispatcherTimer.Tick += DispatcherTimerTick;
    dispatcherTimer.Interval = new TimeSpan(0, 0, 1);
    dispatcherTimer.Start();
}

在处理程序中,我生成一个新的内存样本并将其添加到 RingBuffer

private void DispatcherTimerTick(object sender, EventArgs e)
{
    LatestMemorySample = new MemorySample
    {
        ByteCount = GC.GetTotalMemory(false),
        Timestamp = DateTime.Now
    };
    _memoryStats.Add(LatestMemorySample);
}

最后,我为所有这些数据结构创建绑定属性

private RingBuffer<MemorySample> _memoryStats;
public RingBuffer<MemorySample> MemoryStats
{
    get { return _memoryStats; }
    set
    {
        _memoryStats = value;
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs("MemoryStats"));
        }
    }
}
private MemorySample _latestMemorySample;
public MemorySample LatestMemorySample
{
    get { return _latestMemorySample; }
    set
    {
        _latestMemorySample = value;
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs("LatestMemorySample"));
        }
    }
}

现在我将图表绑定到这些属性

<Charting:AreaSeries VerticalAlignment="Stretch" 
                    HorizontalAlignment="Stretch" 
                    ItemsSource="{Binding Path=MemoryStats}" 
                    IndependentValuePath="Timestamp" 
                    DependentValuePath="ByteCount">

警告

当前版本的 WPF Toolkit 图表包存在一个很大的内存泄漏,该问题在以下文章中得到了解决:http://wpf.codeplex.com/discussions/216609

您必须获得一个在此泄漏修复后的更高版本才能在生产应用程序中使用内存图表(或者您可以按照作者的描述手动修补 WPF Toolkit 代码)。

© . All rights reserved.