在WPF中使用Winform中自帶的畫圖控制元件Chart,模擬動態更新資料

pandawangyt發表於2020-11-07

一、如何在WPF中使用Chart控制元件

1、新增引用

右鍵專案引用-新增引用,在程式集中選擇下圖三個東東
在WPF中使用Winform中自帶的畫圖控制元件Chart,模擬動態更新資料

2、新增名稱空間
xmlns:Wchart="clr-namespace:System.Windows.Forms.DataVisualization.Charting;assembly=System.Windows.Forms.DataVisualization"
3、引用

注意要放在WindowsFormsHost標籤內部

<WindowsFormsHost Grid.Row="2">
	<Wchart:Chart x:Name="ChartPlot"/>
</WindowsFormsHost>

二、程式碼

先上最終的效果圖,如下圖,可選擇圖中顯示的點數,以及更新速度。
在這裡插入圖片描述

1、佈局設計
<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="50"/>
        <RowDefinition Height="*"/>
    </Grid.RowDefinitions>
    <StackPanel Orientation="Horizontal" VerticalAlignment="Center" HorizontalAlignment="Left">
        <StackPanel Orientation="Horizontal" VerticalAlignment="Center">
            <RadioButton Name="rbtn_highspeed" Content="100ms" Style="{StaticResource rabtn}" Click="rbtn_highspeed_Click"/>
            <RadioButton Name="rbtn_lowspeed" Content="500ms" IsChecked="True" Style="{StaticResource rabtn}" Click="rbtn_lowspeed_Click"/>
        </StackPanel>
        <StackPanel Orientation="Horizontal" VerticalAlignment="Center">
            <RadioButton Name="rbtn_manypoint" Content="50點" IsChecked="True" Style="{StaticResource rabtn}" Click="rbtn_manypoint_Click"/>
            <RadioButton Name="rbtn_littlepoint" Content="20點" Style="{StaticResource rabtn}" Click="rbtn_littlepoint_Click"/>
        </StackPanel>
        <Button Name="btn_start" Content="開始" Margin="10,1" Click="btn_start_Click"/>
    </StackPanel>
    <WindowsFormsHost Grid.Row="2">
        <Wchart:Chart x:Name="ChartPlot"/>
    </WindowsFormsHost>
</Grid>

rabtn是自定義的一個RadioButton樣式資原始檔,感興趣的可以看看(不看也沒影響)

<Style x:Key="rabtn" TargetType="RadioButton">
  <Setter Property="Template">
      <Setter.Value>
          <ControlTemplate TargetType="RadioButton">
              <Border>
                  <Grid Background="Transparent">
                      <Grid.ColumnDefinitions>
                          <ColumnDefinition Width="20"/>
                          <ColumnDefinition Width="Auto"/>
                      </Grid.ColumnDefinitions>
                      <Rectangle Name="rec" Grid.Column="0" Width="15" Height="15" 
                                 Stroke="Black" Fill="White"/>
                      <ContentPresenter Grid.Column="1" VerticalAlignment="Center" Margin="5,1"/>
                  </Grid>
              </Border>
              <ControlTemplate.Triggers>
                  <Trigger Property="IsChecked" Value="True">
                      <Setter TargetName="rec" Property="Fill" Value="RoyalBlue"/>
                      <Setter TargetName="rec" Property="Stroke" Value="Transparent"/>
                  </Trigger>
              </ControlTemplate.Triggers>
          </ControlTemplate>
      </Setter.Value>
  </Setter>
</Style>
2、邏輯實現
public partial class MainWindow : Window
{
    private ChartArea AREA = new ChartArea() { Name = "Line" };             // 畫圖區域
    private Series SERIES = new Series();                                   // 一條折線
    private Legend LEGEND = new Legend();                                   // 一個圖例
    private System.Timers.Timer timer = new System.Timers.Timer();          // 定時器
    private int INTERVAL = 500;                                             // 定時器時間
    private int MAXPLOT = 100;                                              // 圖中最多點數
    
    public MainWindow()
    {
        InitializeComponent();

        // area樣式設定
        AREA.AxisX.Enabled = AxisEnabled.True;                  // 使X軸可用
        AREA.AxisX.IntervalAutoMode = IntervalAutoMode.VariableCount;   // X 軸標籤數量,由顯示的資料點數量自動調整
        AREA.AxisY.Enabled = AxisEnabled.True;
        AREA.AxisY.MajorTickMark.Enabled = false;
        AREA.CursorX.IsUserSelectionEnabled = true;             // 滑鼠選擇區域放大

        // series設定
        SERIES.ChartArea = "Line";
        SERIES.ChartType = SeriesChartType.Line;                // 折線圖
        SERIES.Name = "隨機數";
        SERIES.ToolTip = "數值:\n#VALY";                      // 滑鼠懸浮在點上面顯示提示(不夠靈敏)

        // legend設定
        LEGEND.Alignment = System.Drawing.StringAlignment.Near;         // legend靠近顯示,不然太佔用地方了
        LEGEND.Docking = Docking.Left;                                  // 靠左顯示
        LEGEND.DockedToChartArea = "Line";                              // 預設圖例是顯示在圖的外面,佔用地方
        LEGEND.IsDockedInsideChartArea = true;                          // 將圖例放在圖裡面
        LEGEND.BackColor = System.Drawing.Color.Transparent;            // 無背景色,不然會擋住折線

        // 新增area series legend
        ChartPlot.ChartAreas.Add(AREA);
        ChartPlot.Series.Add(SERIES);
        ChartPlot.Legends.Add(LEGEND);

        // timer設定
        timer.Enabled = false;
        timer.Interval = INTERVAL;
        timer.Elapsed += Timer_Elapsed;
    }
    /// <summary>
    /// 定時更新圖
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void Timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
    {
        Application.Current.Dispatcher.Invoke(() =>
        {
            if (SERIES.Points.Count >= MAXPLOT)
            {
                for(int i = 0; i < SERIES.Points.Count - MAXPLOT - 1; i++)
                {
                    SERIES.Points.RemoveAt(0);
                }
            }
            SERIES.Points.AddXY(DateTime.Now.ToString("HH:mm:ss"), GetRandomNumber());
            // 重新整理圖
            AREA.RecalculateAxesScale();
        });
    }
    /// <summary>
    /// 開始、暫停 畫圖
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void btn_start_Click(object sender, RoutedEventArgs e)
    {
        if (timer.Enabled)
        {
            timer.Enabled = false;
            btn_start.Content = "開始";
        }
        else
        {
            timer.Enabled = true;
            btn_start.Content = "暫停";
        }
    }
    /// <summary>
    /// 改變間隔時間
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void rbtn_highspeed_Click(object sender, RoutedEventArgs e)
    {
        timer.Interval = 100;
    }
    private void rbtn_lowspeed_Click(object sender, RoutedEventArgs e)
    {
        timer.Interval = 500;
    }
    /// <summary>
    /// 改變圖中最多點數
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void rbtn_manypoint_Click(object sender, RoutedEventArgs e)
    {
        MAXPLOT = 50;
    }
    private void rbtn_littlepoint_Click(object sender, RoutedEventArgs e)
    {
        MAXPLOT = 20;            
    }
    /// <summary>
    /// 產生隨機數
    /// </summary>
    /// <returns></returns>
    private int GetRandomNumber()
    {
        byte[] buffer = Guid.NewGuid().ToByteArray(); 
        int iSeed = BitConverter.ToInt32(buffer, 0); 
        Random random = new Random(iSeed);
        return random.Next(-100, 100);
    }
}

3、最後

動態效果圖來啦!!!!!!!!!

在這裡插入圖片描述

寫在最後:最近做wpf一個專案,需要畫圖。可惜wpf沒有自帶的畫圖控制元件,而查詢了很多了第三方控制元件(OxyPlot、Visifire、Dynamic Data Display)並嘗試用了一下,唔,好難啊,主要是資料好少,還是winform的chart用的舒服。在此做個記錄,以後用到的話也方便。

有問題歡迎交流。

相關文章