根据服务返回的数据动态创建Silverlight RadChart SeriesMappings

时间:2012-03-19 21:38:42

标签: silverlight telerik

我有一项服务将返回0或更多组数据。数据结构如下所示:

public class ReportData
{
    public List<SeriesSet> SeriesSet {get;set;}
}

public class SeriesSet
{
    public DateTime ItemDate {get;set;}
    public List<SeriesItem> SeriesItem {get;set;}
}

public class SeriesItem
{
    public string ItemType {get;set;}
    public double ItemValue {get;set;}
}

我的服务将返回包含SeriesSets列表的ReportData。 SeriesSet数据包含SeriesItems列表。 SeriesSet中的每个SeriesItem必须是我的图表中相应系列中的数据项(即单独的行或条),用于该SeriesSet的特定日期。我想根据服务返回的内容在图表中动态创建系列。

我想我需要首先根据创建系列映射来识别返回的不同ItemType。

我遇到的一个问题是数据来自异步的Web服务。当数据进入我的viewmodel时,如何在视图中使用正确的绑定创建系列映射?

从我创建图表的方式来看,似乎我需要在从视图模型中获取数据之前定义系列映射?

任何指针?

1 个答案:

答案 0 :(得分:1)

我最近做了类似的事情。我的SeriesMappings的ItemSources已绑定,但SeriesMappings本身和绑定是在代码隐藏中创建的。

我的视图模型在其数据全部加载时触发了一个事件。视图处理了事件并将新的SeriesMapping对象添加到图表中。以下是创建SeriesMapping对象的一些代码。

void AddBarSeriesMapping(string itemsSourceBindingPath, string legendLabel, string itemFieldName = null)
{
    this.AddSeriesMapping(itemsSourceBindingPath, legendLabel, CreateBarSeriesDefinition(), itemFieldName);
}

void AddLineSeriesMapping(string itemsSourceBindingPath, string legendLabel, string itemFieldName = null)
{
    this.AddSeriesMapping(itemsSourceBindingPath, legendLabel, CreateLineSeriesDefinition(), itemFieldName);
}

void AddSeriesMapping(string itemsSourceBindingPath, string legendLabel, ISeriesDefinition seriesDefinition, string itemFieldName)
{
    //
    // Set label and type (bar/line/etc).
    //
    SeriesMapping seriesMapping = new SeriesMapping
    {
        ChartArea = this.Chart.DefaultView.ChartArea,
        LegendLabel = legendLabel,
        SeriesDefinition = seriesDefinition
    };

    //
    // Bind to items source.
    //
    BindingOperations.SetBinding(seriesMapping, SeriesMapping.ItemsSourceProperty, new Binding(itemsSourceBindingPath));

    //
    // Map items to the Y value, and set field name if the items source is not a list of numeric values.
    //
    var itemMapping = new ItemMapping { DataPointMember = DataPointMember.YValue };
    if (itemFieldName != null)
    {
        itemMapping.FieldName = itemFieldName;
    }
    seriesMapping.ItemMappings.Add(itemMapping);

    this.Chart.SeriesMappings.Add(seriesMapping);
}

private static ISeriesDefinition CreateBarSeriesDefinition()
{
    return new BarSeriesDefinition
    {
        ShowItemLabels = false,
        ShowItemToolTips = true,
        ItemToolTipFormat = "#Y",
        InteractivitySettings = DefaultInteractivitySettings
    };
}

private static ISeriesDefinition CreateLineSeriesDefinition()
{
    return new LineSeriesDefinition
    {
        ShowItemLabels = false,
        ShowItemToolTips = true,
        ItemToolTipFormat = "#Y",
        InteractivitySettings = DefaultInteractivitySettings
    };
}

private static InteractivitySettings DefaultInteractivitySettings;

static ChartSummaryView()
{
    DefaultInteractivitySettings = new InteractivitySettings
    {
        HoverScope = InteractivityScope.Series,
        SelectionScope = InteractivityScope.Item
    };
}

更新:

为了让视图模型将数据和映射信息传递给视图,也许你可以做这样的事情。

public class SeriesMappingInfo
{
    public int DataSourceIndex { get; set; } // Index in ViewModel.DataSources
    public string LegendLabel { get; set; }
    // Other properties to tell the view how to create the mapping...
}

public class ViewModel
{
    public event EventHandler DataLoaded;
    public double?[][] DataSources { get; private set; }
    public SeriesMappingInfo[] Mappings { get; private set; }

    private void OnDataRetrievedFromServer(ReportData data)
    {
        // TODO: Translate data into something SeriesMappings can bind to, and set DataSources property.
        // TODO: Assemble info for creating SeriesMappings, and set Mappings property.

        // Tell the view everything is ready.
        if (this.DataLoaded != null)
        {
            this.DataLoaded(this, EventArgs.Empty);
        }
    }
}

public class View : UserControl
{
    public View()
    {
        this.DataContextChanged += new DependencyPropertyChangedEventHandler(View_DataContextChanged);
        // InitializeComponent, etc.
    }

    private void View_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
    {
        var viewModel = e.NewValue as ViewModel;
        if (viewModel != null)
        {     
            this.CreateSeriesMappings(viewModel.Mappings);
            viewModel.DataLoaded += new EventHandler(ViewModel_DataLoaded);
        }
    }

    private void ViewModel_DataLoaded(object sender, EventArgs e)
    {
        var viewModel = sender as ViewModel;
        if (viewModel != null)
        {
            this.CreateSeriesMappings(viewModel.Mappings);
        }
    }

    private void CreateSeriesMappings(SeriesMappingInfo[] seriesMappingInfo)
    {
        var chartSeriesMappings = seriesMappingInfo.Select(m =>
        {
            // TODO: Create mapping. The binding would look something like this:
            var seriesMapping = new SeriesMapping();
            BindingOperations.SetBinding(seriesMapping, SeriesMapping.ItemsSourceProperty, new Binding(String.Format("DataSources[{0}]", m.DataSourceIndex)));
            return seriesMapping;
        });

        // TODO: Give these mappings to the chart control.
    }
}