【问题标题】:Dynamically create Silverlight RadChart SeriesMappings based on data returned from a service根据从服务返回的数据动态创建 Silverlight RadChart SeriesMappings
【发布时间】:2012-03-19 21:38:42
【问题描述】:

我有一项服务将返回 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;}
}

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

我认为我需要首先确定返回的不同 ItemTypes,然后根据它创建系列映射。

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

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

任何指针?

【问题讨论】:

    标签: silverlight telerik


    【解决方案1】:

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

    我的视图模型在其数据全部加载后触发了一个事件。视图处理了事件并将新的 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.
        }
    }
    

    【讨论】:

    • 谢谢。我有很多这部分编码,我可以在后面的代码中创建系列,但是当我从视图模型异步接收数据时,我看不到我能够创建系列的部分。您的 BindingOperations.SetBinding 行帮助很大,因为我试图弄清楚如何从后面的代码中绑定。
    • 您说,“当我从视图模型异步接收数据时,我看不到能够创建系列的部分。”你能帮我理解你问的是哪一部分吗?当您的视图模型接收数据时,我想它需要(1)将其转换为多个 SeriesMappings 可以绑定的东西,(2)组装足够的信息以便视图知道如何创建 SeriesMappings,以及(3)通知视图并制作它提供的所有这些信息。你问的是这三个中的一个还是多个?
    • 我认为我坚持的部分是“(3)通知视图并使所有这些信息可供它使用。”因为现在我可以从服务中获取数据,但我无法告诉视图已收到数据,它可以根据新数据创建系列映射和绑定。
    • 我在回答中附加了一个建议。
    • 感谢安德鲁的回答。我还没有让它工作。我采取了另一种方式,将服务调用和回调放在后面的代码中。这消除了我在收到数据时发生事情的问题,但我遇到了另一个问题,即当它们在回调中发生时,系列映射似乎不起作用。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-12-10
    • 1970-01-01
    • 1970-01-01
    • 2018-10-12
    • 2017-06-17
    • 2014-01-28
    • 1970-01-01
    相关资源
    最近更新 更多