簡體   English   中英

在現代 UI (Metro) 圖表中以編程方式 (MVVM) 添加 ChartSeries

[英]Adding ChartSeries programmatically (MVVM) in Modern UI (Metro) Charts

我一直在為我的項目尋找一個好看的圖表可視化解決方案,我終於找到了它( https://modernuicharts.codeplex.com )。 我也在那里的討論板上發布了這個問題,但我沒有回復......

我一直在玩一些圖表,我真的很喜歡它們。 非常光滑和美麗。 有一件事我需要更多信息,那就是我如何在運行時添加 ChartSeries。

編輯:我設法在運行時添加了欄,但有一些我似乎無法弄清楚的錯誤。 讓我們從一張圖片開始:

圖片

正如您在圖像中看到的,當我縮放窗口時,軸上的標題是正確的並且可以縮放。 這里的問題是酒吧。 條形似乎有固定的寬度,不想適應屏幕。 我這樣做的方式如下:

在 XAML 中,我像這樣放置控件:

<chart:StackedColumnChart ChartTitle="Total"
                          ChartSubTitle="(800)"
                          Series="{Binding Bars}">
</chart:StackedColumnChart>

在我后面的代碼中,我添加了這樣的 Bars:

using System;
using System.Collections.Generic;
using De.TorstenMandelkow.MetroChart;
using System.Collections.ObjectModel;

namespace AutoShop
{
class OccupationChartGroupViewModel
{
    public OccupationChartGroupViewModel()
    {
        List<Tuple<string, int, double>> reqProdHoursPerWeek = DbServiceSegmentRequirement.GetProdSegReq();
        List<Tuple<string, int, double>> reqPlanHoursPerWeek = DbServiceSegmentRequirement.GetPlanSegReq();
        List<Tuple<string, int, double>> reqRepairHoursPerWeek = DbServiceSegmentRequirement.GetRepairSegReq();

        List<Tuple<string, int, double>> reqHoursPerWeek = new List<Tuple<string, int, double>>();
        reqHoursPerWeek.AddRange(reqProdHoursPerWeek);
        reqHoursPerWeek.AddRange(reqPlanHoursPerWeek);
        reqHoursPerWeek.AddRange(reqRepairHoursPerWeek);

        reqHoursPerWeek.Sort();

        switch (reqHoursPerWeek[0].Item2.ToString())
        {
            case "0":
                if (reqHoursPerWeek[1].Item2.ToString() != "1")
                    reqHoursPerWeek.Add(new Tuple<string, int, double>(reqHoursPerWeek[0].Item1, 1, 0.0));
                else
                    if (reqHoursPerWeek[1].Item1 != reqHoursPerWeek[0].Item1)
                        reqHoursPerWeek.Add(new Tuple<string, int, double>(reqHoursPerWeek[0].Item1, 1, 0.0));
                break;

            case "1":
                reqHoursPerWeek.Add(new Tuple<string, int, double>(reqHoursPerWeek[0].Item1, 0, 0.0));
                if (reqHoursPerWeek[1].Item2.ToString() != "2")
                    reqHoursPerWeek.Add(new Tuple<string, int, double>(reqHoursPerWeek[0].Item1, 2, 0.0));
                else
                    if (reqHoursPerWeek[1].Item1 != reqHoursPerWeek[0].Item1)
                        reqHoursPerWeek.Add(new Tuple<string, int, double>(reqHoursPerWeek[0].Item1, 2, 0.0));
                break;

            case "2":
                reqHoursPerWeek.Add(new Tuple<string, int, double>(reqHoursPerWeek[0].Item1, 0, 0.0));
                reqHoursPerWeek.Add(new Tuple<string, int, double>(reqHoursPerWeek[0].Item1, 1, 0.0));
                break;

            default: break;
        }

        reqHoursPerWeek.Sort();

        Bars = new ObservableCollection<De.TorstenMandelkow.MetroChart.ChartSeries>();

        ObservableCollection<TestClass> blocks = new ObservableCollection<TestClass>();

        foreach (Tuple<string, int, double> reqHours in reqHoursPerWeek)
        {
            string group = reqHours.Item2.ToString() == "2" ? "Order1" : reqHours.Item2.ToString() == "1" ? "Order2" : reqHours.Item2.ToString() == "0" ? "Order3" : "Unknown";

            blocks.Add(new TestClass() { Category = group, Number = reqHours.Item3 });

            if (reqHoursPerWeek.IndexOf(reqHours) + 1 < reqHoursPerWeek.Count)
            {
                if (reqHours.Item1 != reqHoursPerWeek[reqHoursPerWeek.IndexOf(reqHours) + 1].Item1)
                {
                    ChartSeries chartSerie = new ChartSeries();
                    chartSerie.SeriesTitle = reqHours.Item1;
                    chartSerie.DisplayMember = "Category";
                    chartSerie.ValueMember = "Number";
                    chartSerie.ItemsSource = blocks;
                    Bars.Add(chartSerie);

                    blocks = new ObservableCollection<TestClass>();
                }
            }
            else
            {
                ChartSeries chartSerie = new ChartSeries();
                chartSerie.SeriesTitle = reqHours.Item1;
                chartSerie.DisplayMember = "Category";
                chartSerie.ValueMember = "Number";
                chartSerie.ItemsSource = blocks;
                Bars.Add(chartSerie);
            }
        }
    }

    public ObservableCollection<ChartSeries> Bars { get; private set; }
}

// class which represent a data point in the chart
public class TestClass
{
    public string Category { get; set; }

    public double Number { get; set; }
}
}

最后,我在 XAML 查看器中設計時遇到的錯誤是:

**NullReferenceException: Object reference not set to an instance of an object.**

**Stacktrace**
at De.TorstenMandelkow.MetroChart.ChartBase.UpdateDataContextOfSeries()
at De.TorstenMandelkow.MetroChart.ChartBase.InternalDataContextChanged()
at De.TorstenMandelkow.MetroChart.ChartBase.DataContextWatcher_Changed(DependencyObject sender, DependencyPropertyChangedEventArgs args)
at System.Windows.DependencyObject.OnPropertyChanged(DependencyPropertyChangedEventArgs e)
at System.Windows.FrameworkElement.OnPropertyChanged(DependencyPropertyChangedEventArgs e)
at System.Windows.DependencyObject.NotifyPropertyChange(DependencyPropertyChangedEventArgs args)
at System.Windows.DependencyObject.UpdateEffectiveValue(EntryIndex entryIndex, DependencyProperty dp, PropertyMetadata metadata, EffectiveValueEntry oldEntry, EffectiveValueEntry& newEntry, Boolean coerceWithDeferredReference, Boolean coerceWithCurrentValue, OperationType operationType)
at System.Windows.DependencyObject.InvalidateProperty(DependencyProperty dp, Boolean preserveCurrentValue)
at System.Windows.Data.BindingExpressionBase.Invalidate(Boolean isASubPropertyChange)
at System.Windows.Data.BindingExpression.TransferValue(Object newValue, Boolean isASubPropertyChange)
at System.Windows.Data.BindingExpression.Activate(Object item)
at System.Windows.Data.BindingExpression.AttachToContext(AttachAttempt attempt)
at System.Windows.Data.BindingExpression.MS.Internal.Data.IDataBindEngineClient.AttachToContext(Boolean lastChance)
at MS.Internal.Data.DataBindEngine.Task.Run(Boolean lastChance)
at MS.Internal.Data.DataBindEngine.Run(Object arg)
at MS.Internal.Data.DataBindEngine.OnLayoutUpdated(Object sender, EventArgs e)
at System.Windows.ContextLayoutManager.fireLayoutUpdateEvent()
at System.Windows.ContextLayoutManager.UpdateLayout()
at System.Windows.UIElement.UpdateLayout()

**InnerException: None**

您正在使用 Series 而不是 SeriesSource 屬性(我嘗試使用 SeriesSource 但由於某種原因圖表顯示為空)。 無論如何,錯誤確實發生了,因為在 MVVM 調用 Series 綁定的 get 方法之前調用了上述方法,因此在 ChartBase.cs 的以下定義中將 Series 設為 null。 我希望你的解決方案中有這個項目,否則打開他們提供的代碼,更新代碼,編譯並引用生成的 dll。

    private void UpdateDataContextOfSeries()
    {
        onApplyTemplateFinished = false;

        //ADDED CODE STARTS
        if(this.Series != null)
        {
        //ADDED CODE ENDS
        foreach (var newItem in this.Series)
        {
            if (newItem is FrameworkElement)
            {
                (newItem as FrameworkElement).DataContext = this.DataContext;
            }
        }
        onApplyTemplateFinished = true;
        UpdateSeries();            
        //ADDED CODE STARTS
        }
        //ADDED CODE ENDS
    }    

只需要在運行循環和應用更新之前檢查系列是否為空。 一旦系列被獲取,這個方法也會被調用。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM