The requested page is not available for the requested platform. You are viewing the content for Default platform.

How to: Use a DevExtreme Chart in a Mobile Application

  • 9 min to read

XAF allows you to integrate JavaScript widgets into a Mobile application using custom modules. In this topic, a custom List Editor based on a data-bound module is implemented.

ChartLineObject

Follow the steps below to display ListView records in a line chart using the DevExtreme Chart widget:

  1. Follow the How to: Add an XAF Mobile Custom Module topic's first 4 steps to create a new Mobile custom module, and name it chart. Use this name when you register the module in the MobileApplication.CustomizeApplicationConfig event.
  2. In this example, you can exclude the widget.css file from your module. To do this, open the module's module.json file and modify it as shown below:

    {
      "main": "widget.js",
      "files": [
        "template.html"
      ]
    }
    
  3. Modify the template.html file to create the chart widget:

    <script type="text/html" id="xet-dust-chart">
        <!-- ko withModel: { component: 'chart', viewModel:{ {bindingString|s} }} -->
        <div class="xet-chart chart" data-bind="style: $data.style, dxChart: $data, css: $data._classNames"></div>
        <!-- /ko -->
    </script>
    
  4. Create a dxChart control configuration in the widget.js file. Specify the dataSource property and handle the onPointClick event which helps to navigate to a Detail View. In control's ViewModel, transfer properties whose names start with the "control_" substring to the dxChart configuration object. This prefix is used on the server side to specify the chart settings. The following code demonstrates how to do this:

    var chartComponentInfo = { 
        componentViewModel: (viewModel) => { 
            var result = $.extend({}, viewModel); 
            Object.keys(result).forEach(function (key) { 
                var controlViewModelPrefix = "control_"; 
                if (key.startsWith(controlViewModelPrefix)) { 
                    var stringValue = result[key]; 
                    var readyToEvalValue = "(" + stringValue + ")"; 
                    var value = eval(readyToEvalValue); 
                    var newKey = key.replace(controlViewModelPrefix, ""); 
                    result[newKey] = value; 
                } 
            }); 
            result.dataSource = viewModel.listViewDataSource(); 
            result.dataSource.select(function (item) {
                return (result.processingFunction !== undefined) ? result.processingFunction(item) : item;
            });
            result.onPointClick = function (e) {
                var oid = e.target.tag._value;
                var application = AppPlayer.Application.get();
                DevExpress.ExpressApp.Mobile.navigateToView({
                    viewId: result.detailViewId, currentObjectEdit: oid,
                    $functions: application.functions
                });
            };   
            return result; 
        }, 
        defaults: { 
            style: { width: "100%" } 
        } 
    }; 
    DevExpress.ExpressApp.Mobile.updateComponentInfo("chart", chartComponentInfo);
    
  5. The dxChart widget is not supplied with XAF by default; you should add the viz module that exposes this widget using the MobileApplication.AdditionalDevExtremeModules property as shown below:

    using DevExpress.ExpressApp.Mobile;
    // ...
    public partial class MySolutionMobileApplication : MobileApplication {
        // ...
        public MySolutionMobileApplication() {
            // ...
            AdditionalDevExtremeModules.Add(DevExtremeModule.Viz);
        }
    }
    
  6. In MySolution.Module.Mobile | Editors folder, create the CustomComponent descendant that is used as the chart widget's server-side wrapper and name it Chart. Specify the widget's name in its Type property and provide properties that configure the widget's ViewModel:

    using DevExpress.ExpressApp.Mobile.MobileModel;
    // ...
    public class Chart : CustomComponent {
        public Chart() {
            Type = "chart";
        }
        public string DataSource { 
            get { return TryGetValue<string>("listViewDataSource"); } 
            set { this["listViewDataSource"] = value; } 
        }
        public string DetailViewId { 
            get { return TryGetValue<string>("detailViewId"); } 
            set { this["detailViewId"] = value; } 
        }
    }
    
  7. In the MySolution.Module | BusinessObjects folder, create a Business Object to be shown in the chart:

    using System.ComponentModel; 
    using DevExpress.Persistent.Base; 
    using DevExpress.Persistent.BaseImpl; 
    using DevExpress.Xpo; 
    // ...  
    [DefaultClassOptions]
    public class ChartLineObject : BaseObject { 
        public ChartLineObject(Session session) : base(session) { } 
        private string country;
        public string Country {
            get { return country; }
            set { SetPropertyValue("Country", ref country, value); }
        }
        private double population;
        public double Population
        {
            get { return population; }
            set { SetPropertyValue("Population", ref population, value); }
        }
    }
    
  8. In MySolution.Module.Mobile | Editors folder, create the custom MobileChartListEditor List Editor that creates and configures the Chart component. Implement the IViewModelAware interface to supply the ViewModelManager object used to bind data to the Chart control. Use the MobileListEditorsHelper.CreateDataSource extension method to create a data source based on the Collection Source received in IComplexListEditor.Setup and View Model received in the IViewModelAware.Setup extended method.

    using DevExpress.ExpressApp;
    using DevExpress.ExpressApp.Editors;
    using DevExpress.ExpressApp.Mobile;
    using DevExpress.ExpressApp.Mobile.Editors;
    using DevExpress.ExpressApp.Mobile.MobileModel;
    using DevExpress.ExpressApp.Model;
    using System.Collections;
    // ...
    [ListEditor(typeof(ChartLineObject), true)]
    public class MobileChartListEditor : ListEditor, IComplexListEditor, IViewModelAware {
        private object selectedObject;
        private IModelListView modelListView;
        private CollectionSourceBase collectionSource;
        private XafApplication application;
        private ViewModelManager viewModel;
    
        public override SelectionType SelectionType
        {
            get { return SelectionType.TemporarySelection; }
        }
    
        public override IList GetSelectedObjects() {
            return (selectedObject != null) ? new object[] { selectedObject } : new object[0];
        }
    
        public override void Refresh() {
        }
    
        public void Setup(ViewModelManager viewModel) {
            this.viewModel = viewModel;
        }
    
        public void Setup(CollectionSourceBase collectionSource, XafApplication application) {
            this.collectionSource = collectionSource;
            this.application = application;
        }
    
        protected override void AssignDataSourceToControl(object dataSource) {
            if (Control != null) {
                if (collectionSource != null) {
                    string url = MobileListEditorsHelper.CreateUrlProperty(Model, (MobileApplication)application);
                    DataSource modelDataSource = 
                        collectionSource.CreateDataSource(MobileListEditorsHelper.ListViewDataSourceKey, 
                        (MobileApplication)application, viewModel, Model, url);
                    MobileListEditorsHelper.AssignSort(modelDataSource, Model);
                    modelDataSource.Paginate = false;
                    modelDataSource.RefreshOnViewShown = "whenChanges";
                    ((Chart)Control).DataSource = viewModel.BindToDataSource(modelDataSource.Id);
                }
            }
        }
    
        protected override object CreateControlsCore() {
            Chart chart = new Chart();
            chart.DetailViewId = GetDetailViewId();
            return chart;
        }
    
        private string GetDetailViewId() {
            return modelListView.DetailView.Id + "$View"; 
        }
    
        public MobileChartListEditor(IModelListView model) : base(model) {
            modelListView = model;
            selectedObject = null;
        }
    }
    
  9. In the MySolution.Module.Mobile | Controllers folder, create the new CustomizeChartListEditorController that specifies the Chart control settings. In this case, you can specify different settings for one module according to information this module displays.

    using DevExpress.ExpressApp;
    // ...
    public class CustomizeChartListEditorController : ObjectViewController<ListView, ChartLineObject> {
        protected override void OnViewControlsCreated() {
            base.OnViewControlsCreated();
            MobileChartListEditor mobileMapsListEditor = View.Editor as MobileChartListEditor;
            if (mobileMapsListEditor != null) {
                Chart chart = mobileMapsListEditor.Control as Chart;
                CustomizeChartControl(chart);
            }
        }
        private void CustomizeChartControl(Chart chart) {
            chart["control_valueAxis"] = @"{ 
                        label:  { 
                            format: 'millions' 
                        } 
                    }";
            chart["control_argumentAxis"] = @"{ 
                        label:  { 
                            overlappingBehavior: 'stagger' 
                        } 
                    }";
            chart["control_series"] = String.Format(
                @"[{{ 
                    argumentField: '{0}', 
                    valueField: '{1}',
                    tagField: '{2}' 
                }}]", 
                nameof(ChartLineObject.Country), 
                nameof(ChartLineObject.Population), 
                nameof(ChartLineObject.Oid)
            );
            chart["control_legend"] = "{ visible: false }";
    
            chart["control_title"] = "'Population by Countries'";
    
            chart["control_processingFunction"] = @"(function(item) {
                item.Country = DevExpress.ExpressApp.Mobile.encodeHtml(item.Country);
                return item;
            })";
        }
    }
    

    In the code above, the encodeHtml method converts a property value to an HTML-encoded string to provide a secure input.

  10. Open the Updater.cs (Updater.vb) file, located in the MySolution.Module project's DatabaseUpdate folder. Add the following code to the ModuleUpdater.UpdateDatabaseAfterUpdateSchema method to supply initial data:

    using DevExpress.ExpressApp;
    // ...
    public class Updater : ModuleUpdater {
        public override void UpdateDatabaseAfterUpdateSchema() {
            base.UpdateDatabaseAfterUpdateSchema();
            if(ObjectSpace.FindObject<ChartLineObject>(null) == null) {
                ChartLineObject china = ObjectSpace.CreateObject<ChartLineObject>();
                china.Country = "China";
                china.Population = 1382500000;
    
                ChartLineObject india = ObjectSpace.CreateObject<ChartLineObject>();
                india.Country = "India";
                india.Population = 1314300000;
    
                ChartLineObject usa = ObjectSpace.CreateObject<ChartLineObject>();
                usa.Country = "USA";
                usa.Population = 324789000;
    
                ChartLineObject indonesia = ObjectSpace.CreateObject<ChartLineObject>();
                indonesia.Country = "Indonesia";
                indonesia.Population = 261600000;
    
                ChartLineObject brazil = ObjectSpace.CreateObject<ChartLineObject>();
                brazil.Country = "Brazil";
                brazil.Population = 207332000;
    
                ChartLineObject pakistan = ObjectSpace.CreateObject<ChartLineObject>();
                pakistan.Country = "Pakistan";
                pakistan.Population = 196865000;
    
                ChartLineObject nigeria = ObjectSpace.CreateObject<ChartLineObject>();
                nigeria.Country = "Nigeria";
                nigeria.Population = 188500000;
            }
            ObjectSpace.CommitChanges();
        }
    }
    
  11. Start the application and navigate to the ChartLineObject List View. The image in the introduction demonstrates the result.
See Also